Exemplo n.º 1
0
/*--- poly_2xm1() -----------------------------------------------------------+
 | Requires st(0) which is TAG_Valid and < 1.                                |
 +---------------------------------------------------------------------------*/
int	poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result)
{
  s32       exponent, shift;
  u64       Xll;
  Xsig      accumulator, Denom, argSignif;
  u_char    tag;

  exponent = exponent16(arg);

#ifdef PARANOID
  if ( exponent >= 0 )    	/* Don't want a |number| >= 1.0 */
    {
      /* Number negative, too large, or not Valid. */
      EXCEPTION(EX_INTERNAL|0x127);
      return 1;
    }
#endif /* PARANOID */

  argSignif.lsw = 0;
  XSIG_LL(argSignif) = Xll = significand(arg);

  if ( exponent == -1 )
    {
      shift = (argSignif.msw & 0x40000000) ? 3 : 2;
      /* subtract 0.5 or 0.75 */
      exponent -= 2;
      XSIG_LL(argSignif) <<= 2;
      Xll <<= 2;
    }
  else if ( exponent == -2 )
    {
      shift = 1;
      /* subtract 0.25 */
      exponent--;
      XSIG_LL(argSignif) <<= 1;
      Xll <<= 1;
    }
  else
    shift = 0;

  if ( exponent < -2 )
    {
      /* Shift the argument right by the required places. */
      if ( FPU_shrx(&Xll, -2-exponent) >= 0x80000000U )
	Xll++;	/* round up */
    }

  accumulator.lsw = accumulator.midw = accumulator.msw = 0;
  polynomial_Xsig(&accumulator, &Xll, lterms, HIPOWER-1);
  mul_Xsig_Xsig(&accumulator, &argSignif);
  shr_Xsig(&accumulator, 3);

  mul_Xsig_Xsig(&argSignif, &hiterm);   /* The leading term */
  add_two_Xsig(&accumulator, &argSignif, &exponent);

  if ( shift )
    {
      /* The argument is large, use the identity:
	 f(x+a) = f(a) * (f(x) + 1) - 1;
	 */
      shr_Xsig(&accumulator, - exponent);
      accumulator.msw |= 0x80000000;      /* add 1.0 */
      mul_Xsig_Xsig(&accumulator, shiftterm[shift]);
      accumulator.msw &= 0x3fffffff;      /* subtract 1.0 */
      exponent = 1;
    }

  if ( sign != SIGN_POS )
    {
      /* The argument is negative, use the identity:
	     f(-x) = -f(x) / (1 + f(x))
	 */
      Denom.lsw = accumulator.lsw;
      XSIG_LL(Denom) = XSIG_LL(accumulator);
      if ( exponent < 0 )
	shr_Xsig(&Denom, - exponent);
      else if ( exponent > 0 )
	{
	  /* exponent must be 1 here */
	  XSIG_LL(Denom) <<= 1;
	  if ( Denom.lsw & 0x80000000 )
	    XSIG_LL(Denom) |= 1;
	  (Denom.lsw) <<= 1;
	}
      Denom.msw |= 0x80000000;      /* add 1.0 */
      div_Xsig(&accumulator, &Denom, &accumulator);
    }

  /* Convert to 64 bit signed-compatible */
  exponent += round_Xsig(&accumulator);

  result = &st(0);
  significand(result) = XSIG_LL(accumulator);
  setexponent16(result, exponent);

  tag = FPU_round(result, 1, 0, FULL_PRECISION, sign);

  setsign(result, sign);
  FPU_settag0(tag);

  return 0;

}
Exemplo n.º 2
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
Exemplo n.º 3
0
int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result)
{
	long int exponent, shift;
	unsigned long long Xll;
	Xsig accumulator, Denom, argSignif;
	u_char tag;

	exponent = exponent16(arg);

#ifdef PARANOID
	if (exponent >= 0) {	/*                              */
		/*                                           */
		EXCEPTION(EX_INTERNAL | 0x127);
		return 1;
	}
#endif /*          */

	argSignif.lsw = 0;
	XSIG_LL(argSignif) = Xll = significand(arg);

	if (exponent == -1) {
		shift = (argSignif.msw & 0x40000000) ? 3 : 2;
		/*                      */
		exponent -= 2;
		XSIG_LL(argSignif) <<= 2;
		Xll <<= 2;
	} else if (exponent == -2) {
		shift = 1;
		/*               */
		exponent--;
		XSIG_LL(argSignif) <<= 1;
		Xll <<= 1;
	} else
		shift = 0;

	if (exponent < -2) {
		/*                                                  */
		if (FPU_shrx(&Xll, -2 - exponent) >= 0x80000000U)
			Xll++;	/*          */
	}

	accumulator.lsw = accumulator.midw = accumulator.msw = 0;
	polynomial_Xsig(&accumulator, &Xll, lterms, HIPOWER - 1);
	mul_Xsig_Xsig(&accumulator, &argSignif);
	shr_Xsig(&accumulator, 3);

	mul_Xsig_Xsig(&argSignif, &hiterm);	/*                  */
	add_two_Xsig(&accumulator, &argSignif, &exponent);

	if (shift) {
		/*                                         
                                    
   */
		shr_Xsig(&accumulator, -exponent);
		accumulator.msw |= 0x80000000;	/*         */
		mul_Xsig_Xsig(&accumulator, shiftterm[shift]);
		accumulator.msw &= 0x3fffffff;	/*              */
		exponent = 1;
	}

	if (sign != SIGN_POS) {
		/*                                            
                               
   */
		Denom.lsw = accumulator.lsw;
		XSIG_LL(Denom) = XSIG_LL(accumulator);
		if (exponent < 0)
			shr_Xsig(&Denom, -exponent);
		else if (exponent > 0) {
			/*                         */
			XSIG_LL(Denom) <<= 1;
			if (Denom.lsw & 0x80000000)
				XSIG_LL(Denom) |= 1;
			(Denom.lsw) <<= 1;
		}
		Denom.msw |= 0x80000000;	/*         */
		div_Xsig(&accumulator, &Denom, &accumulator);
	}

	/*                                     */
	exponent += round_Xsig(&accumulator);

	result = &st(0);
	significand(result) = XSIG_LL(accumulator);
	setexponent16(result, exponent);

	tag = FPU_round(result, 1, 0, FULL_PRECISION, sign);

	setsign(result, sign);
	FPU_settag0(tag);

	return 0;

}