long_double __subxf3(long_double A, long_double B) { #if __SIZEOF_LONG_DOUBLE__ == 12 return floatx80_sub(A, B); #else return float128_sub(A, B); #endif }
/* required sqrt(2)/2 < x < sqrt(2) */ static float128 poly_l2(float128 x) { /* using float128 for approximation */ float128 x_p1 = float128_add(x, float128_one); float128 x_m1 = float128_sub(x, float128_one); x = float128_div(x_m1, x_p1); x = poly_ln(x); x = float128_mul(x, float128_ln2inv2); return x; }
/* 128-bit FP subtraction RR */ uint32_t HELPER(sxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) { CPU_QuadU v1; CPU_QuadU v2; CPU_QuadU res; v1.ll.upper = env->fregs[f1].ll; v1.ll.lower = env->fregs[f1 + 2].ll; v2.ll.upper = env->fregs[f2].ll; v2.ll.lower = env->fregs[f2 + 2].ll; res.q = float128_sub(v1.q, v2.q, &env->fpu_status); env->fregs[f1].ll = res.ll.upper; env->fregs[f1 + 2].ll = res.ll.lower; return set_cc_nz_f128(res.q); }
floatx80 fpatan(floatx80 a, floatx80 b, float_status_t &status) { // handle unsupported extended double-precision floating encodings if (floatx80_is_unsupported(a) || floatx80_is_unsupported(b)) { float_raise(status, float_flag_invalid); return floatx80_default_nan; } Bit64u aSig = extractFloatx80Frac(a); Bit32s aExp = extractFloatx80Exp(a); int aSign = extractFloatx80Sign(a); Bit64u bSig = extractFloatx80Frac(b); Bit32s bExp = extractFloatx80Exp(b); int bSign = extractFloatx80Sign(b); int zSign = aSign ^ bSign; if (bExp == 0x7FFF) { if ((Bit64u) (bSig<<1)) return propagateFloatx80NaN(a, b, status); if (aExp == 0x7FFF) { if ((Bit64u) (aSig<<1)) return propagateFloatx80NaN(a, b, status); if (aSign) { /* return 3PI/4 */ return roundAndPackFloatx80(80, bSign, FLOATX80_3PI4_EXP, FLOAT_3PI4_HI, FLOAT_3PI4_LO, status); } else { /* return PI/4 */ return roundAndPackFloatx80(80, bSign, FLOATX80_PI4_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status); } } if (aSig && (aExp == 0)) float_raise(status, float_flag_denormal); /* return PI/2 */ return roundAndPackFloatx80(80, bSign, FLOATX80_PI2_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status); } if (aExp == 0x7FFF) { if ((Bit64u) (aSig<<1)) return propagateFloatx80NaN(a, b, status); if (bSig && (bExp == 0)) float_raise(status, float_flag_denormal); return_PI_or_ZERO: if (aSign) { /* return PI */ return roundAndPackFloatx80(80, bSign, FLOATX80_PI_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status); } else { /* return 0 */ return packFloatx80(bSign, 0, 0); } } if (bExp == 0) { if (bSig == 0) { if (aSig && (aExp == 0)) float_raise(status, float_flag_denormal); goto return_PI_or_ZERO; } float_raise(status, float_flag_denormal); normalizeFloatx80Subnormal(bSig, &bExp, &bSig); } if (aExp == 0) { if (aSig == 0) /* return PI/2 */ return roundAndPackFloatx80(80, bSign, FLOATX80_PI2_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status); float_raise(status, float_flag_denormal); normalizeFloatx80Subnormal(aSig, &aExp, &aSig); } float_raise(status, float_flag_inexact); /* |a| = |b| ==> return PI/4 */ if (aSig == bSig && aExp == bExp) return roundAndPackFloatx80(80, bSign, FLOATX80_PI4_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status); /* ******************************** */ /* using float128 for approximation */ /* ******************************** */ float128 a128 = normalizeRoundAndPackFloat128(0, aExp-0x10, aSig, 0, status); float128 b128 = normalizeRoundAndPackFloat128(0, bExp-0x10, bSig, 0, status); float128 x; int swap = 0, add_pi6 = 0, add_pi4 = 0; if (aExp > bExp || (aExp == bExp && aSig > bSig)) { x = float128_div(b128, a128, status); } else { x = float128_div(a128, b128, status); swap = 1; } Bit32s xExp = extractFloat128Exp(x); if (xExp <= EXP_BIAS-40) goto approximation_completed; if (x.hi >= BX_CONST64(0x3ffe800000000000)) // 3/4 < x < 1 { /* arctan(x) = arctan((x-1)/(x+1)) + pi/4 */ float128 t1 = float128_sub(x, float128_one, status); float128 t2 = float128_add(x, float128_one, status); x = float128_div(t1, t2, status); add_pi4 = 1; } else { /* argument correction */ if (xExp >= 0x3FFD) // 1/4 < x < 3/4 { /* arctan(x) = arctan((x*sqrt(3)-1)/(x+sqrt(3))) + pi/6 */ float128 t1 = float128_mul(x, float128_sqrt3, status); float128 t2 = float128_add(x, float128_sqrt3, status); x = float128_sub(t1, float128_one, status); x = float128_div(x, t2, status); add_pi6 = 1; } } x = poly_atan(x, status); if (add_pi6) x = float128_add(x, float128_pi6, status); if (add_pi4) x = float128_add(x, float128_pi4, status); approximation_completed: if (swap) x = float128_sub(float128_pi2, x, status); floatx80 result = float128_to_floatx80(x, status); if (zSign) floatx80_chs(result); int rSign = extractFloatx80Sign(result); if (!bSign && rSign) return floatx80_add(result, floatx80_pi, status); if (bSign && !rSign) return floatx80_sub(result, floatx80_pi, status); return result; }