static floatx80 fyl2x(floatx80 a, floatx80 b) { UINT64 aSig = extractFloatx80Frac(a); INT32 aExp = extractFloatx80Exp(a); int aSign = extractFloatx80Sign(a); UINT64 bSig = extractFloatx80Frac(b); INT32 bExp = extractFloatx80Exp(b); int bSign = extractFloatx80Sign(b); int zSign = bSign ^ 1; if (aExp == 0x7FFF) { if ((UINT64) (aSig<<1) || ((bExp == 0x7FFF) && (UINT64) (bSig<<1))) { return propagateFloatx80NaN(a, b); } if (aSign) { invalid: float_raise(float_flag_invalid); return floatx80_default_nan; } else { if (bExp == 0) { if (bSig == 0) goto invalid; float_raise(float_flag_denormal); } return packFloatx80(bSign, 0x7FFF, U64(0x8000000000000000)); } } if (bExp == 0x7FFF) { if ((UINT64) (bSig<<1)) return propagateFloatx80NaN(a, b); if (aSign && (UINT64)(aExp | aSig)) goto invalid; if (aSig && (aExp == 0)) float_raise(float_flag_denormal); if (aExp < 0x3FFF) { return packFloatx80(zSign, 0x7FFF, U64(0x8000000000000000)); } if (aExp == 0x3FFF && ((UINT64) (aSig<<1) == 0)) goto invalid; return packFloatx80(bSign, 0x7FFF, U64(0x8000000000000000)); } if (aExp == 0) { if (aSig == 0) { if ((bExp | bSig) == 0) goto invalid; float_raise(float_flag_divbyzero); return packFloatx80(zSign, 0x7FFF, U64(0x8000000000000000)); } if (aSign) goto invalid; float_raise(float_flag_denormal); normalizeFloatx80Subnormal(aSig, &aExp, &aSig); } if (aSign) goto invalid; if (bExp == 0) { if (bSig == 0) { if (aExp < 0x3FFF) return packFloatx80(zSign, 0, 0); return packFloatx80(bSign, 0, 0); } float_raise(float_flag_denormal); normalizeFloatx80Subnormal(bSig, &bExp, &bSig); } if (aExp == 0x3FFF && ((UINT64) (aSig<<1) == 0)) return packFloatx80(bSign, 0, 0); float_raise(float_flag_inexact); int ExpDiff = aExp - 0x3FFF; aExp = 0; if (aSig >= SQRT2_HALF_SIG) { ExpDiff++; aExp--; } /* ******************************** */ /* using float128 for approximation */ /* ******************************** */ UINT64 zSig0, zSig1; shift128Right(aSig<<1, 0, 16, &zSig0, &zSig1); float128 x = packFloat128(0, aExp+0x3FFF, zSig0, zSig1); x = poly_l2(x); x = float128_add(x, int64_to_float128((INT64) ExpDiff)); return floatx80_mul(b, float128_to_floatx80(x)); }
floatx80 fyl2xp1(floatx80 a, floatx80 b) { INT32 aExp, bExp; UINT64 aSig, bSig, zSig0, zSig1, zSig2; int aSign, bSign; aSig = extractFloatx80Frac(a); aExp = extractFloatx80Exp(a); aSign = extractFloatx80Sign(a); bSig = extractFloatx80Frac(b); bExp = extractFloatx80Exp(b); bSign = extractFloatx80Sign(b); int zSign = aSign ^ bSign; if (aExp == 0x7FFF) { if ((UINT64) (aSig<<1) || ((bExp == 0x7FFF) && (UINT64) (bSig<<1))) { return propagateFloatx80NaN(a, b); } if (aSign) { invalid: float_raise(float_flag_invalid); return floatx80_default_nan; } else { if (bExp == 0) { if (bSig == 0) goto invalid; float_raise(float_flag_denormal); } return packFloatx80(bSign, 0x7FFF, U64(0x8000000000000000)); } } if (bExp == 0x7FFF) { if ((UINT64) (bSig<<1)) return propagateFloatx80NaN(a, b); if (aExp == 0) { if (aSig == 0) goto invalid; float_raise(float_flag_denormal); } return packFloatx80(zSign, 0x7FFF, U64(0x8000000000000000)); } if (aExp == 0) { if (aSig == 0) { if (bSig && (bExp == 0)) float_raise(float_flag_denormal); return packFloatx80(zSign, 0, 0); } float_raise(float_flag_denormal); normalizeFloatx80Subnormal(aSig, &aExp, &aSig); } if (bExp == 0) { if (bSig == 0) return packFloatx80(zSign, 0, 0); float_raise(float_flag_denormal); normalizeFloatx80Subnormal(bSig, &bExp, &bSig); } float_raise(float_flag_inexact); if (aSign && aExp >= 0x3FFF) return a; if (aExp >= 0x3FFC) // big argument { return fyl2x(floatx80_add(a, floatx80_one), b); } // handle tiny argument if (aExp < EXP_BIAS-70) { // first order approximation, return (a*b)/ln(2) INT32 zExp = aExp + FLOAT_LN2INV_EXP - 0x3FFE; mul128By64To192(FLOAT_LN2INV_HI, FLOAT_LN2INV_LO, aSig, &zSig0, &zSig1, &zSig2); if (0 < (INT64) zSig0) { shortShift128Left(zSig0, zSig1, 1, &zSig0, &zSig1); --zExp; } zExp = zExp + bExp - 0x3FFE; mul128By64To192(zSig0, zSig1, bSig, &zSig0, &zSig1, &zSig2); if (0 < (INT64) zSig0) { shortShift128Left(zSig0, zSig1, 1, &zSig0, &zSig1); --zExp; } return roundAndPackFloatx80(80, aSign ^ bSign, zExp, zSig0, zSig1); } /* ******************************** */ /* using float128 for approximation */ /* ******************************** */ shift128Right(aSig<<1, 0, 16, &zSig0, &zSig1); float128 x = packFloat128(aSign, aExp, zSig0, zSig1); x = poly_l2p1(x); return floatx80_mul(b, float128_to_floatx80(x)); }
/*============================================================================ * Written for Bochs (x86 achitecture simulator) by * Stanislav Shwartsman [sshwarts at sourceforge net] * ==========================================================================*/ #define FLOAT128 #include "softfloatx80.h" #include "softfloat-round-pack.h" #include "fpu_constant.h" #define FPATAN_ARR_SIZE 11 static const float128 float128_one = packFloat128(BX_CONST64(0x3fff000000000000), BX_CONST64(0x0000000000000000)); static const float128 float128_sqrt3 = packFloat128(BX_CONST64(0x3fffbb67ae8584ca), BX_CONST64(0xa73b25742d7078b8)); static const floatx80 floatx80_pi = packFloatx80(0, 0x4000, BX_CONST64(0xc90fdaa22168c235)); static const float128 float128_pi2 = packFloat128(BX_CONST64(0x3fff921fb54442d1), BX_CONST64(0x8469898CC5170416)); static const float128 float128_pi4 = packFloat128(BX_CONST64(0x3ffe921fb54442d1), BX_CONST64(0x8469898CC5170416)); static const float128 float128_pi6 = packFloat128(BX_CONST64(0x3ffe0c152382d736), BX_CONST64(0x58465BB32E0F580F)); static float128 atan_arr[FPATAN_ARR_SIZE] = { PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 1 */