Exemple #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);	/* 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;
	}
Exemple #2
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;
	}
Exemple #3
0
static void f2xm1(FPU_REG *st0_ptr, u_char tag)
{
  FPU_REG a;

  clear_C1();

  if ( tag == TAG_Valid )
    {
      /* For an 80486 FPU, the result is undefined if the arg is >= 1.0 */
      if ( exponent(st0_ptr) < 0 )
	{
	denormal_arg:

	  FPU_to_exp16(st0_ptr, &a);

	  /* poly_2xm1(x) requires 0 < st(0) < 1. */
	  poly_2xm1(getsign(st0_ptr), &a, st0_ptr);
	}
      set_precision_flag_up();   /* 80486 appears to always do this */
      return;
    }

  if ( tag == TAG_Zero )
    return;

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

  switch ( tag )
    {
    case TW_Denormal:
      if ( denormal_operand() < 0 )
	return;
      goto denormal_arg;
    case TW_Infinity:
      if ( signnegative(st0_ptr) )
	{
	  /* -infinity gives -1 (p16-10) */
	  FPU_copy_to_reg0(&CONST_1, TAG_Valid);
	  setnegative(st0_ptr);
	}
      return;
    default:
      single_arg_error(st0_ptr, tag);
    }
}
Exemple #4
0
static void f2xm1(FPU_REG *st0_ptr, u_char tag)
{
	FPU_REG a;

	clear_C1();

	if (tag == TAG_Valid) {
		
		if (exponent(st0_ptr) < 0) {
		      denormal_arg:

			FPU_to_exp16(st0_ptr, &a);

			
			poly_2xm1(getsign(st0_ptr), &a, st0_ptr);
		}
		set_precision_flag_up();	
		return;
	}

	if (tag == TAG_Zero)
		return;

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

	switch (tag) {
	case TW_Denormal:
		if (denormal_operand() < 0)
			return;
		goto denormal_arg;
	case TW_Infinity:
		if (signnegative(st0_ptr)) {
			
			FPU_copy_to_reg0(&CONST_1, TAG_Valid);
			setnegative(st0_ptr);
		}
		return;
	default:
		single_arg_error(st0_ptr, tag);
	}
}
Exemple #5
0
static int trig_arg(FPU_REG *st0_ptr, int even)
{
	FPU_REG tmp;
	u_char tmptag;
	unsigned long long q;
	int old_cw = control_word, saved_status = partial_status;
	int tag, st0_tag = TAG_Valid;

	if (exponent(st0_ptr) >= 63) {
		partial_status |= SW_C2;	
		return -1;
	}

	control_word &= ~CW_RC;
	control_word |= RC_CHOP;

	setpositive(st0_ptr);
	tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
			SIGN_POS);

	FPU_round_to_int(&tmp, tag);	
	q = significand(&tmp);
	if (q) {
		rem_kernel(significand(st0_ptr),
			   &significand(&tmp),
			   significand(&CONST_PI2),
			   q, exponent(st0_ptr) - exponent(&CONST_PI2));
		setexponent16(&tmp, exponent(&CONST_PI2));
		st0_tag = FPU_normalize(&tmp);
		FPU_copy_to_reg0(&tmp, st0_tag);
	}

	if ((even && !(q & 1)) || (!even && (q & 1))) {
		st0_tag =
		    FPU_sub(REV | LOADED | TAG_Valid, (int)&CONST_PI2,
			    FULL_PRECISION);

#ifdef BETTER_THAN_486
		
		if ((exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)
		    || (q > 1)) {
			

			significand(&tmp) = q + 1;
			setexponent16(&tmp, 63);
			FPU_normalize(&tmp);
			tmptag =
			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
				      FULL_PRECISION, SIGN_POS,
				      exponent(&CONST_PI2extra) +
				      exponent(&tmp));
			setsign(&tmp, getsign(&CONST_PI2extra));
			st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
			if (signnegative(st0_ptr)) {
				
				setpositive(st0_ptr);
				q++;
			}
		}
#endif 
	}
#ifdef BETTER_THAN_486
	else {
		
		if (((q > 0)
		     && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
		    || (q > 1)) {
			

			significand(&tmp) = q;
			setexponent16(&tmp, 63);
			FPU_normalize(&tmp);	
			tmptag =
			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
				      FULL_PRECISION, SIGN_POS,
				      exponent(&CONST_PI2extra) +
				      exponent(&tmp));
			setsign(&tmp, getsign(&CONST_PI2extra));
			st0_tag = FPU_sub(LOADED | (tmptag & 0x0f), (int)&tmp,
					  FULL_PRECISION);
			if ((exponent(st0_ptr) == exponent(&CONST_PI2)) &&
			    ((st0_ptr->sigh > CONST_PI2.sigh)
			     || ((st0_ptr->sigh == CONST_PI2.sigh)
				 && (st0_ptr->sigl > CONST_PI2.sigl)))) {
				
				st0_tag =
				    FPU_sub(REV | LOADED | TAG_Valid,
					    (int)&CONST_PI2, FULL_PRECISION);
				q++;
			}
		}
	}
#endif 

	FPU_settag0(st0_tag);
	control_word = old_cw;
	partial_status = saved_status & ~SW_C2;	

	return (q & 3) | even;
}
/*--- 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
Exemple #7
0
/* Limited measurements show no results worse than 64 bit precision
   except for the results for arguments close to 2^63, where the
   precision of the result sometimes degrades to about 63.9 bits */
static int trig_arg(FPU_REG *st0_ptr, int even)
{
	FPU_REG tmp;
	u_char tmptag;
	unsigned long long q;
	int old_cw = control_word, saved_status = partial_status;
	int tag, st0_tag = TAG_Valid;

	if (exponent(st0_ptr) >= 63) {
		partial_status |= SW_C2;	/* Reduction incomplete. */
		return -1;
	}

	control_word &= ~CW_RC;
	control_word |= RC_CHOP;

	setpositive(st0_ptr);
	tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
			SIGN_POS);

	FPU_round_to_int(&tmp, tag);	/* Fortunately, this can't overflow
					   to 2^64 */
	q = significand(&tmp);
	if (q) {
		rem_kernel(significand(st0_ptr),
			   &significand(&tmp),
			   significand(&CONST_PI2),
			   q, exponent(st0_ptr) - exponent(&CONST_PI2));
		setexponent16(&tmp, exponent(&CONST_PI2));
		st0_tag = FPU_normalize(&tmp);
		FPU_copy_to_reg0(&tmp, st0_tag);
	}

	if ((even && !(q & 1)) || (!even && (q & 1))) {
		st0_tag =
		    FPU_sub(REV | LOADED | TAG_Valid, (int)&CONST_PI2,
			    FULL_PRECISION);

#ifdef BETTER_THAN_486
		/* So far, the results are exact but based upon a 64 bit
		   precision approximation to pi/2. The technique used
		   now is equivalent to using an approximation to pi/2 which
		   is accurate to about 128 bits. */
		if ((exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)
		    || (q > 1)) {
			/* This code gives the effect of having pi/2 to better than
			   128 bits precision. */

			significand(&tmp) = q + 1;
			setexponent16(&tmp, 63);
			FPU_normalize(&tmp);
			tmptag =
			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
				      FULL_PRECISION, SIGN_POS,
				      exponent(&CONST_PI2extra) +
				      exponent(&tmp));
			setsign(&tmp, getsign(&CONST_PI2extra));
			st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
			if (signnegative(st0_ptr)) {
				/* CONST_PI2extra is negative, so the result of the addition
				   can be negative. This means that the argument is actually
				   in a different quadrant. The correction is always < pi/2,
				   so it can't overflow into yet another quadrant. */
				setpositive(st0_ptr);
				q++;
			}
		}
#endif /* BETTER_THAN_486 */
	}
#ifdef BETTER_THAN_486
	else {
		/* So far, the results are exact but based upon a 64 bit
		   precision approximation to pi/2. The technique used
		   now is equivalent to using an approximation to pi/2 which
		   is accurate to about 128 bits. */
		if (((q > 0)
		     && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
		    || (q > 1)) {
			/* This code gives the effect of having p/2 to better than
			   128 bits precision. */

			significand(&tmp) = q;
			setexponent16(&tmp, 63);
			FPU_normalize(&tmp);	/* This must return TAG_Valid */
			tmptag =
			    FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
				      FULL_PRECISION, SIGN_POS,
				      exponent(&CONST_PI2extra) +
				      exponent(&tmp));
			setsign(&tmp, getsign(&CONST_PI2extra));
			st0_tag = FPU_sub(LOADED | (tmptag & 0x0f), (int)&tmp,
					  FULL_PRECISION);
			if ((exponent(st0_ptr) == exponent(&CONST_PI2)) &&
			    ((st0_ptr->sigh > CONST_PI2.sigh)
			     || ((st0_ptr->sigh == CONST_PI2.sigh)
				 && (st0_ptr->sigl > CONST_PI2.sigl)))) {
				/* CONST_PI2extra is negative, so the result of the
				   subtraction can be larger than pi/2. This means
				   that the argument is actually in a different quadrant.
				   The correction is always < pi/2, so it can't overflow
				   into yet another quadrant. */
				st0_tag =
				    FPU_sub(REV | LOADED | TAG_Valid,
					    (int)&CONST_PI2, FULL_PRECISION);
				q++;
			}
		}
	}
#endif /* BETTER_THAN_486 */

	FPU_settag0(st0_tag);
	control_word = old_cw;
	partial_status = saved_status & ~SW_C2;	/* Reduction complete. */

	return (q & 3) | even;
}