예제 #1
0
static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag)
{
	int expon;

	clear_C1();

	if (st0_tag == TAG_Valid) {
		u_char tag;

		if (signnegative(st0_ptr)) {
			arith_invalid(0);	
			return;
		}

		
		expon = exponent(st0_ptr);

	      denormal_arg:

		setexponent16(st0_ptr, (expon & 1));

		
		tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS);
		addexponent(st0_ptr, expon >> 1);
		FPU_settag0(tag);
		return;
	}
예제 #2
0
파일: fpu_trig.c 프로젝트: kame/kame
static void
fsqrt_(void)
{
    if (!(FPU_st0_tag ^ TW_Valid)) {
        int     expon;

        if (FPU_st0_ptr->sign == SIGN_NEG) {
            arith_invalid(FPU_st0_ptr);	/* sqrt(negative) is
							 * invalid */
            return;
        }
#ifdef DENORM_OPERAND
        if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
            return;
#endif				/* DENORM_OPERAND */

        expon = FPU_st0_ptr->exp - EXP_BIAS;
        FPU_st0_ptr->exp = EXP_BIAS + (expon & 1);	/* make st(0) in  [1.0
								 * .. 4.0) */

        wm_sqrt(FPU_st0_ptr, control_word);	/* Do the computation */

        FPU_st0_ptr->exp += expon >> 1;
        FPU_st0_ptr->sign = SIGN_POS;
    } else if (FPU_st0_tag == TW_Zero)
예제 #3
0
파일: fpu_trig.c 프로젝트: 0-T-0/ps4-linux
static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag)
{
	int expon;

	clear_C1();

	if (st0_tag == TAG_Valid) {
		u_char tag;

		if (signnegative(st0_ptr)) {
			arith_invalid(0);	/* sqrt(negative) is invalid */
			return;
		}

		/* make st(0) in  [1.0 .. 4.0) */
		expon = exponent(st0_ptr);

	      denormal_arg:

		setexponent16(st0_ptr, (expon & 1));

		/* Do the computation, the sign of the result will be positive. */
		tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS);
		addexponent(st0_ptr, expon >> 1);
		FPU_settag0(tag);
		return;
	}
예제 #4
0
파일: poly_l2.c 프로젝트: BTHUNTERCN/cygwin
/*--- poly_l2p1() -----------------------------------------------------------+
 |   Base 2 logarithm by a polynomial approximation.                         |
 |   log2(x+1)                                                               |
 +---------------------------------------------------------------------------*/
int	poly_l2p1(u_char sign0, u_char sign1,
		  FPU_REG *st0_ptr, FPU_REG *st1_ptr, FPU_REG *dest)
{
  u_char       	tag;
  s32        	exponent;
  Xsig         	accumulator, yaccum;

  if ( exponent16(st0_ptr) < 0 )
    {
      log2_kernel(st0_ptr, sign0, &accumulator, &exponent);

      yaccum.lsw = 0;
      XSIG_LL(yaccum) = significand(st1_ptr);
      mul_Xsig_Xsig(&accumulator, &yaccum);

      exponent += round_Xsig(&accumulator);

      exponent += exponent16(st1_ptr) + 1;
      if ( exponent < EXP_WAY_UNDER ) exponent = EXP_WAY_UNDER;

      significand(dest) = XSIG_LL(accumulator);
      setexponent16(dest, exponent);

      tag = FPU_round(dest, 1, 0, FULL_PRECISION, sign0 ^ sign1);
      FPU_settagi(1, tag);

      if ( tag == TAG_Valid )
	set_precision_flag_up();   /* 80486 appears to always do this */
    }
  else
    {
      /* The magnitude of st0_ptr is far too large. */

      if ( sign0 != SIGN_POS )
	{
	  /* Trying to get the log of a negative number. */
#ifdef PECULIAR_486   /* Stupid 80486 doesn't worry about log(negative). */
	  changesign(st1_ptr);
#else
	  if ( arith_invalid(1) < 0 )
	    return 1;
#endif /* PECULIAR_486 */
	}

      /* 80486 appears to do this */
      if ( sign0 == SIGN_NEG )
	set_precision_flag_down();
      else
	set_precision_flag_up();
    }

  if ( exponent(dest) <= EXP_UNDER )
    EXCEPTION(EX_Underflow);

  return 0;

}
예제 #5
0
static void fptan(FPU_REG *st0_ptr, u_char st0_tag)
{
	FPU_REG *st_new_ptr;
	int q;
	u_char arg_sign = getsign(st0_ptr);

	
	if (st0_tag == TAG_Empty) {
		FPU_stack_underflow();	
		if (control_word & CW_Invalid) {
			st_new_ptr = &st(-1);
			push();
			FPU_stack_underflow();	
		}
		return;
	}

	if (STACK_OVERFLOW) {
		FPU_stack_overflow();
		return;
	}

	if (st0_tag == TAG_Valid) {
		if (exponent(st0_ptr) > -40) {
			if ((q = trig_arg(st0_ptr, 0)) == -1) {
				
				return;
			}

			poly_tan(st0_ptr);
			setsign(st0_ptr, (q & 1) ^ (arg_sign != 0));
			set_precision_flag_up();	
		} else {
			
			

		      denormal_arg:

			FPU_to_exp16(st0_ptr, st0_ptr);

			st0_tag =
			    FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
			FPU_settag0(st0_tag);
		}
		push();
		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
		return;
	}

	if (st0_tag == TAG_Zero) {
		push();
		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
		setcc(0);
		return;
	}

	if (st0_tag == TAG_Special)
		st0_tag = FPU_Special(st0_ptr);

	if (st0_tag == TW_Denormal) {
		if (denormal_operand() < 0)
			return;

		goto denormal_arg;
	}

	if (st0_tag == TW_Infinity) {
		
		if (arith_invalid(0) >= 0) {
			st_new_ptr = &st(-1);
			push();
			arith_invalid(0);
		}
		return;
	}

	single_arg_2_error(st0_ptr, st0_tag);
}
예제 #6
0
/*--- poly_tan() ------------------------------------------------------------+
 |                                                                           |
 +---------------------------------------------------------------------------*/
void	poly_tan(FPU_REG *st0_ptr)
{
  long int    		exponent;
  int                   invert;
  Xsig                  argSq, argSqSq, accumulatoro, accumulatore, accum,
                        argSignif, fix_up;
  unsigned long         adj;

  exponent = exponent(st0_ptr);

#ifdef PARANOID
  if ( signnegative(st0_ptr) )	/* Can't hack a number < 0.0 */
    { arith_invalid(0); return; }  /* Need a positive number */
#endif PARANOID

  /* Split the problem into two domains, smaller and larger than pi/4 */
  if ( (exponent == 0) || ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2)) )
    {
      /* The argument is greater than (approx) pi/4 */
      invert = 1;
      accum.lsw = 0;
      XSIG_LL(accum) = significand(st0_ptr);
 
      if ( exponent == 0 )
	{
	  /* The argument is >= 1.0 */
	  /* Put the binary point at the left. */
	  XSIG_LL(accum) <<= 1;
	}
      /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
      XSIG_LL(accum) = 0x921fb54442d18469LL - XSIG_LL(accum);
      /* This is a special case which arises due to rounding. */
      if ( XSIG_LL(accum) == 0xffffffffffffffffLL )
	{
	  FPU_settag0(TAG_Valid);
	  significand(st0_ptr) = 0x8a51e04daabda360LL;
	  setexponent16(st0_ptr, (0x41 + EXTENDED_Ebias) | SIGN_Negative);
	  return;
	}

      argSignif.lsw = accum.lsw;
      XSIG_LL(argSignif) = XSIG_LL(accum);
      exponent = -1 + norm_Xsig(&argSignif);
    }
  else
    {
      invert = 0;
      argSignif.lsw = 0;
      XSIG_LL(accum) = XSIG_LL(argSignif) = significand(st0_ptr);
 
      if ( exponent < -1 )
	{
	  /* shift the argument right by the required places */
	  if ( FPU_shrx(&XSIG_LL(accum), -1-exponent) >= 0x80000000U )
	    XSIG_LL(accum) ++;	/* round up */
	}
    }

  XSIG_LL(argSq) = XSIG_LL(accum); argSq.lsw = accum.lsw;
  mul_Xsig_Xsig(&argSq, &argSq);
  XSIG_LL(argSqSq) = XSIG_LL(argSq); argSqSq.lsw = argSq.lsw;
  mul_Xsig_Xsig(&argSqSq, &argSqSq);

  /* Compute the negative terms for the numerator polynomial */
  accumulatoro.msw = accumulatoro.midw = accumulatoro.lsw = 0;
  polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddnegterm, HiPOWERon-1);
  mul_Xsig_Xsig(&accumulatoro, &argSq);
  negate_Xsig(&accumulatoro);
  /* Add the positive terms */
  polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddplterm, HiPOWERop-1);

  
  /* Compute the positive terms for the denominator polynomial */
  accumulatore.msw = accumulatore.midw = accumulatore.lsw = 0;
  polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evenplterm, HiPOWERep-1);
  mul_Xsig_Xsig(&accumulatore, &argSq);
  negate_Xsig(&accumulatore);
  /* Add the negative terms */
  polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evennegterm, HiPOWERen-1);
  /* Multiply by arg^2 */
  mul64_Xsig(&accumulatore, &XSIG_LL(argSignif));
  mul64_Xsig(&accumulatore, &XSIG_LL(argSignif));
  /* de-normalize and divide by 2 */
  shr_Xsig(&accumulatore, -2*(1+exponent) + 1);
  negate_Xsig(&accumulatore);      /* This does 1 - accumulator */

  /* Now find the ratio. */
  if ( accumulatore.msw == 0 )
    {
      /* accumulatoro must contain 1.0 here, (actually, 0) but it
	 really doesn't matter what value we use because it will
	 have negligible effect in later calculations
	 */
      XSIG_LL(accum) = 0x8000000000000000LL;
      accum.lsw = 0;
    }
  else
    {
      div_Xsig(&accumulatoro, &accumulatore, &accum);
    }

  /* Multiply by 1/3 * arg^3 */
  mul64_Xsig(&accum, &XSIG_LL(argSignif));
  mul64_Xsig(&accum, &XSIG_LL(argSignif));
  mul64_Xsig(&accum, &XSIG_LL(argSignif));
  mul64_Xsig(&accum, &twothirds);
  shr_Xsig(&accum, -2*(exponent+1));

  /* tan(arg) = arg + accum */
  add_two_Xsig(&accum, &argSignif, &exponent);

  if ( invert )
    {
      /* We now have the value of tan(pi_2 - arg) where pi_2 is an
	 approximation for pi/2
	 */
      /* The next step is to fix the answer to compensate for the
	 error due to the approximation used for pi/2
	 */

      /* This is (approx) delta, the error in our approx for pi/2
	 (see above). It has an exponent of -65
	 */
      XSIG_LL(fix_up) = 0x898cc51701b839a2LL;
      fix_up.lsw = 0;

      if ( exponent == 0 )
	adj = 0xffffffff;   /* We want approx 1.0 here, but
			       this is close enough. */
      else if ( exponent > -30 )
	{
	  adj = accum.msw >> -(exponent+1);      /* tan */
	  adj = mul_32_32(adj, adj);             /* tan^2 */
	}
      else
static
int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
		     FPU_REG const *b, u_char tagb, u_char signb,
		     FPU_REG * dest, int deststnr, int control_w)
{
	if (((taga == TW_Denormal) || (tagb == TW_Denormal))
	    && (denormal_operand() < 0))
		return FPU_Exception;

	if (taga == TAG_Zero) {
		if (tagb == TAG_Zero) {
			
			u_char different_signs = signa ^ signb;

			FPU_copy_to_regi(a, TAG_Zero, deststnr);
			if (different_signs) {
				
				
				setsign(dest, ((control_w & CW_RC) != RC_DOWN)
					? SIGN_POS : SIGN_NEG);
			} else
				setsign(dest, signa);	
			return TAG_Zero;
		} else {
			reg_copy(b, dest);
			if ((tagb == TW_Denormal) && (b->sigh & 0x80000000)) {
				
				addexponent(dest, 1);
				tagb = TAG_Valid;
			} else if (tagb > TAG_Empty)
				tagb = TAG_Special;
			setsign(dest, signb);	
			FPU_settagi(deststnr, tagb);
			return tagb;
		}
	} else if (tagb == TAG_Zero) {
		reg_copy(a, dest);
		if ((taga == TW_Denormal) && (a->sigh & 0x80000000)) {
			
			addexponent(dest, 1);
			taga = TAG_Valid;
		} else if (taga > TAG_Empty)
			taga = TAG_Special;
		setsign(dest, signa);	
		FPU_settagi(deststnr, taga);
		return taga;
	} else if (taga == TW_Infinity) {
		if ((tagb != TW_Infinity) || (signa == signb)) {
			FPU_copy_to_regi(a, TAG_Special, deststnr);
			setsign(dest, signa);	
			return taga;
		}
		
		return arith_invalid(deststnr);
	} else if (tagb == TW_Infinity) {
		FPU_copy_to_regi(b, TAG_Special, deststnr);
		setsign(dest, signb);	
		return tagb;
	}
#ifdef PARANOID
	EXCEPTION(EX_INTERNAL | 0x101);
#endif

	return FPU_Exception;
}
예제 #8
0
static
int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
		     FPU_REG const *b, u_char tagb, u_char signb,
		     FPU_REG *dest, int deststnr, int control_w)
{
  if ( ((taga == TW_Denormal) || (tagb == TW_Denormal))
       && (denormal_operand() < 0) )
    return FPU_Exception;

  if (taga == TAG_Zero)
    {
      if (tagb == TAG_Zero)
	{
	  /* Both are zero, result will be zero. */
	  u_char different_signs = signa ^ signb;

	  FPU_copy_to_regi(a, TAG_Zero, deststnr);
	  if ( different_signs )
	    {
	      /* Signs are different. */
	      /* Sign of answer depends upon rounding mode. */
	      setsign(dest, ((control_w & CW_RC) != RC_DOWN)
		      ? SIGN_POS : SIGN_NEG);
	    }
	  else
	    setsign(dest, signa);  /* signa may differ from the sign of a. */
	  return TAG_Zero;
	}
      else
	{
	  reg_copy(b, dest);
	  if ( (tagb == TW_Denormal) && (b->sigh & 0x80000000) )
	    {
	      /* A pseudoDenormal, convert it. */
	      addexponent(dest, 1);
	      tagb = TAG_Valid;
	    }
	  else if ( tagb > TAG_Empty )
	    tagb = TAG_Special;
	  setsign(dest, signb);  /* signb may differ from the sign of b. */
	  FPU_settagi(deststnr, tagb);
	  return tagb;
	}
    }
  else if (tagb == TAG_Zero)
    {
      reg_copy(a, dest);
      if ( (taga == TW_Denormal) && (a->sigh & 0x80000000) )
	{
	  /* A pseudoDenormal */
	  addexponent(dest, 1);
	  taga = TAG_Valid;
	}
      else if ( taga > TAG_Empty )
	taga = TAG_Special;
      setsign(dest, signa);  /* signa may differ from the sign of a. */
      FPU_settagi(deststnr, taga);
      return taga;
    }
  else if (taga == TW_Infinity)
    {
      if ( (tagb != TW_Infinity) || (signa == signb) )
	{
	  FPU_copy_to_regi(a, TAG_Special, deststnr);
	  setsign(dest, signa);  /* signa may differ from the sign of a. */
	  return taga;
	}
      /* Infinity-Infinity is undefined. */
      return arith_invalid(deststnr);
    }
  else if (tagb == TW_Infinity)
    {
      FPU_copy_to_regi(b, TAG_Special, deststnr);
      setsign(dest, signb);  /* signb may differ from the sign of b. */
      return tagb;
    }

#ifdef PARANOID
  EXCEPTION(EX_INTERNAL|0x101);
#endif

  return FPU_Exception;
}
예제 #9
0
파일: fpu_trig.c 프로젝트: 0-T-0/ps4-linux
static void fptan(FPU_REG *st0_ptr, u_char st0_tag)
{
	FPU_REG *st_new_ptr;
	int q;
	u_char arg_sign = getsign(st0_ptr);

	/* Stack underflow has higher priority */
	if (st0_tag == TAG_Empty) {
		FPU_stack_underflow();	/* Puts a QNaN in st(0) */
		if (control_word & CW_Invalid) {
			st_new_ptr = &st(-1);
			push();
			FPU_stack_underflow();	/* Puts a QNaN in the new st(0) */
		}
		return;
	}

	if (STACK_OVERFLOW) {
		FPU_stack_overflow();
		return;
	}

	if (st0_tag == TAG_Valid) {
		if (exponent(st0_ptr) > -40) {
			if ((q = trig_arg(st0_ptr, 0)) == -1) {
				/* Operand is out of range */
				return;
			}

			poly_tan(st0_ptr);
			setsign(st0_ptr, (q & 1) ^ (arg_sign != 0));
			set_precision_flag_up();	/* We do not really know if up or down */
		} else {
			/* For a small arg, the result == the argument */
			/* Underflow may happen */

		      denormal_arg:

			FPU_to_exp16(st0_ptr, st0_ptr);

			st0_tag =
			    FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
			FPU_settag0(st0_tag);
		}
		push();
		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
		return;
	}

	if (st0_tag == TAG_Zero) {
		push();
		FPU_copy_to_reg0(&CONST_1, TAG_Valid);
		setcc(0);
		return;
	}

	if (st0_tag == TAG_Special)
		st0_tag = FPU_Special(st0_ptr);

	if (st0_tag == TW_Denormal) {
		if (denormal_operand() < 0)
			return;

		goto denormal_arg;
	}

	if (st0_tag == TW_Infinity) {
		/* The 80486 treats infinity as an invalid operand */
		if (arith_invalid(0) >= 0) {
			st_new_ptr = &st(-1);
			push();
			arith_invalid(0);
		}
		return;
	}

	single_arg_2_error(st0_ptr, st0_tag);
}
예제 #10
0
/*--- poly_atan() -----------------------------------------------------------+
 |                                                                           |
 +---------------------------------------------------------------------------*/
void
poly_atan(FPU_REG * arg)
{
	char    recursions = 0;
	short   exponent;
	FPU_REG odd_poly, even_poly, pos_poly, neg_poly;
	FPU_REG argSq;
	long long arg_signif, argSqSq;


#ifdef PARANOID
	if (arg->sign != 0) {	/* Can't hack a number < 0.0 */
		arith_invalid(arg);
		return;
	}			/* Need a positive number */
#endif				/* PARANOID */

	exponent = arg->exp - EXP_BIAS;

	if (arg->tag == TW_Zero) {
		/* Return 0.0 */
		reg_move(&CONST_Z, arg);
		return;
	}
	if (exponent >= -2) {
		/* argument is in the range  [0.25 .. 1.0] */
		if (exponent >= 0) {
#ifdef PARANOID
			if ((exponent == 0) &&
			    (arg->sigl == 0) && (arg->sigh == 0x80000000))
#endif				/* PARANOID */
			{
				reg_move(&CONST_PI4, arg);
				return;
			}
#ifdef PARANOID
			EXCEPTION(EX_INTERNAL | 0x104);	/* There must be a logic
							 * error */
#endif				/* PARANOID */
		}
		/* If the argument is greater than sqrt(2)-1 (=0.414213562...) */
		/* convert the argument by an identity for atan */
		if ((exponent >= -1) || (arg->sigh > 0xd413ccd0)) {
			FPU_REG numerator, denom;

			recursions++;

			arg_signif = *(long long *) &(arg->sigl);
			if (exponent < -1) {
				if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
					arg_signif++;	/* round up */
			}
			*(long long *) &(numerator.sigl) = -arg_signif;
			numerator.exp = EXP_BIAS - 1;
			normalize(&numerator);	/* 1 - arg */

			arg_signif = *(long long *) &(arg->sigl);
			if (shrx(&arg_signif, -exponent) >= (unsigned)0x80000000)
				arg_signif++;	/* round up */
			*(long long *) &(denom.sigl) = arg_signif;
			denom.sigh |= 0x80000000;	/* 1 + arg */

			arg->exp = numerator.exp;
			reg_u_div(&numerator, &denom, arg, FULL_PRECISION);

			exponent = arg->exp - EXP_BIAS;
		}
	}
	*(long long *) &arg_signif = *(long long *) &(arg->sigl);

#ifdef PARANOID
	/* This must always be true */
	if (exponent >= -1) {
		EXCEPTION(EX_INTERNAL | 0x120);	/* There must be a logic error */
	}
#endif				/* PARANOID */

	/* shift the argument right by the required places */
	if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
		arg_signif++;	/* round up */

	/* Now have arg_signif with binary point at the left .1xxxxxxxx */
	mul64(&arg_signif, &arg_signif, (long long *) (&argSq.sigl));
	mul64((long long *) (&argSq.sigl), (long long *) (&argSq.sigl), &argSqSq);

	/* will be a valid positive nr with expon = 0 */
	*(short *) &(pos_poly.sign) = 0;
	pos_poly.exp = EXP_BIAS;

	/* Do the basic fixed point polynomial evaluation */
	polynomial(&pos_poly.sigl, (unsigned *) &argSqSq,
	    (unsigned short (*)[4]) oddplterms, HIPOWERop - 1);
	mul64((long long *) (&argSq.sigl), (long long *) (&pos_poly.sigl),
	    (long long *) (&pos_poly.sigl));

	/* will be a valid positive nr with expon = 0 */
	*(short *) &(neg_poly.sign) = 0;
	neg_poly.exp = EXP_BIAS;

	/* Do the basic fixed point polynomial evaluation */
	polynomial(&neg_poly.sigl, (unsigned *) &argSqSq,
	    (unsigned short (*)[4]) oddnegterms, HIPOWERon - 1);

	/* Subtract the mantissas */
	*((long long *) (&pos_poly.sigl)) -= *((long long *) (&neg_poly.sigl));

	reg_move(&pos_poly, &odd_poly);
	poly_add_1(&odd_poly);

	/* The complete odd polynomial */
	reg_u_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION);

	/* will be a valid positive nr with expon = 0 */
	*(short *) &(even_poly.sign) = 0;

	mul64((long long *) (&argSq.sigl),
	    (long long *) (&denomterm), (long long *) (&even_poly.sigl));

	poly_add_1(&even_poly);

	reg_div(&odd_poly, &even_poly, arg, FULL_PRECISION);

	if (recursions)
		reg_sub(&CONST_PI4, arg, arg, FULL_PRECISION);
}
예제 #11
0
/*
  Divide one register by another and put the result into a third register.
  */
int FPU_div(int flags, int rm, int control_w)
{
	FPU_REG x, y;
	FPU_REG const *a, *b, *st0_ptr, *st_ptr;
	FPU_REG *dest;
	u_char taga, tagb, signa, signb, sign, saved_sign;
	int tag, deststnr;

	if (flags & DEST_RM)
		deststnr = rm;
	else
		deststnr = 0;

	if (flags & REV) {
		b = &st(0);
		st0_ptr = b;
		tagb = FPU_gettag0();
		if (flags & LOADED) {
			a = (FPU_REG *) rm;
			taga = flags & 0x0f;
		} else {
			a = &st(rm);
			st_ptr = a;
			taga = FPU_gettagi(rm);
		}
	} else {
		a = &st(0);
		st0_ptr = a;
		taga = FPU_gettag0();
		if (flags & LOADED) {
			b = (FPU_REG *) rm;
			tagb = flags & 0x0f;
		} else {
			b = &st(rm);
			st_ptr = b;
			tagb = FPU_gettagi(rm);
		}
	}

	signa = getsign(a);
	signb = getsign(b);

	sign = signa ^ signb;

	dest = &st(deststnr);
	saved_sign = getsign(dest);

	if (!(taga | tagb)) {
		/* Both regs Valid, this should be the most common case. */
		reg_copy(a, &x);
		reg_copy(b, &y);
		setpositive(&x);
		setpositive(&y);
		tag = FPU_u_div(&x, &y, dest, control_w, sign);

		if (tag < 0)
			return tag;

		FPU_settagi(deststnr, tag);
		return tag;
	}

	if (taga == TAG_Special)
		taga = FPU_Special(a);
	if (tagb == TAG_Special)
		tagb = FPU_Special(b);

	if (((taga == TAG_Valid) && (tagb == TW_Denormal))
	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
	    || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
		if (denormal_operand() < 0)
			return FPU_Exception;

		FPU_to_exp16(a, &x);
		FPU_to_exp16(b, &y);
		tag = FPU_u_div(&x, &y, dest, control_w, sign);
		if (tag < 0)
			return tag;

		FPU_settagi(deststnr, tag);
		return tag;
	} else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
		if (tagb != TAG_Zero) {
			/* Want to find Zero/Valid */
			if (tagb == TW_Denormal) {
				if (denormal_operand() < 0)
					return FPU_Exception;
			}

			/* The result is zero. */
			FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
			setsign(dest, sign);
			return TAG_Zero;
		}
		/* We have an exception condition, either 0/0 or Valid/Zero. */
		if (taga == TAG_Zero) {
			/* 0/0 */
			return arith_invalid(deststnr);
		}
		/* Valid/Zero */
		return FPU_divide_by_zero(deststnr, sign);
	}
	/* Must have infinities, NaNs, etc */
	else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
		if (flags & LOADED)
			return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0,
					    st0_ptr);

		if (flags & DEST_RM) {
			int tag;
			tag = FPU_gettag0();
			if (tag == TAG_Special)
				tag = FPU_Special(st0_ptr);
			return real_2op_NaN(st0_ptr, tag, rm,
					    (flags & REV) ? st0_ptr : &st(rm));
		} else {
			int tag;
			tag = FPU_gettagi(rm);
			if (tag == TAG_Special)
				tag = FPU_Special(&st(rm));
			return real_2op_NaN(&st(rm), tag, 0,
					    (flags & REV) ? st0_ptr : &st(rm));
		}
	} else if (taga == TW_Infinity) {
		if (tagb == TW_Infinity) {
			/* infinity/infinity */
			return arith_invalid(deststnr);
		} else {
			/* tagb must be Valid or Zero */
			if ((tagb == TW_Denormal) && (denormal_operand() < 0))
				return FPU_Exception;

			/* Infinity divided by Zero or Valid does
			   not raise and exception, but returns Infinity */
			FPU_copy_to_regi(a, TAG_Special, deststnr);
			setsign(dest, sign);
			return taga;
		}
	} else if (tagb == TW_Infinity) {
		if ((taga == TW_Denormal) && (denormal_operand() < 0))
			return FPU_Exception;

		/* The result is zero. */
		FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
		setsign(dest, sign);
		return TAG_Zero;
	}
#ifdef PARANOID
	else {
		EXCEPTION(EX_INTERNAL | 0x102);
		return FPU_Exception;
	}
#endif /* PARANOID */

	return 0;
}
예제 #12
0
/*--- poly_tan() ------------------------------------------------------------+
 |                                                                           |
 +---------------------------------------------------------------------------*/
void
poly_tan(FPU_REG * arg, FPU_REG * y_reg)
{
	char    invert = 0;
	short   exponent;
	FPU_REG odd_poly, even_poly, pos_poly, neg_poly;
	FPU_REG argSq;
	long long arg_signif, argSqSq;


	exponent = arg->exp - EXP_BIAS;

	if (arg->tag == TW_Zero) {
		/* Return 0.0 */
		reg_move(&CONST_Z, y_reg);
		return;
	}
	if (exponent >= -1) {
		/* argument is in the range  [0.5 .. 1.0] */
		if (exponent >= 0) {
#ifdef PARANOID
			if ((exponent == 0) &&
			    (arg->sigl == 0) && (arg->sigh == 0x80000000))
#endif				/* PARANOID */
			{
				arith_overflow(y_reg);
				return;
			}
#ifdef PARANOID
			EXCEPTION(EX_INTERNAL | 0x104);	/* There must be a logic
							 * error */
			return;
#endif				/* PARANOID */
		}
		/* The argument is in the range  [0.5 .. 1.0) */
		/* Convert the argument to a number in the range  (0.0 .. 0.5] */
		*((long long *) (&arg->sigl)) = -*((long long *) (&arg->sigl));
		normalize(arg);	/* Needed later */
		exponent = arg->exp - EXP_BIAS;
		invert = 1;
	}
#ifdef PARANOID
	if (arg->sign != 0) {	/* Can't hack a number < 0.0 */
		arith_invalid(y_reg);
		return;
	}			/* Need a positive number */
#endif				/* PARANOID */

	*(long long *) &arg_signif = *(long long *) &(arg->sigl);
	if (exponent < -1) {
		/* shift the argument right by the required places */
		if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
			arg_signif++;	/* round up */
	}
	mul64(&arg_signif, &arg_signif, (long long *) (&argSq.sigl));
	mul64((long long *) (&argSq.sigl), (long long *) (&argSq.sigl), &argSqSq);

	/* will be a valid positive nr with expon = 0 */
	*(short *) &(pos_poly.sign) = 0;
	pos_poly.exp = EXP_BIAS;

	/* Do the basic fixed point polynomial evaluation */
	polynomial((u_int *) &pos_poly.sigl, (unsigned *) &argSqSq, oddplterms, HIPOWERop - 1);

	/* will be a valid positive nr with expon = 0 */
	*(short *) &(neg_poly.sign) = 0;
	neg_poly.exp = EXP_BIAS;

	/* Do the basic fixed point polynomial evaluation */
	polynomial((u_int *) &neg_poly.sigl, (unsigned *) &argSqSq, oddnegterms, HIPOWERon - 1);
	mul64((long long *) (&argSq.sigl), (long long *) (&neg_poly.sigl),
	    (long long *) (&neg_poly.sigl));

	/* Subtract the mantissas */
	*((long long *) (&pos_poly.sigl)) -= *((long long *) (&neg_poly.sigl));

	/* Convert to 64 bit signed-compatible */
	pos_poly.exp -= 1;

	reg_move(&pos_poly, &odd_poly);
	normalize(&odd_poly);

	reg_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION);
	reg_u_add(&odd_poly, arg, &odd_poly, FULL_PRECISION);	/* This is just the odd
								 * polynomial */


	/* will be a valid positive nr with expon = 0 */
	*(short *) &(pos_poly.sign) = 0;
	pos_poly.exp = EXP_BIAS;

	/* Do the basic fixed point polynomial evaluation */
	polynomial((u_int *) &pos_poly.sigl, (unsigned *) &argSqSq, evenplterms, HIPOWERep - 1);
	mul64((long long *) (&argSq.sigl),
	    (long long *) (&pos_poly.sigl), (long long *) (&pos_poly.sigl));

	/* will be a valid positive nr with expon = 0 */
	*(short *) &(neg_poly.sign) = 0;
	neg_poly.exp = EXP_BIAS;

	/* Do the basic fixed point polynomial evaluation */
	polynomial((u_int *) &neg_poly.sigl, (unsigned *) &argSqSq, evennegterms, HIPOWERen - 1);

	/* Subtract the mantissas */
	*((long long *) (&neg_poly.sigl)) -= *((long long *) (&pos_poly.sigl));
	/* and multiply by argSq */

	/* Convert argSq to a valid reg number */
	*(short *) &(argSq.sign) = 0;
	argSq.exp = EXP_BIAS - 1;
	normalize(&argSq);

	/* Convert to 64 bit signed-compatible */
	neg_poly.exp -= 1;

	reg_move(&neg_poly, &even_poly);
	normalize(&even_poly);

	reg_mul(&even_poly, &argSq, &even_poly, FULL_PRECISION);
	reg_add(&even_poly, &argSq, &even_poly, FULL_PRECISION);
	reg_sub(&CONST_1, &even_poly, &even_poly, FULL_PRECISION);	/* This is just the even
									 * polynomial */

	/* Now ready to copy the results */
	if (invert) {
		reg_div(&even_poly, &odd_poly, y_reg, FULL_PRECISION);
	} else {
		reg_div(&odd_poly, &even_poly, y_reg, FULL_PRECISION);
	}

}
예제 #13
0
int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
{
	FPU_REG *a = &st(deststnr);
	FPU_REG *dest = a;
	u_char taga = FPU_gettagi(deststnr);
	u_char saved_sign = getsign(dest);
	u_char sign = (getsign(a) ^ getsign(b));
	int tag;

	if (!(taga | tagb)) {
		

		tag =
		    FPU_u_mul(a, b, dest, control_w, sign,
			      exponent(a) + exponent(b));
		if (tag < 0) {
			setsign(dest, saved_sign);
			return tag;
		}
		FPU_settagi(deststnr, tag);
		return tag;
	}

	if (taga == TAG_Special)
		taga = FPU_Special(a);
	if (tagb == TAG_Special)
		tagb = FPU_Special(b);

	if (((taga == TAG_Valid) && (tagb == TW_Denormal))
	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
	    || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
		FPU_REG x, y;
		if (denormal_operand() < 0)
			return FPU_Exception;

		FPU_to_exp16(a, &x);
		FPU_to_exp16(b, &y);
		tag = FPU_u_mul(&x, &y, dest, control_w, sign,
				exponent16(&x) + exponent16(&y));
		if (tag < 0) {
			setsign(dest, saved_sign);
			return tag;
		}
		FPU_settagi(deststnr, tag);
		return tag;
	} else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
		if (((tagb == TW_Denormal) || (taga == TW_Denormal))
		    && (denormal_operand() < 0))
			return FPU_Exception;

		FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
		setsign(dest, sign);
		return TAG_Zero;
	}
	
	else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
		return real_2op_NaN(b, tagb, deststnr, &st(0));
	} else if (((taga == TW_Infinity) && (tagb == TAG_Zero))
		   || ((tagb == TW_Infinity) && (taga == TAG_Zero))) {
		return arith_invalid(deststnr);	
	} else if (((taga == TW_Denormal) || (tagb == TW_Denormal))
		   && (denormal_operand() < 0)) {
		return FPU_Exception;
	} else if (taga == TW_Infinity) {
		FPU_copy_to_regi(a, TAG_Special, deststnr);
		setsign(dest, sign);
		return TAG_Special;
	} else if (tagb == TW_Infinity) {
		FPU_copy_to_regi(b, TAG_Special, deststnr);
		setsign(dest, sign);
		return TAG_Special;
	}
#ifdef PARANOID
	else {
		EXCEPTION(EX_INTERNAL | 0x102);
		return FPU_Exception;
	}
#endif 

	return 0;
}
예제 #14
0
void
reg_add(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w)
{
	int     diff;

	if (!(a->tag | b->tag)) {
		/* Both registers are valid */
		if (!(a->sign ^ b->sign)) {
			/* signs are the same */
			reg_u_add(a, b, dest, control_w);
			dest->sign = a->sign;
			return;
		}
		/* The signs are different, so do a subtraction */
		diff = a->exp - b->exp;
		if (!diff) {
			diff = a->sigh - b->sigh;	/* Works only if ms bits
							 * are identical */
			if (!diff) {
				diff = a->sigl > b->sigl;
				if (!diff)
					diff = -(a->sigl < b->sigl);
			}
		}
		if (diff > 0) {
			reg_u_sub(a, b, dest, control_w);
			dest->sign = a->sign;
		} else
			if (diff == 0) {
				reg_move(&CONST_Z, dest);
				/* sign depends upon rounding mode */
				dest->sign = ((control_w & CW_RC) != RC_DOWN)
				    ? SIGN_POS : SIGN_NEG;
			} else {
				reg_u_sub(b, a, dest, control_w);
				dest->sign = b->sign;
			}
		return;
	} else {
		if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) {
			real_2op_NaN(a, b, dest);
			return;
		} else
			if (a->tag == TW_Zero) {
				if (b->tag == TW_Zero) {
					char    different_signs = a->sign ^ b->sign;
					/* Both are zero, result will be zero. */
					reg_move(a, dest);
					if (different_signs) {
						/* Signs are different. */
						/* Sign of answer depends upon
						 * rounding mode. */
						dest->sign = ((control_w & CW_RC) != RC_DOWN)
						    ? SIGN_POS : SIGN_NEG;
					}
				} else {
#ifdef DENORM_OPERAND
					if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
					    denormal_operand())
						return;
#endif				/* DENORM_OPERAND */
					reg_move(b, dest);
				}
				return;
			} else
				if (b->tag == TW_Zero) {
#ifdef DENORM_OPERAND
					if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
					    denormal_operand())
						return;
#endif				/* DENORM_OPERAND */
					reg_move(a, dest);
					return;
				} else
					if (a->tag == TW_Infinity) {
						if (b->tag != TW_Infinity) {
#ifdef DENORM_OPERAND
							if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
							    denormal_operand())
								return;
#endif				/* DENORM_OPERAND */
							reg_move(a, dest);
							return;
						}
						if (a->sign == b->sign) {
							/* They are both + or
							 * - infinity */
							reg_move(a, dest);
							return;
						}
						arith_invalid(dest);	/* Infinity-Infinity is
									 * undefined. */
						return;
					} else
						if (b->tag == TW_Infinity) {
#ifdef DENORM_OPERAND
							if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
							    denormal_operand())
								return;
#endif				/* DENORM_OPERAND */
							reg_move(b, dest);
							return;
						}
	}
#ifdef PARANOID
	EXCEPTION(EX_INTERNAL | 0x101);
#endif
}
예제 #15
0
/* Subtract b from a.  (a-b) -> dest */
void
reg_sub(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w)
{
	int     diff;

	if (!(a->tag | b->tag)) {
		/* Both registers are valid */
		diff = a->exp - b->exp;
		if (!diff) {
			diff = a->sigh - b->sigh;	/* Works only if ms bits
							 * are identical */
			if (!diff) {
				diff = a->sigl > b->sigl;
				if (!diff)
					diff = -(a->sigl < b->sigl);
			}
		}
		switch (a->sign * 2 + b->sign) {
		case 0:	/* P - P */
		case 3:	/* N - N */
			if (diff > 0) {
				reg_u_sub(a, b, dest, control_w);
				dest->sign = a->sign;
			} else
				if (diff == 0) {
#ifdef DENORM_OPERAND
					if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
					    denormal_operand())
						return;
#endif				/* DENORM_OPERAND */
					reg_move(&CONST_Z, dest);
					/* sign depends upon rounding mode */
					dest->sign = ((control_w & CW_RC) != RC_DOWN)
					    ? SIGN_POS : SIGN_NEG;
				} else {
					reg_u_sub(b, a, dest, control_w);
					dest->sign = a->sign ^ SIGN_POS ^ SIGN_NEG;
				}
			return;
		case 1:	/* P - N */
			reg_u_add(a, b, dest, control_w);
			dest->sign = SIGN_POS;
			return;
		case 2:	/* N - P */
			reg_u_add(a, b, dest, control_w);
			dest->sign = SIGN_NEG;
			return;
		}
	} else {
		if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) {
			real_2op_NaN(a, b, dest);
			return;
		} else
			if (b->tag == TW_Zero) {
				if (a->tag == TW_Zero) {
					char    same_signs = !(a->sign ^ b->sign);
					/* Both are zero, result will be zero. */
					reg_move(a, dest);	/* Answer for different
								 * signs. */
					if (same_signs) {
						/* Sign depends upon rounding
						 * mode */
						dest->sign = ((control_w & CW_RC) != RC_DOWN)
						    ? SIGN_POS : SIGN_NEG;
					}
				} else {
#ifdef DENORM_OPERAND
					if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
					    denormal_operand())
						return;
#endif				/* DENORM_OPERAND */
					reg_move(a, dest);
				}
				return;
			} else
				if (a->tag == TW_Zero) {
#ifdef DENORM_OPERAND
					if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
					    denormal_operand())
						return;
#endif				/* DENORM_OPERAND */
					reg_move(b, dest);
					dest->sign ^= SIGN_POS ^ SIGN_NEG;
					return;
				} else
					if (a->tag == TW_Infinity) {
						if (b->tag != TW_Infinity) {
#ifdef DENORM_OPERAND
							if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
							    denormal_operand())
								return;
#endif				/* DENORM_OPERAND */
							reg_move(a, dest);
							return;
						}
						/* Both args are Infinity */
						if (a->sign == b->sign) {
							arith_invalid(dest);	/* Infinity-Infinity is
										 * undefined. */
							return;
						}
						reg_move(a, dest);
						return;
					} else
						if (b->tag == TW_Infinity) {
#ifdef DENORM_OPERAND
							if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
							    denormal_operand())
								return;
#endif				/* DENORM_OPERAND */
							reg_move(b, dest);
							dest->sign ^= SIGN_POS ^ SIGN_NEG;
							return;
						}
	}
#ifdef PARANOID
	EXCEPTION(EX_INTERNAL | 0x110);
#endif
}
예제 #16
0
int FPU_div(int flags, int rm, int control_w)
{
	FPU_REG x, y;
	FPU_REG const *a, *b, *st0_ptr, *st_ptr;
	FPU_REG *dest;
	u_char taga, tagb, signa, signb, sign, saved_sign;
	int tag, deststnr;

	if (flags & DEST_RM)
		deststnr = rm;
	else
		deststnr = 0;

	if (flags & REV) {
		b = &st(0);
		st0_ptr = b;
		tagb = FPU_gettag0();
		if (flags & LOADED) {
			a = (FPU_REG *) rm;
			taga = flags & 0x0f;
		} else {
			a = &st(rm);
			st_ptr = a;
			taga = FPU_gettagi(rm);
		}
	} else {
		a = &st(0);
		st0_ptr = a;
		taga = FPU_gettag0();
		if (flags & LOADED) {
			b = (FPU_REG *) rm;
			tagb = flags & 0x0f;
		} else {
			b = &st(rm);
			st_ptr = b;
			tagb = FPU_gettagi(rm);
		}
	}

	signa = getsign(a);
	signb = getsign(b);

	sign = signa ^ signb;

	dest = &st(deststnr);
	saved_sign = getsign(dest);

	if (!(taga | tagb)) {
		
		reg_copy(a, &x);
		reg_copy(b, &y);
		setpositive(&x);
		setpositive(&y);
		tag = FPU_u_div(&x, &y, dest, control_w, sign);

		if (tag < 0)
			return tag;

		FPU_settagi(deststnr, tag);
		return tag;
	}

	if (taga == TAG_Special)
		taga = FPU_Special(a);
	if (tagb == TAG_Special)
		tagb = FPU_Special(b);

	if (((taga == TAG_Valid) && (tagb == TW_Denormal))
	    || ((taga == TW_Denormal) && (tagb == TAG_Valid))
	    || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
		if (denormal_operand() < 0)
			return FPU_Exception;

		FPU_to_exp16(a, &x);
		FPU_to_exp16(b, &y);
		tag = FPU_u_div(&x, &y, dest, control_w, sign);
		if (tag < 0)
			return tag;

		FPU_settagi(deststnr, tag);
		return tag;
	} else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
		if (tagb != TAG_Zero) {
			
			if (tagb == TW_Denormal) {
				if (denormal_operand() < 0)
					return FPU_Exception;
			}

			
			FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
			setsign(dest, sign);
			return TAG_Zero;
		}
		
		if (taga == TAG_Zero) {
			
			return arith_invalid(deststnr);
		}
		
		return FPU_divide_by_zero(deststnr, sign);
	}
	
	else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
		if (flags & LOADED)
			return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0,
					    st0_ptr);

		if (flags & DEST_RM) {
			int tag;
			tag = FPU_gettag0();
			if (tag == TAG_Special)
				tag = FPU_Special(st0_ptr);
			return real_2op_NaN(st0_ptr, tag, rm,
					    (flags & REV) ? st0_ptr : &st(rm));
		} else {
			int tag;
			tag = FPU_gettagi(rm);
			if (tag == TAG_Special)
				tag = FPU_Special(&st(rm));
			return real_2op_NaN(&st(rm), tag, 0,
					    (flags & REV) ? st0_ptr : &st(rm));
		}
	} else if (taga == TW_Infinity) {
		if (tagb == TW_Infinity) {
			
			return arith_invalid(deststnr);
		} else {
			
			if ((tagb == TW_Denormal) && (denormal_operand() < 0))
				return FPU_Exception;

			
			FPU_copy_to_regi(a, TAG_Special, deststnr);
			setsign(dest, sign);
			return taga;
		}
	} else if (tagb == TW_Infinity) {
		if ((taga == TW_Denormal) && (denormal_operand() < 0))
			return FPU_Exception;

		
		FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
		setsign(dest, sign);
		return TAG_Zero;
	}
#ifdef PARANOID
	else {
		EXCEPTION(EX_INTERNAL | 0x102);
		return FPU_Exception;
	}
#endif 

	return 0;
}