Ejemplo n.º 1
0
/* Convert a s32 to register */
static void convert_l2reg(s32 const *arg, int deststnr)
{
  int tag;
  s32 num = *arg;
  u_char sign;
  FPU_REG *dest = &st(deststnr);

  if (num == 0)
    {
      FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
      return;
    }

  if (num > 0)
    { sign = SIGN_POS; }
  else
    { num = -num; sign = SIGN_NEG; }

  dest->sigh = num;
  dest->sigl = 0;
  setexponent16(dest, 31);
  tag = FPU_normalize_nuo(dest,
                         EXTENDED_Ebias);  /* No underflow or overflow
                                              is possible */
  FPU_settagi(deststnr, tag);
  setsign(dest, sign);
  return;
}
Ejemplo n.º 2
0
int FPU_to_exp16(FPU_REG const *a, FPU_REG *x)
{
	int sign = getsign(a);

	*(long long *)&(x->sigl) = *(const long long *)&(a->sigl);

	/* Set up the exponent as a 16 bit quantity. */
	setexponent16(x, exponent(a));

	if (exponent16(x) == EXP_UNDER) {
		/* The number is a de-normal or pseudodenormal. */
		/* We only deal with the significand and exponent. */

		if (x->sigh & 0x80000000) {
			/* Is a pseudodenormal. */
			/* This is non-80486 behaviour because the number
			   loses its 'denormal' identity. */
			addexponent(x, 1);
		} else {
			/* Is a denormal. */
			addexponent(x, 1);
			FPU_normalize_nuo(x);
		}
	}

	if (!(x->sigh & 0x80000000)) {
		EXCEPTION(EX_INTERNAL | 0x180);
	}

	return sign;
}
int FPU_to_exp16(FPU_REG const *a, FPU_REG *x)
{
	int sign = getsign(a);

	*(long long *)&(x->sigl) = *(const long long *)&(a->sigl);

	
	setexponent16(x, exponent(a));

	if (exponent16(x) == EXP_UNDER) {
		
		

		if (x->sigh & 0x80000000) {
			
			addexponent(x, 1);
		} else {
			
			addexponent(x, 1);
			FPU_normalize_nuo(x);
		}
	}

	if (!(x->sigh & 0x80000000)) {
		EXCEPTION(EX_INTERNAL | 0x180);
	}

	return sign;
}
Ejemplo n.º 4
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 flags)
{
  FPU_REG tmp;
  u_char tmptag;
  u64 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;
    }

  if ( flags & FPTAN )
    st0_ptr->exp ++;         /* Effectively base the following upon pi/4 */

  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_nuo(&tmp,
                                 EXTENDED_Ebias);  /* No underflow or overflow
                                                      is possible */

      FPU_copy_to_reg0(&tmp, st0_tag);
    }

  if ( ((flags & FCOS) && !(q & 1)) || (!(flags & FCOS) && (q & 1)) )
    {
      st0_tag = FPU_sub(REV|LOADED|TAG_Valid, &CONST_PI2, FULL_PRECISION); //bbd: arg2 used to typecast to (int)

#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_nuo(&tmp,
                            EXTENDED_Ebias);  /* No underflow or overflow
                                                 is possible */
	  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) && !(flags & FPTAN) )
	    {
	      /* 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. */
              /* The function is even, so we need just adjust the sign
                 and q. */
	      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_nuo(&tmp,
                            EXTENDED_Ebias);  /* No underflow or overflow
                                                 is possible.
                                                 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), &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. 
	         bbd: arg2 used to typecast to (int), corrupting 64-bit ptrs
	       */
	      st0_tag = FPU_sub(REV|LOADED|TAG_Valid, &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. */

  if ( flags & FPTAN )
    {
      st0_ptr->exp --;
      return q & 7;
    }

  return (q & 3) | (flags & FCOS);
}
Ejemplo n.º 5
0
/*--- poly_l2() -------------------------------------------------------------+
 |   Base 2 logarithm by a polynomial approximation.                         |
 +---------------------------------------------------------------------------*/
void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign)
{
	long int exponent, expon, expon_expon;
	Xsig accumulator, expon_accum, yaccum;
	u_char sign, argsign;
	FPU_REG x;
	int tag;

	exponent = exponent16(st0_ptr);

	/* From st0_ptr, make a number > sqrt(2)/2 and < sqrt(2) */
	if (st0_ptr->sigh > (unsigned)0xb504f334) {
		/* Treat as  sqrt(2)/2 < st0_ptr < 1 */
		significand(&x) = -significand(st0_ptr);
		setexponent16(&x, -1);
		exponent++;
		argsign = SIGN_NEG;
	} else {
		/* Treat as  1 <= st0_ptr < sqrt(2) */
		x.sigh = st0_ptr->sigh - 0x80000000;
		x.sigl = st0_ptr->sigl;
		setexponent16(&x, 0);
		argsign = SIGN_POS;
	}
	tag = FPU_normalize_nuo(&x);

	if (tag == TAG_Zero) {
		expon = 0;
		accumulator.msw = accumulator.midw = accumulator.lsw = 0;
	} else {
		log2_kernel(&x, argsign, &accumulator, &expon);
	}

	if (exponent < 0) {
		sign = SIGN_NEG;
		exponent = -exponent;
	} else
		sign = SIGN_POS;
	expon_accum.msw = exponent;
	expon_accum.midw = expon_accum.lsw = 0;
	if (exponent) {
		expon_expon = 31 + norm_Xsig(&expon_accum);
		shr_Xsig(&accumulator, expon_expon - expon);

		if (sign ^ argsign)
			negate_Xsig(&accumulator);
		add_Xsig_Xsig(&accumulator, &expon_accum);
	} else {
		expon_expon = expon;
		sign = argsign;
	}

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

	expon_expon += round_Xsig(&accumulator);

	if (accumulator.msw == 0) {
		FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
		return;
	}

	significand(st1_ptr) = XSIG_LL(accumulator);
	setexponent16(st1_ptr, expon_expon + exponent16(st1_ptr) + 1);

	tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign ^ st1_sign);
	FPU_settagi(1, tag);

	set_precision_flag_up();	/* 80486 appears to always do this */

	return;

}