long double __ieee754_remainderl(long double x, long double p) { int64_t hx,hp; u_int64_t sx,lx,lp; long double p_half; double xhi, xlo, phi, plo; ldbl_unpack (x, &xhi, &xlo); EXTRACT_WORDS64 (hx, xhi); EXTRACT_WORDS64 (lx, xlo); ldbl_unpack (p, &phi, &plo); EXTRACT_WORDS64 (hp, phi); EXTRACT_WORDS64 (lp, plo); sx = hx&0x8000000000000000ULL; lp ^= hp & 0x8000000000000000ULL; hp &= 0x7fffffffffffffffLL; lx ^= sx; hx &= 0x7fffffffffffffffLL; if (lp == 0x8000000000000000ULL) lp = 0; if (lx == 0x8000000000000000ULL) lx = 0; /* purge off exception values */ if(hp==0) return (x*p)/(x*p); /* p = 0 */ if((hx>=0x7ff0000000000000LL)|| /* x not finite */ (hp>0x7ff0000000000000LL)) /* p is NaN */ return (x*p)/(x*p); if (hp<=0x7fdfffffffffffffLL) x = __ieee754_fmodl(x,p+p); /* now x < 2p */ if (((hx-hp)|(lx-lp))==0) return zero*x; x = fabsl(x); p = fabsl(p); if (hp<0x0020000000000000LL) { if(x+x>p) { x-=p; if(x+x>=p) x -= p; } } else { p_half = 0.5L*p; if(x>p_half) { x-=p; if(x>=p_half) x -= p; } } if (sx) x = -x; return x; }
int FUNC (long double *x, long double payload) { double hi, lo; uint64_t hx, lx; ldbl_unpack (payload, &hi, &lo); EXTRACT_WORDS64 (hx, hi); EXTRACT_WORDS64 (lx, lo); int exponent = hx >> EXPLICIT_MANT_DIG; /* Test if argument is (a) negative or too large; (b) too small, except for 0 when allowed; (c) not an integer. All valid arguments have the low part zero. */ if ((lx & 0x7fffffffffffffffULL) != 0 || exponent >= BIAS + PAYLOAD_DIG || (exponent < BIAS && !(SET_HIGH_BIT && hx == 0)) || (hx & ((1ULL << (BIAS + EXPLICIT_MANT_DIG - exponent)) - 1)) != 0) { *x = 0.0L; return 1; } if (hx != 0) { hx &= (1ULL << EXPLICIT_MANT_DIG) - 1; hx |= 1ULL << EXPLICIT_MANT_DIG; hx >>= BIAS + EXPLICIT_MANT_DIG - exponent; }
long double __truncl (long double x) { double xh, xl, hi, lo; ldbl_unpack (x, &xh, &xl); /* Return Inf, Nan, +/-0 unchanged. */ if (__builtin_expect (xh != 0.0 && __builtin_isless (__builtin_fabs (xh), __builtin_inf ()), 1)) { double orig_xh; /* Long double arithmetic, including the canonicalisation below, only works in round-to-nearest mode. */ /* Convert the high double to integer. */ orig_xh = xh; hi = ldbl_nearbyint (xh); /* Subtract integral high part from the value. */ xh -= hi; ldbl_canonicalize (&xh, &xl); /* Now convert the low double, adjusted for any remainder from the high double. */ lo = ldbl_nearbyint (xh); /* Adjust the result when the remainder is non-zero. nearbyint rounds values to the nearest integer, and values halfway between integers to the nearest even integer. floorl must round towards -Inf. */ xh -= lo; ldbl_canonicalize (&xh, &xl); if (orig_xh < 0.0) { if (xh > 0.0 || (xh == 0.0 && xl > 0.0)) lo += 1.0; } else { if (xh < 0.0 || (xh == 0.0 && xl < 0.0)) lo -= 1.0; } /* Ensure the final value is canonical. In certain cases, rounding causes hi,lo calculated so far to be non-canonical. */ xh = hi; xl = lo; ldbl_canonicalize (&xh, &xl); /* Ensure we return -0 rather than +0 when appropriate. */ if (orig_xh < 0.0) xh = -__builtin_fabs (xh); } return ldbl_pack (xh, xl); }
long double __truncl (long double x) { double xh, xl, hi, lo; ldbl_unpack (x, &xh, &xl); /* Return Inf, Nan, +/-0 unchanged. */ if (__builtin_expect (xh != 0.0 && __builtin_isless (__builtin_fabs (xh), __builtin_inf ()), 1)) { hi = __trunc (xh); if (hi != xh) { /* The high part is not an integer; the low part does not affect the result. */ xh = hi; xl = 0; } else { /* The high part is a nonzero integer. */ lo = xh > 0 ? __floor (xl) : __ceil (xl); xh = hi; xl = lo; ldbl_canonicalize_int (&xh, &xl); } } return ldbl_pack (xh, xl); }
long double __ieee754_acoshl(long double x) { long double t; int64_t hx; uint64_t lx; double xhi, xlo; ldbl_unpack (x, &xhi, &xlo); EXTRACT_WORDS64 (hx, xhi); EXTRACT_WORDS64 (lx, xlo); if(hx<0x3ff0000000000000LL) { /* x < 1 */ return (x-x)/(x-x); } else if(hx >=0x41b0000000000000LL) { /* x > 2**28 */ if(hx >=0x7ff0000000000000LL) { /* x is inf of NaN */ return x+x; } else return __ieee754_logl(x)+ln2; /* acosh(huge)=log(2x) */ } else if (((hx-0x3ff0000000000000LL)|(lx&0x7fffffffffffffffLL))==0) { return 0.0; /* acosh(1) = 0 */ } else if (hx > 0x4000000000000000LL) { /* 2**28 > x > 2 */ t=x*x; return __ieee754_logl(2.0*x-one/(x+__ieee754_sqrtl(t-one))); } else { /* 1<x<2 */ t = x-one; return __log1pl(t+__ieee754_sqrtl(2.0*t+t*t)); } }
long double __roundl (long double x) { double xh, xl, hi, lo; ldbl_unpack (x, &xh, &xl); /* Return Inf, Nan, +/-0 unchanged. */ if (__builtin_expect (xh != 0.0 && __builtin_isless (__builtin_fabs (xh), __builtin_inf ()), 1)) { hi = __round (xh); if (hi != xh) { /* The high part is not an integer; the low part only affects the result if the high part is exactly half way between two integers and the low part is nonzero with the opposite sign. */ if (fabs (hi - xh) == 0.5) { if (xh > 0 && xl < 0) xh = hi - 1; else if (xh < 0 && xl > 0) xh = hi + 1; else xh = hi; } else xh = hi; xl = 0; } else { /* The high part is a nonzero integer. */ lo = __round (xl); if (fabs (lo - xl) == 0.5) { if (xh > 0 && xl < 0) xl = lo + 1; else if (xh < 0 && lo > 0) xl = lo - 1; else xl = lo; } else xl = lo; xh = hi; ldbl_canonicalize_int (&xh, &xl); } } else /* Quiet signaling NaN arguments. */ xh += xh; return ldbl_pack (xh, xl); }
long double __roundl (long double x) { double xh, xl, hi, lo; ldbl_unpack (x, &xh, &xl); /* Return Inf, Nan, +/-0 unchanged. */ if (__builtin_expect (xh != 0.0 && __builtin_isless (__builtin_fabs (xh), __builtin_inf ()), 1)) { double orig_xh; /* Long double arithmetic, including the canonicalisation below, only works in round-to-nearest mode. */ /* Convert the high double to integer. */ orig_xh = xh; hi = ldbl_nearbyint (xh); /* Subtract integral high part from the value. */ xh -= hi; ldbl_canonicalize (&xh, &xl); /* Now convert the low double, adjusted for any remainder from the high double. */ lo = ldbl_nearbyint (xh); /* Adjust the result when the remainder is exactly 0.5. nearbyint rounds values halfway between integers to the nearest even integer. roundl must round away from zero. Also correct cases where nearbyint returns an incorrect value for LO. */ xh -= lo; ldbl_canonicalize (&xh, &xl); if (xh == 0.5) { if (xl > 0.0 || (xl == 0.0 && orig_xh > 0.0)) lo += 1.0; } else if (-xh == 0.5) { if (xl < 0.0 || (xl == 0.0 && orig_xh < 0.0)) lo -= 1.0; } /* Ensure the final value is canonical. In certain cases, rounding causes hi,lo calculated so far to be non-canonical. */ xh = hi; xl = lo; ldbl_canonicalize (&xh, &xl); } return ldbl_pack (xh, xl); }
long double __fabsl(long double x) { uint64_t hx, lx; double xhi, xlo; ldbl_unpack (x, &xhi, &xlo); EXTRACT_WORDS64 (hx, xhi); EXTRACT_WORDS64 (lx, xlo); lx = lx ^ ( hx & 0x8000000000000000LL ); hx = hx & 0x7fffffffffffffffLL; INSERT_WORDS64 (xhi, hx); INSERT_WORDS64 (xlo, lx); x = ldbl_pack (xhi, xlo); return x; }
int ___fpclassifyl (long double x) { u_int64_t hx, lx; int retval = FP_NORMAL; double xhi, xlo; ldbl_unpack (x, &xhi, &xlo); EXTRACT_WORDS64 (hx, xhi); if ((hx & 0x7ff0000000000000ULL) == 0x7ff0000000000000ULL) { /* +/-NaN or +/-Inf */ if (hx & 0x000fffffffffffffULL) { /* +/-NaN */ retval = FP_NAN; } else { retval = FP_INFINITE; } } else { /* +/-zero or +/- normal or +/- denormal */ if (hx & 0x7fffffffffffffffULL) { /* +/- normal or +/- denormal */ if ((hx & 0x7ff0000000000000ULL) > 0x0360000000000000ULL) { /* +/- normal */ retval = FP_NORMAL; } else { if ((hx & 0x7ff0000000000000ULL) == 0x0360000000000000ULL) { EXTRACT_WORDS64 (lx, xlo); if ((lx & 0x7fffffffffffffff) /* lower is non-zero */ && ((lx^hx) & 0x8000000000000000ULL)) { /* and sign differs */ /* +/- denormal */ retval = FP_SUBNORMAL; } else { /* +/- normal */ retval = FP_NORMAL; } } else { /* +/- denormal */ retval = FP_SUBNORMAL; } } } else { /* +/- zero */ retval = FP_ZERO; } } return retval; }
long double __roundevenl (long double x) { double xh, xl, hi; ldbl_unpack (x, &xh, &xl); if (xh != 0 && isfinite (xh)) { hi = __roundeven (xh); if (hi != xh) { /* The high part is not an integer; the low part only affects the result if the high part is exactly half way between two integers and the low part is nonzero in the opposite direction to the rounding of the high part. */ double diff = hi - xh; if (fabs (diff) == 0.5) { if (xl < 0 && diff > 0) xh = hi - 1; else if (xl > 0 && diff < 0) xh = hi + 1; else xh = hi; } else xh = hi; xl = 0; } else { /* The high part is a nonzero integer. Rounding the low part to nearest, ties round to even, is always correct, as a high part that is an odd integer together with a low part with magnitude 0.5 is not a valid long double. */ xl = __roundeven (xl); xh = hi; ldbl_canonicalize_int (&xh, &xl); } } else /* Quiet signaling NaN arguments. */ xh += xh; return ldbl_pack (xh, xl); }
long double __remquol (long double x, long double y, int *quo) { int64_t hx,hy; u_int64_t sx,lx,ly,qs; int cquo; double xhi, xlo, yhi, ylo; ldbl_unpack (x, &xhi, &xlo); EXTRACT_WORDS64 (hx, xhi); EXTRACT_WORDS64 (lx, xlo); ldbl_unpack (y, &yhi, &ylo); EXTRACT_WORDS64 (hy, yhi); EXTRACT_WORDS64 (ly, ylo); sx = hx & 0x8000000000000000ULL; qs = sx ^ (hy & 0x8000000000000000ULL); hy &= 0x7fffffffffffffffLL; hx &= 0x7fffffffffffffffLL; /* Purge off exception values. */ if (hy == 0) return (x * y) / (x * y); /* y = 0 */ if ((hx >= 0x7ff0000000000000LL) /* x not finite */ || (hy > 0x7ff0000000000000LL)) /* y is NaN */ return (x * y) / (x * y); if (hy <= 0x7fbfffffffffffffLL) x = __ieee754_fmodl (x, 8 * y); /* now x < 8y */ if (((hx - hy) | (lx - ly)) == 0) { *quo = qs ? -1 : 1; return zero * x; } x = fabsl (x); y = fabsl (y); cquo = 0; if (hy <= 0x7fcfffffffffffffLL && x >= 4 * y) { x -= 4 * y; cquo += 4; } if (hy <= 0x7fdfffffffffffffLL && x >= 2 * y) { x -= 2 * y; cquo += 2; } if (hy < 0x0020000000000000LL) { if (x + x > y) { x -= y; ++cquo; if (x + x >= y) { x -= y; ++cquo; } } } else { long double y_half = 0.5L * y; if (x > y_half) { x -= y; ++cquo; if (x >= y_half) { x -= y; ++cquo; } } } *quo = qs ? -cquo : cquo; /* Ensure correct sign of zero result in round-downward mode. */ if (x == 0.0L) x = 0.0L; if (sx) x = -x; return x; }
long long __llrintl (long double x) { double xh, xl; long long res, hi, lo; int save_round; ldbl_unpack (x, &xh, &xl); /* Limit the range of values handled by the conversion to long long. We do this because we aren't sure whether that conversion properly raises FE_INVALID. */ if (__builtin_expect ((__builtin_fabs (xh) <= -(double) (-__LONG_LONG_MAX__ - 1)), 1) #if !defined (FE_INVALID) || 1 #endif ) { save_round = fegetround (); if (__glibc_unlikely ((xh == -(double) (-__LONG_LONG_MAX__ - 1)))) { /* When XH is 9223372036854775808.0, converting to long long will overflow, resulting in an invalid operation. However, XL might be negative and of sufficient magnitude that the overall long double is in fact in range. Avoid raising an exception. In any case we need to convert this value specially, because the converted value is not exactly represented as a double thus subtracting HI from XH suffers rounding error. */ hi = __LONG_LONG_MAX__; xh = 1.0; } else { hi = (long long) xh; xh -= hi; } ldbl_canonicalize (&xh, &xl); lo = (long long) xh; /* Peg at max/min values, assuming that the above conversions do so. Strictly speaking, we can return anything for values that overflow, but this is more useful. */ res = hi + lo; /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi). */ if (__glibc_unlikely (((~(hi ^ lo) & (res ^ hi)) < 0))) goto overflow; xh -= lo; ldbl_canonicalize (&xh, &xl); hi = res; switch (save_round) { case FE_TONEAREST: if (fabs (xh) < 0.5 || (fabs (xh) == 0.5 && ((xh > 0.0 && xl < 0.0) || (xh < 0.0 && xl > 0.0) || (xl == 0.0 && (res & 1) == 0)))) return res; if (xh < 0.0) res -= 1; else res += 1; break; case FE_TOWARDZERO: if (res > 0 && (xh < 0.0 || (xh == 0.0 && xl < 0.0))) res -= 1; else if (res < 0 && (xh > 0.0 || (xh == 0.0 && xl > 0.0))) res += 1; return res; break; case FE_UPWARD: if (xh > 0.0 || (xh == 0.0 && xl > 0.0)) res += 1; break; case FE_DOWNWARD: if (xh < 0.0 || (xh == 0.0 && xl < 0.0)) res -= 1; break; } if (__glibc_unlikely (((~(hi ^ (res - hi)) & (res ^ hi)) < 0))) goto overflow; return res; } else { if (xh > 0.0) hi = __LONG_LONG_MAX__; else if (xh < 0.0) hi = -__LONG_LONG_MAX__ - 1; else /* Nan */ hi = 0; } overflow: #ifdef FE_INVALID feraiseexcept (FE_INVALID); #endif return hi; }
long __lroundl (long double x) { double xh, xl; long res, hi, lo; ldbl_unpack (x, &xh, &xl); /* Limit the range of values handled by the conversion to long. We do this because we aren't sure whether that conversion properly raises FE_INVALID. */ if ( #if __LONG_MAX__ == 2147483647 __builtin_expect ((__builtin_fabs (xh) <= (double) __LONG_MAX__ + 2), 1) #else __builtin_expect ((__builtin_fabs (xh) <= -(double) (-__LONG_MAX__ - 1)), 1) #endif #if !defined (FE_INVALID) || 1 #endif ) { #if __LONG_MAX__ == 2147483647 long long llhi = (long long) xh; if (llhi != (long) llhi) hi = llhi < 0 ? -__LONG_MAX__ - 1 : __LONG_MAX__; else hi = llhi; xh -= hi; #else if (__glibc_unlikely ((xh == -(double) (-__LONG_MAX__ - 1)))) { /* When XH is 9223372036854775808.0, converting to long long will overflow, resulting in an invalid operation. However, XL might be negative and of sufficient magnitude that the overall long double is in fact in range. Avoid raising an exception. In any case we need to convert this value specially, because the converted value is not exactly represented as a double thus subtracting HI from XH suffers rounding error. */ hi = __LONG_MAX__; xh = 1.0; } else { hi = (long) xh; xh -= hi; } #endif ldbl_canonicalize (&xh, &xl); lo = (long) xh; /* Peg at max/min values, assuming that the above conversions do so. Strictly speaking, we can return anything for values that overflow, but this is more useful. */ res = hi + lo; /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi). */ if (__glibc_unlikely (((~(hi ^ lo) & (res ^ hi)) < 0))) goto overflow; xh -= lo; ldbl_canonicalize (&xh, &xl); hi = res; if (xh > 0.5) { res += 1; } else if (xh == 0.5) { if (xl > 0.0 || (xl == 0.0 && res >= 0)) res += 1; } else if (-xh > 0.5) { res -= 1; } else if (-xh == 0.5) { if (xl < 0.0 || (xl == 0.0 && res <= 0)) res -= 1; } if (__glibc_unlikely (((~(hi ^ (res - hi)) & (res ^ hi)) < 0))) goto overflow; return res; } else { if (xh > 0.0) hi = __LONG_MAX__; else if (xh < 0.0) hi = -__LONG_MAX__ - 1; else /* Nan */ hi = 0; } overflow: #ifdef FE_INVALID feraiseexcept (FE_INVALID); #endif return hi; }
long double __rintl (long double x) { double xh, xl, hi, lo; ldbl_unpack (x, &xh, &xl); /* Return Inf, Nan, +/-0 unchanged. */ if (__builtin_expect (xh != 0.0 && __builtin_isless (__builtin_fabs (xh), __builtin_inf ()), 1)) { double orig_xh; int save_round = fegetround (); /* Long double arithmetic, including the canonicalisation below, only works in round-to-nearest mode. */ fesetround (FE_TONEAREST); /* Convert the high double to integer. */ orig_xh = xh; hi = ldbl_nearbyint (xh); /* Subtract integral high part from the value. If the low double happens to be exactly 0.5 or -0.5, you might think that this subtraction could result in an incorrect conversion. For instance, subtracting an odd number would cause this function to round in the wrong direction. However, if we have a canonical long double with the low double 0.5 or -0.5, then the high double must be even. */ xh -= hi; ldbl_canonicalize (&xh, &xl); /* Now convert the low double, adjusted for any remainder from the high double. */ lo = ldbl_nearbyint (xh); xh -= lo; ldbl_canonicalize (&xh, &xl); switch (save_round) { case FE_TONEAREST: if (xl > 0.0 && xh == 0.5) lo += 1.0; else if (xl < 0.0 && -xh == 0.5) lo -= 1.0; break; case FE_TOWARDZERO: if (orig_xh < 0.0) goto do_up; /* Fall thru */ case FE_DOWNWARD: if (xh < 0.0 || (xh == 0.0 && xl < 0.0)) lo -= 1.0; break; case FE_UPWARD: do_up: if (xh > 0.0 || (xh == 0.0 && xl > 0.0)) lo += 1.0; break; } /* Ensure the final value is canonical. In certain cases, rounding causes hi,lo calculated so far to be non-canonical. */ xh = hi; xl = lo; ldbl_canonicalize (&xh, &xl); /* Ensure we return -0 rather than +0 when appropriate. */ if (orig_xh < 0.0) xh = -__builtin_fabs (xh); fesetround (save_round); } return ldbl_pack (xh, xl); }
long double __ieee754_hypotl(long double x, long double y) { long double a,b,a1,a2,b1,b2,w,kld; int64_t j,k,ha,hb; double xhi, yhi, hi, lo; xhi = ldbl_high (x); EXTRACT_WORDS64 (ha, xhi); yhi = ldbl_high (y); EXTRACT_WORDS64 (hb, yhi); ha &= 0x7fffffffffffffffLL; hb &= 0x7fffffffffffffffLL; if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;} a = fabsl(a); /* a <- |a| */ b = fabsl(b); /* b <- |b| */ if((ha-hb)>0x0780000000000000LL) {return a+b;} /* x/y > 2**120 */ k=0; kld = 1.0L; if(ha > 0x5f30000000000000LL) { /* a>2**500 */ if(ha >= 0x7ff0000000000000LL) { /* Inf or NaN */ w = a+b; /* for sNaN */ if (issignaling (a) || issignaling (b)) return w; if(ha == 0x7ff0000000000000LL) w = a; if(hb == 0x7ff0000000000000LL) w = b; return w; } /* scale a and b by 2**-600 */ a *= 0x1p-600L; b *= 0x1p-600L; k = 600; kld = 0x1p+600L; } else if(hb < 0x23d0000000000000LL) { /* b < 2**-450 */ if(hb <= 0x000fffffffffffffLL) { /* subnormal b or 0 */ if(hb==0) return a; a *= 0x1p+1022L; b *= 0x1p+1022L; k = -1022; kld = 0x1p-1022L; } else { /* scale a and b by 2^600 */ a *= 0x1p+600L; b *= 0x1p+600L; k = -600; kld = 0x1p-600L; } } /* medium size a and b */ w = a-b; if (w>b) { ldbl_unpack (a, &hi, &lo); a1 = hi; a2 = lo; /* a*a + b*b = (a1+a2)*a + b*b = a1*a + a2*a + b*b = a1*(a1+a2) + a2*a + b*b = a1*a1 + a1*a2 + a2*a + b*b = a1*a1 + a2*(a+a1) + b*b */ w = sqrtl(a1*a1-(b*(-b)-a2*(a+a1))); } else { a = a+a; ldbl_unpack (b, &hi, &lo); b1 = hi; b2 = lo; ldbl_unpack (a, &hi, &lo); a1 = hi; a2 = lo; /* a*a + b*b = a*a + (a-b)*(a-b) - (a-b)*(a-b) + b*b = a*a + w*w - (a*a - 2*a*b + b*b) + b*b = w*w + 2*a*b = w*w + (a1+a2)*b = w*w + a1*b + a2*b = w*w + a1*(b1+b2) + a2*b = w*w + a1*b1 + a1*b2 + a2*b */ w = sqrtl(a1*b1-(w*(-w)-(a1*b2+a2*b))); } if(k!=0) { w *= kld; math_check_force_underflow_nonneg (w); return w; } else return w; }