/*--- poly_atan() -----------------------------------------------------------+ | | +---------------------------------------------------------------------------*/ void poly_atan(FPU_REG *st0_ptr, u_char st0_tag, FPU_REG *st1_ptr, u_char st1_tag) { u_char transformed, inverted, sign1, sign2; int exponent; long int dummy_exp; Xsig accumulator, Numer, Denom, accumulatore, argSignif, argSq, argSqSq; u_char tag; sign1 = getsign(st0_ptr); sign2 = getsign(st1_ptr); if ( st0_tag == TAG_Valid ) { exponent = exponent(st0_ptr); } else { /* This gives non-compatible stack contents... */ FPU_to_exp16(st0_ptr, st0_ptr); exponent = exponent16(st0_ptr); } if ( st1_tag == TAG_Valid ) { exponent -= exponent(st1_ptr); } else { /* This gives non-compatible stack contents... */ FPU_to_exp16(st1_ptr, st1_ptr); exponent -= exponent16(st1_ptr); } if ( (exponent < 0) || ((exponent == 0) && ((st0_ptr->sigh < st1_ptr->sigh) || ((st0_ptr->sigh == st1_ptr->sigh) && (st0_ptr->sigl < st1_ptr->sigl))) ) ) { inverted = 1; Numer.lsw = Denom.lsw = 0; XSIG_LL(Numer) = significand(st0_ptr); XSIG_LL(Denom) = significand(st1_ptr); } else { inverted = 0; exponent = -exponent; Numer.lsw = Denom.lsw = 0; XSIG_LL(Numer) = significand(st1_ptr); XSIG_LL(Denom) = significand(st0_ptr); } div_Xsig(&Numer, &Denom, &argSignif); exponent += norm_Xsig(&argSignif); if ( (exponent >= -1) || ((exponent == -2) && (argSignif.msw > 0xd413ccd0)) ) { /* The argument is greater than sqrt(2)-1 (=0.414213562...) */ /* Convert the argument by an identity for atan */ transformed = 1; if ( exponent >= 0 ) { #ifdef PARANOID if ( !( (exponent == 0) && (argSignif.lsw == 0) && (argSignif.midw == 0) && (argSignif.msw == 0x80000000) ) ) { EXCEPTION(EX_INTERNAL|0x104); /* There must be a logic error */ return; } #endif /* PARANOID */ argSignif.msw = 0; /* Make the transformed arg -> 0.0 */ } else { Numer.lsw = Denom.lsw = argSignif.lsw; XSIG_LL(Numer) = XSIG_LL(Denom) = XSIG_LL(argSignif); if ( exponent < -1 ) shr_Xsig(&Numer, -1-exponent); negate_Xsig(&Numer); shr_Xsig(&Denom, -exponent); Denom.msw |= 0x80000000; div_Xsig(&Numer, &Denom, &argSignif); exponent = -1 + norm_Xsig(&argSignif); } } else { transformed = 0; } argSq.lsw = argSignif.lsw; argSq.midw = argSignif.midw; argSq.msw = argSignif.msw; mul_Xsig_Xsig(&argSq, &argSq); argSqSq.lsw = argSq.lsw; argSqSq.midw = argSq.midw; argSqSq.msw = argSq.msw; mul_Xsig_Xsig(&argSqSq, &argSqSq); accumulatore.lsw = argSq.lsw; XSIG_LL(accumulatore) = XSIG_LL(argSq); shr_Xsig(&argSq, 2*(-1-exponent-1)); shr_Xsig(&argSqSq, 4*(-1-exponent-1)); /* Now have argSq etc with binary point at the left .1xxxxxxxx */ /* Do the basic fixed point polynomial evaluation */ accumulator.msw = accumulator.midw = accumulator.lsw = 0; polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq), oddplterms, HIPOWERop-1); mul64_Xsig(&accumulator, &XSIG_LL(argSq)); negate_Xsig(&accumulator); polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq), oddnegterms, HIPOWERon-1); negate_Xsig(&accumulator); add_two_Xsig(&accumulator, &fixedpterm, &dummy_exp); mul64_Xsig(&accumulatore, &denomterm); shr_Xsig(&accumulatore, 1 + 2*(-1-exponent)); accumulatore.msw |= 0x80000000; div_Xsig(&accumulator, &accumulatore, &accumulator); mul_Xsig_Xsig(&accumulator, &argSignif); mul_Xsig_Xsig(&accumulator, &argSq); shr_Xsig(&accumulator, 3); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &argSignif); if ( transformed ) { /* compute pi/4 - accumulator */ shr_Xsig(&accumulator, -1-exponent); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &pi_signif); exponent = -1; } if ( inverted ) { /* compute pi/2 - accumulator */ shr_Xsig(&accumulator, -exponent); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &pi_signif); exponent = 0; } if ( sign1 ) { /* compute pi - accumulator */ shr_Xsig(&accumulator, 1 - exponent); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &pi_signif); exponent = 1; } exponent += round_Xsig(&accumulator); significand(st1_ptr) = XSIG_LL(accumulator); setexponent16(st1_ptr, exponent); tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign2); FPU_settagi(1, tag); set_precision_flag_up(); /* We do not really know if up or down, use this as the default. */ }
/*--- 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
void poly_atan(FPU_REG *st0_ptr, u_char st0_tag, FPU_REG *st1_ptr, u_char st1_tag) { u_char transformed, inverted, sign1, sign2; int exponent; long int dummy_exp; Xsig accumulator, Numer, Denom, accumulatore, argSignif, argSq, argSqSq; u_char tag; sign1 = getsign(st0_ptr); sign2 = getsign(st1_ptr); if (st0_tag == TAG_Valid) { exponent = exponent(st0_ptr); } else { FPU_to_exp16(st0_ptr, st0_ptr); exponent = exponent16(st0_ptr); } if (st1_tag == TAG_Valid) { exponent -= exponent(st1_ptr); } else { FPU_to_exp16(st1_ptr, st1_ptr); exponent -= exponent16(st1_ptr); } if ((exponent < 0) || ((exponent == 0) && ((st0_ptr->sigh < st1_ptr->sigh) || ((st0_ptr->sigh == st1_ptr->sigh) && (st0_ptr->sigl < st1_ptr->sigl))))) { inverted = 1; Numer.lsw = Denom.lsw = 0; XSIG_LL(Numer) = significand(st0_ptr); XSIG_LL(Denom) = significand(st1_ptr); } else { inverted = 0; exponent = -exponent; Numer.lsw = Denom.lsw = 0; XSIG_LL(Numer) = significand(st1_ptr); XSIG_LL(Denom) = significand(st0_ptr); } div_Xsig(&Numer, &Denom, &argSignif); exponent += norm_Xsig(&argSignif); if ((exponent >= -1) || ((exponent == -2) && (argSignif.msw > 0xd413ccd0))) { transformed = 1; if (exponent >= 0) { #ifdef PARANOID if (!((exponent == 0) && (argSignif.lsw == 0) && (argSignif.midw == 0) && (argSignif.msw == 0x80000000))) { EXCEPTION(EX_INTERNAL | 0x104); return; } #endif argSignif.msw = 0; } else { Numer.lsw = Denom.lsw = argSignif.lsw; XSIG_LL(Numer) = XSIG_LL(Denom) = XSIG_LL(argSignif); if (exponent < -1) shr_Xsig(&Numer, -1 - exponent); negate_Xsig(&Numer); shr_Xsig(&Denom, -exponent); Denom.msw |= 0x80000000; div_Xsig(&Numer, &Denom, &argSignif); exponent = -1 + norm_Xsig(&argSignif); } } else { transformed = 0; } argSq.lsw = argSignif.lsw; argSq.midw = argSignif.midw; argSq.msw = argSignif.msw; mul_Xsig_Xsig(&argSq, &argSq); argSqSq.lsw = argSq.lsw; argSqSq.midw = argSq.midw; argSqSq.msw = argSq.msw; mul_Xsig_Xsig(&argSqSq, &argSqSq); accumulatore.lsw = argSq.lsw; XSIG_LL(accumulatore) = XSIG_LL(argSq); shr_Xsig(&argSq, 2 * (-1 - exponent - 1)); shr_Xsig(&argSqSq, 4 * (-1 - exponent - 1)); accumulator.msw = accumulator.midw = accumulator.lsw = 0; polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq), oddplterms, HIPOWERop - 1); mul64_Xsig(&accumulator, &XSIG_LL(argSq)); negate_Xsig(&accumulator); polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq), oddnegterms, HIPOWERon - 1); negate_Xsig(&accumulator); add_two_Xsig(&accumulator, &fixedpterm, &dummy_exp); mul64_Xsig(&accumulatore, &denomterm); shr_Xsig(&accumulatore, 1 + 2 * (-1 - exponent)); accumulatore.msw |= 0x80000000; div_Xsig(&accumulator, &accumulatore, &accumulator); mul_Xsig_Xsig(&accumulator, &argSignif); mul_Xsig_Xsig(&accumulator, &argSq); shr_Xsig(&accumulator, 3); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &argSignif); if (transformed) { shr_Xsig(&accumulator, -1 - exponent); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &pi_signif); exponent = -1; } if (inverted) { shr_Xsig(&accumulator, -exponent); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &pi_signif); exponent = 0; } if (sign1) { shr_Xsig(&accumulator, 1 - exponent); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &pi_signif); exponent = 1; } exponent += round_Xsig(&accumulator); significand(st1_ptr) = XSIG_LL(accumulator); setexponent16(st1_ptr, exponent); tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign2); FPU_settagi(1, tag); set_precision_flag_up(); }
/*--- 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; }
/*--- log2_kernel() ---------------------------------------------------------+ | Base 2 logarithm by a polynomial approximation. | | log2(x+1) | +---------------------------------------------------------------------------*/ static void log2_kernel(FPU_REG const *arg, u_char argsign, Xsig *accum_result, long int *expon) { long int exponent, adj; unsigned long long Xsq; Xsig accumulator, Numer, Denom, argSignif, arg_signif; exponent = exponent16(arg); Numer.lsw = Denom.lsw = 0; XSIG_LL(Numer) = XSIG_LL(Denom) = significand(arg); if (argsign == SIGN_POS) { shr_Xsig(&Denom, 2 - (1 + exponent)); Denom.msw |= 0x80000000; div_Xsig(&Numer, &Denom, &argSignif); } else { shr_Xsig(&Denom, 1 - (1 + exponent)); negate_Xsig(&Denom); if (Denom.msw & 0x80000000) { div_Xsig(&Numer, &Denom, &argSignif); exponent++; } else { /* Denom must be 1.0 */ argSignif.lsw = Numer.lsw; argSignif.midw = Numer.midw; argSignif.msw = Numer.msw; } } #ifndef PECULIAR_486 /* Should check here that |local_arg| is within the valid range */ if (exponent >= -2) { if ((exponent > -2) || (argSignif.msw > (unsigned)0xafb0ccc0)) { /* The argument is too large */ } } #endif /* PECULIAR_486 */ arg_signif.lsw = argSignif.lsw; XSIG_LL(arg_signif) = XSIG_LL(argSignif); adj = norm_Xsig(&argSignif); accumulator.lsw = argSignif.lsw; XSIG_LL(accumulator) = XSIG_LL(argSignif); mul_Xsig_Xsig(&accumulator, &accumulator); shr_Xsig(&accumulator, 2 * (-1 - (1 + exponent + adj))); Xsq = XSIG_LL(accumulator); if (accumulator.lsw & 0x80000000) Xsq++; accumulator.msw = accumulator.midw = accumulator.lsw = 0; /* Do the basic fixed point polynomial evaluation */ polynomial_Xsig(&accumulator, &Xsq, logterms, HIPOWER - 1); mul_Xsig_Xsig(&accumulator, &argSignif); shr_Xsig(&accumulator, 6 - adj); mul32_Xsig(&arg_signif, leadterm); add_two_Xsig(&accumulator, &arg_signif, &exponent); *expon = exponent + 1; accum_result->lsw = accumulator.lsw; accum_result->midw = accumulator.midw; accum_result->msw = accumulator.msw; }
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; }
void poly_sine(FPU_REG *st0_ptr) { int exponent, echange; Xsig accumulator, argSqrd, argTo4; unsigned long fix_up, adj; unsigned long long fixed_arg; FPU_REG result; exponent = exponent(st0_ptr); accumulator.lsw = accumulator.midw = accumulator.msw = 0; if ((exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xe21240aa))) { argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl; argSqrd.lsw = 0; mul64_Xsig(&argSqrd, &significand(st0_ptr)); shr_Xsig(&argSqrd, 2 * (-1 - exponent)); argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw; argTo4.lsw = argSqrd.lsw; mul_Xsig_Xsig(&argTo4, &argTo4); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l, N_COEFF_N - 1); mul_Xsig_Xsig(&accumulator, &argSqrd); negate_Xsig(&accumulator); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l, N_COEFF_P - 1); shr_Xsig(&accumulator, 2); accumulator.msw |= 0x80000000; mul64_Xsig(&accumulator, &significand(st0_ptr)); mul64_Xsig(&accumulator, &significand(st0_ptr)); mul64_Xsig(&accumulator, &significand(st0_ptr)); exponent = 3 * exponent; shr_Xsig(&accumulator, exponent(st0_ptr) - exponent); negate_Xsig(&accumulator); XSIG_LL(accumulator) += significand(st0_ptr); echange = round_Xsig(&accumulator); setexponentpos(&result, exponent(st0_ptr) + echange); } else { fixed_arg = significand(st0_ptr); if (exponent == 0) { fixed_arg <<= 1; } fixed_arg = 0x921fb54442d18469LL - fixed_arg; if (fixed_arg == 0xffffffffffffffffLL) fixed_arg = 0; XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0; mul64_Xsig(&argSqrd, &fixed_arg); XSIG_LL(argTo4) = XSIG_LL(argSqrd); argTo4.lsw = argSqrd.lsw; mul_Xsig_Xsig(&argTo4, &argTo4); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h, N_COEFF_NH - 1); mul_Xsig_Xsig(&accumulator, &argSqrd); negate_Xsig(&accumulator); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h, N_COEFF_PH - 1); negate_Xsig(&accumulator); mul64_Xsig(&accumulator, &fixed_arg); mul64_Xsig(&accumulator, &fixed_arg); shr_Xsig(&accumulator, 3); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &argSqrd); shr_Xsig(&accumulator, 1); accumulator.lsw |= 1; negate_Xsig(&accumulator); fix_up = 0x898cc517; if (argSqrd.msw & 0xffc00000) { fix_up -= mul_32_32(0x898cc517, argSqrd.msw) / 6; } fix_up = mul_32_32(fix_up, LL_MSW(fixed_arg)); adj = accumulator.lsw; accumulator.lsw -= fix_up; if (accumulator.lsw > adj) XSIG_LL(accumulator)--; echange = round_Xsig(&accumulator); setexponentpos(&result, echange - 1); } significand(&result) = XSIG_LL(accumulator); setsign(&result, getsign(st0_ptr)); FPU_copy_to_reg0(&result, TAG_Valid); #ifdef PARANOID if ((exponent(&result) >= 0) && (significand(&result) > 0x8000000000000000LL)) { EXCEPTION(EX_INTERNAL | 0x150); } #endif }
void poly_cos(FPU_REG *st0_ptr) { FPU_REG result; long int exponent, exp2, echange; Xsig accumulator, argSqrd, fix_up, argTo4; unsigned long long fixed_arg; #ifdef PARANOID if ((exponent(st0_ptr) > 0) || ((exponent(st0_ptr) == 0) && (significand(st0_ptr) > 0xc90fdaa22168c234LL))) { EXCEPTION(EX_Invalid); FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); return; } #endif exponent = exponent(st0_ptr); accumulator.lsw = accumulator.midw = accumulator.msw = 0; if ((exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xb00d6f54))) { argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl; argSqrd.lsw = 0; mul64_Xsig(&argSqrd, &significand(st0_ptr)); if (exponent < -1) { shr_Xsig(&argSqrd, 2 * (-1 - exponent)); } argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw; argTo4.lsw = argSqrd.lsw; mul_Xsig_Xsig(&argTo4, &argTo4); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h, N_COEFF_NH - 1); mul_Xsig_Xsig(&accumulator, &argSqrd); negate_Xsig(&accumulator); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h, N_COEFF_PH - 1); negate_Xsig(&accumulator); mul64_Xsig(&accumulator, &significand(st0_ptr)); mul64_Xsig(&accumulator, &significand(st0_ptr)); shr_Xsig(&accumulator, -2 * (1 + exponent)); shr_Xsig(&accumulator, 3); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &argSqrd); shr_Xsig(&accumulator, 1); negate_Xsig(&accumulator); if (accumulator.lsw & 0x80000000) XSIG_LL(accumulator)++; if (accumulator.msw == 0) { FPU_copy_to_reg0(&CONST_1, TAG_Valid); return; } else { significand(&result) = XSIG_LL(accumulator); setexponentpos(&result, -1); } } else { fixed_arg = significand(st0_ptr); if (exponent == 0) { fixed_arg <<= 1; } fixed_arg = 0x921fb54442d18469LL - fixed_arg; if (fixed_arg == 0xffffffffffffffffLL) fixed_arg = 0; exponent = -1; exp2 = -1; if (!(LL_MSW(fixed_arg) & 0xffff0000)) { fixed_arg <<= 16; exponent -= 16; exp2 -= 16; } XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0; mul64_Xsig(&argSqrd, &fixed_arg); if (exponent < -1) { shr_Xsig(&argSqrd, 2 * (-1 - exponent)); } argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw; argTo4.lsw = argSqrd.lsw; mul_Xsig_Xsig(&argTo4, &argTo4); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l, N_COEFF_N - 1); mul_Xsig_Xsig(&accumulator, &argSqrd); negate_Xsig(&accumulator); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l, N_COEFF_P - 1); shr_Xsig(&accumulator, 2); accumulator.msw |= 0x80000000; mul64_Xsig(&accumulator, &fixed_arg); mul64_Xsig(&accumulator, &fixed_arg); mul64_Xsig(&accumulator, &fixed_arg); exponent = 3 * exponent; shr_Xsig(&accumulator, exp2 - exponent); negate_Xsig(&accumulator); XSIG_LL(accumulator) += fixed_arg; XSIG_LL(fix_up) = 0x898cc51701b839a2ll; fix_up.lsw = 0; if (argSqrd.msw & 0xffc00000) { fix_up.msw -= mul_32_32(0x898cc517, argSqrd.msw) / 2; fix_up.msw += mul_32_32(0x898cc517, argTo4.msw) / 24; } exp2 += norm_Xsig(&accumulator); shr_Xsig(&accumulator, 1); exp2++; shr_Xsig(&fix_up, 65 + exp2); add_Xsig_Xsig(&accumulator, &fix_up); echange = round_Xsig(&accumulator); setexponentpos(&result, exp2 + echange); significand(&result) = XSIG_LL(accumulator); } FPU_copy_to_reg0(&result, TAG_Valid); #ifdef PARANOID if ((exponent(&result) >= 0) && (significand(&result) > 0x8000000000000000LL)) { EXCEPTION(EX_INTERNAL | 0x151); } #endif }
/*--- poly_atan() -----------------------------------------------------------+ | | +---------------------------------------------------------------------------*/ void poly_atan(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *result) { char transformed, inverted, sign1 = arg1->sign, sign2 = arg2->sign; long int exponent, dummy_exp; Xsig accumulator, Numer, Denom, accumulatore, argSignif, argSq, argSqSq; arg1->sign = arg2->sign = SIGN_POS; if ( (compare(arg2) & ~COMP_Denormal) == COMP_A_lt_B ) { inverted = 1; exponent = arg1->exp - arg2->exp; Numer.lsw = Denom.lsw = 0; XSIG_LL(Numer) = significand(arg1); XSIG_LL(Denom) = significand(arg2); } else { inverted = 0; exponent = arg2->exp - arg1->exp; Numer.lsw = Denom.lsw = 0; XSIG_LL(Numer) = significand(arg2); XSIG_LL(Denom) = significand(arg1); } div_Xsig(&Numer, &Denom, &argSignif); exponent += norm_Xsig(&argSignif); if ( (exponent >= -1) || ((exponent == -2) && (argSignif.msw > 0xd413ccd0)) ) { /* The argument is greater than sqrt(2)-1 (=0.414213562...) */ /* Convert the argument by an identity for atan */ transformed = 1; if ( exponent >= 0 ) { #ifdef PARANOID if ( !( (exponent == 0) && (argSignif.lsw == 0) && (argSignif.midw == 0) && (argSignif.msw == 0x80000000) ) ) { EXCEPTION(EX_INTERNAL|0x104); /* There must be a logic error */ return; } #endif PARANOID argSignif.msw = 0; /* Make the transformed arg -> 0.0 */ } else { Numer.lsw = Denom.lsw = argSignif.lsw; XSIG_LL(Numer) = XSIG_LL(Denom) = XSIG_LL(argSignif); if ( exponent < -1 ) shr_Xsig(&Numer, -1-exponent); negate_Xsig(&Numer); shr_Xsig(&Denom, -exponent); Denom.msw |= 0x80000000; div_Xsig(&Numer, &Denom, &argSignif); exponent = -1 + norm_Xsig(&argSignif); } } else { transformed = 0; } argSq.lsw = argSignif.lsw; argSq.midw = argSignif.midw; argSq.msw = argSignif.msw; mul_Xsig_Xsig(&argSq, &argSq); argSqSq.lsw = argSq.lsw; argSqSq.midw = argSq.midw; argSqSq.msw = argSq.msw; mul_Xsig_Xsig(&argSqSq, &argSqSq); accumulatore.lsw = argSq.lsw; XSIG_LL(accumulatore) = XSIG_LL(argSq); shr_Xsig(&argSq, 2*(-1-exponent-1)); shr_Xsig(&argSqSq, 4*(-1-exponent-1)); /* Now have argSq etc with binary point at the left .1xxxxxxxx */ /* Do the basic fixed point polynomial evaluation */ accumulator.msw = accumulator.midw = accumulator.lsw = 0; polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq), oddplterms, HIPOWERop-1); mul64_Xsig(&accumulator, &XSIG_LL(argSq)); negate_Xsig(&accumulator); polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq), oddnegterms, HIPOWERon-1); negate_Xsig(&accumulator); add_two_Xsig(&accumulator, &fixedpterm, &dummy_exp); mul64_Xsig(&accumulatore, &denomterm); shr_Xsig(&accumulatore, 1 + 2*(-1-exponent)); accumulatore.msw |= 0x80000000; div_Xsig(&accumulator, &accumulatore, &accumulator); mul_Xsig_Xsig(&accumulator, &argSignif); mul_Xsig_Xsig(&accumulator, &argSq); shr_Xsig(&accumulator, 3); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &argSignif); if ( transformed ) { /* compute pi/4 - accumulator */ shr_Xsig(&accumulator, -1-exponent); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &pi_signif); exponent = -1; } if ( inverted ) { /* compute pi/2 - accumulator */ shr_Xsig(&accumulator, -exponent); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &pi_signif); exponent = 0; } if ( sign1 ) { /* compute pi - accumulator */ shr_Xsig(&accumulator, 1 - exponent); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &pi_signif); exponent = 1; } exponent += round_Xsig(&accumulator); significand(result) = XSIG_LL(accumulator); result->exp = exponent + EXP_BIAS; result->tag = TW_Valid; result->sign = sign2; }
/*--- poly_sine() -----------------------------------------------------------+ | | +---------------------------------------------------------------------------*/ void poly_sine(FPU_REG const *arg, FPU_REG *result) { int exponent, echange; Xsig accumulator, argSqrd, argTo4; unsigned long fix_up, adj; unsigned long long fixed_arg; #ifdef PARANOID if ( arg->tag == TW_Zero ) { /* Return 0.0 */ reg_move(&CONST_Z, result); return; } #endif PARANOID exponent = arg->exp - EXP_BIAS; accumulator.lsw = accumulator.midw = accumulator.msw = 0; /* Split into two ranges, for arguments below and above 1.0 */ /* The boundary between upper and lower is approx 0.88309101259 */ if ( (exponent < -1) || ((exponent == -1) && (arg->sigh <= 0xe21240aa)) ) { /* The argument is <= 0.88309101259 */ argSqrd.msw = arg->sigh; argSqrd.midw = arg->sigl; argSqrd.lsw = 0; mul64_Xsig(&argSqrd, &significand(arg)); shr_Xsig(&argSqrd, 2*(-1-exponent)); argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw; argTo4.lsw = argSqrd.lsw; mul_Xsig_Xsig(&argTo4, &argTo4); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l, N_COEFF_N-1); mul_Xsig_Xsig(&accumulator, &argSqrd); negate_Xsig(&accumulator); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l, N_COEFF_P-1); shr_Xsig(&accumulator, 2); /* Divide by four */ accumulator.msw |= 0x80000000; /* Add 1.0 */ mul64_Xsig(&accumulator, &significand(arg)); mul64_Xsig(&accumulator, &significand(arg)); mul64_Xsig(&accumulator, &significand(arg)); /* Divide by four, FPU_REG compatible, etc */ exponent = 3*exponent + EXP_BIAS; /* The minimum exponent difference is 3 */ shr_Xsig(&accumulator, arg->exp - exponent); negate_Xsig(&accumulator); XSIG_LL(accumulator) += significand(arg); echange = round_Xsig(&accumulator); result->exp = arg->exp + echange; } else { /* The argument is > 0.88309101259 */ /* We use sin(arg) = cos(pi/2-arg) */ fixed_arg = significand(arg); if ( exponent == 0 ) { /* The argument is >= 1.0 */ /* Put the binary point at the left. */ fixed_arg <<= 1; } /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */ fixed_arg = 0x921fb54442d18469LL - fixed_arg; XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0; mul64_Xsig(&argSqrd, &fixed_arg); XSIG_LL(argTo4) = XSIG_LL(argSqrd); argTo4.lsw = argSqrd.lsw; mul_Xsig_Xsig(&argTo4, &argTo4); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h, N_COEFF_NH-1); mul_Xsig_Xsig(&accumulator, &argSqrd); negate_Xsig(&accumulator); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h, N_COEFF_PH-1); negate_Xsig(&accumulator); mul64_Xsig(&accumulator, &fixed_arg); mul64_Xsig(&accumulator, &fixed_arg); shr_Xsig(&accumulator, 3); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &argSqrd); shr_Xsig(&accumulator, 1); accumulator.lsw |= 1; /* A zero accumulator here would cause problems */ negate_Xsig(&accumulator); /* The basic computation is complete. Now fix the answer to compensate for the error due to the approximation used for pi/2 */ /* This has an exponent of -65 */ fix_up = 0x898cc517; /* The fix-up needs to be improved for larger args */ if ( argSqrd.msw & 0xffc00000 ) { /* Get about 32 bit precision in these: */ mul_32_32(0x898cc517, argSqrd.msw, &adj); fix_up -= adj/6; } mul_32_32(fix_up, LL_MSW(fixed_arg), &fix_up); adj = accumulator.lsw; /* temp save */ accumulator.lsw -= fix_up; if ( accumulator.lsw > adj ) XSIG_LL(accumulator) --; echange = round_Xsig(&accumulator); result->exp = EXP_BIAS - 1 + echange; } significand(result) = XSIG_LL(accumulator); result->tag = TW_Valid; result->sign = arg->sign; #ifdef PARANOID if ( (result->exp >= EXP_BIAS) && (significand(result) > 0x8000000000000000LL) ) { EXCEPTION(EX_INTERNAL|0x150); } #endif PARANOID }
/*--- poly_cos() ------------------------------------------------------------+ | | +---------------------------------------------------------------------------*/ void poly_cos(FPU_REG const *arg, FPU_REG *result) { long int exponent, exp2, echange; Xsig accumulator, argSqrd, fix_up, argTo4; unsigned long adj; unsigned long long fixed_arg; #ifdef PARANOID if ( arg->tag == TW_Zero ) { /* Return 1.0 */ reg_move(&CONST_1, result); return; } if ( (arg->exp > EXP_BIAS) || ((arg->exp == EXP_BIAS) && (significand(arg) > 0xc90fdaa22168c234LL)) ) { EXCEPTION(EX_Invalid); reg_move(&CONST_QNaN, result); return; } #endif PARANOID exponent = arg->exp - EXP_BIAS; accumulator.lsw = accumulator.midw = accumulator.msw = 0; if ( (exponent < -1) || ((exponent == -1) && (arg->sigh <= 0xb00d6f54)) ) { /* arg is < 0.687705 */ argSqrd.msw = arg->sigh; argSqrd.midw = arg->sigl; argSqrd.lsw = 0; mul64_Xsig(&argSqrd, &significand(arg)); if ( exponent < -1 ) { /* shift the argument right by the required places */ shr_Xsig(&argSqrd, 2*(-1-exponent)); } argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw; argTo4.lsw = argSqrd.lsw; mul_Xsig_Xsig(&argTo4, &argTo4); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h, N_COEFF_NH-1); mul_Xsig_Xsig(&accumulator, &argSqrd); negate_Xsig(&accumulator); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h, N_COEFF_PH-1); negate_Xsig(&accumulator); mul64_Xsig(&accumulator, &significand(arg)); mul64_Xsig(&accumulator, &significand(arg)); shr_Xsig(&accumulator, -2*(1+exponent)); shr_Xsig(&accumulator, 3); negate_Xsig(&accumulator); add_Xsig_Xsig(&accumulator, &argSqrd); shr_Xsig(&accumulator, 1); /* It doesn't matter if accumulator is all zero here, the following code will work ok */ negate_Xsig(&accumulator); if ( accumulator.lsw & 0x80000000 ) XSIG_LL(accumulator) ++; if ( accumulator.msw == 0 ) { /* The result is 1.0 */ reg_move(&CONST_1, result); } else { significand(result) = XSIG_LL(accumulator); /* will be a valid positive nr with expon = -1 */ *(short *)&(result->sign) = 0; result->exp = EXP_BIAS - 1; } } else { fixed_arg = significand(arg); if ( exponent == 0 ) { /* The argument is >= 1.0 */ /* Put the binary point at the left. */ fixed_arg <<= 1; } /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */ fixed_arg = 0x921fb54442d18469LL - fixed_arg; exponent = -1; exp2 = -1; /* A shift is needed here only for a narrow range of arguments, i.e. for fixed_arg approx 2^-32, but we pick up more... */ if ( !(LL_MSW(fixed_arg) & 0xffff0000) ) { fixed_arg <<= 16; exponent -= 16; exp2 -= 16; } XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0; mul64_Xsig(&argSqrd, &fixed_arg); if ( exponent < -1 ) { /* shift the argument right by the required places */ shr_Xsig(&argSqrd, 2*(-1-exponent)); } argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw; argTo4.lsw = argSqrd.lsw; mul_Xsig_Xsig(&argTo4, &argTo4); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l, N_COEFF_N-1); mul_Xsig_Xsig(&accumulator, &argSqrd); negate_Xsig(&accumulator); polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l, N_COEFF_P-1); shr_Xsig(&accumulator, 2); /* Divide by four */ accumulator.msw |= 0x80000000; /* Add 1.0 */ mul64_Xsig(&accumulator, &fixed_arg); mul64_Xsig(&accumulator, &fixed_arg); mul64_Xsig(&accumulator, &fixed_arg); /* Divide by four, FPU_REG compatible, etc */ exponent = 3*exponent; /* The minimum exponent difference is 3 */ shr_Xsig(&accumulator, exp2 - exponent); negate_Xsig(&accumulator); XSIG_LL(accumulator) += fixed_arg; /* The basic computation is complete. Now fix the answer to compensate for the error due to the approximation used for pi/2 */ /* This has an exponent of -65 */ XSIG_LL(fix_up) = 0x898cc51701b839a2ll; fix_up.lsw = 0; /* The fix-up needs to be improved for larger args */ if ( argSqrd.msw & 0xffc00000 ) { /* Get about 32 bit precision in these: */ mul_32_32(0x898cc517, argSqrd.msw, &adj); fix_up.msw -= adj/2; mul_32_32(0x898cc517, argTo4.msw, &adj); fix_up.msw += adj/24; } exp2 += norm_Xsig(&accumulator); shr_Xsig(&accumulator, 1); /* Prevent overflow */ exp2++; shr_Xsig(&fix_up, 65 + exp2); add_Xsig_Xsig(&accumulator, &fix_up); echange = round_Xsig(&accumulator); result->exp = exp2 + EXP_BIAS + echange; *(short *)&(result->sign) = 0; /* Is a valid positive nr */ significand(result) = XSIG_LL(accumulator); } #ifdef PARANOID if ( (result->exp >= EXP_BIAS) && (significand(result) > 0x8000000000000000LL) ) { EXCEPTION(EX_INTERNAL|0x151); } #endif PARANOID }