TEST(math, ilogbl) { ASSERT_EQ(FP_ILOGB0, ilogbl(0.0L)); ASSERT_EQ(FP_ILOGBNAN, ilogbl(nanl(""))); ASSERT_EQ(INT_MAX, ilogbl(HUGE_VALL)); ASSERT_EQ(0L, ilogbl(1.0L)); ASSERT_EQ(3L, ilogbl(10.0L)); }
int main(void) { char buf[128], *end; double d; float f; long double ld; int e, i; printf("1..3\n"); assert(ilogb(0) == FP_ILOGB0); assert(ilogb(NAN) == FP_ILOGBNAN); assert(ilogb(INFINITY) == INT_MAX); for (e = DBL_MIN_EXP - DBL_MANT_DIG; e < DBL_MAX_EXP; e++) { snprintf(buf, sizeof(buf), "0x1.p%d", e); d = strtod(buf, &end); assert(*end == '\0'); i = ilogb(d); assert(i == e); } printf("ok 1 - ilogb\n"); assert(ilogbf(0) == FP_ILOGB0); assert(ilogbf(NAN) == FP_ILOGBNAN); assert(ilogbf(INFINITY) == INT_MAX); for (e = FLT_MIN_EXP - FLT_MANT_DIG; e < FLT_MAX_EXP; e++) { snprintf(buf, sizeof(buf), "0x1.p%d", e); f = strtof(buf, &end); assert(*end == '\0'); i = ilogbf(f); assert(i == e); } printf("ok 2 - ilogbf\n"); assert(ilogbl(0) == FP_ILOGB0); assert(ilogbl(NAN) == FP_ILOGBNAN); assert(ilogbl(INFINITY) == INT_MAX); for (e = LDBL_MIN_EXP - LDBL_MANT_DIG; e < LDBL_MAX_EXP; e++) { snprintf(buf, sizeof(buf), "0x1.p%d", e); ld = strtold(buf, &end); assert(*end == '\0'); i = ilogbl(ld); assert(i == e); } printf("ok 3 - ilogbl\n"); return (0); }
int __rem_pio2l(long double x, long double *y) { long double z, w; double t[3], v[5]; int e0, i, nx, n, sign; sign = signbitl(x); z = fabsl(x); if (z <= pio4) { y[0] = x; y[1] = 0; return (0); } e0 = ilogbl(z) - 23; z = scalbnl(z, -e0); for (i = 0; i < 3; i++) { t[i] = (double)((int)(z)); z = (z - (long double)t[i]) * two24l; } nx = 3; while (t[nx-1] == 0.0) nx--; /* omit trailing zeros */ n = __rem_pio2m(t, v, e0, nx, 2, _TBL_ipio2l_inf); z = (long double)v[1]; w = (long double)v[0]; y[0] = z + w; y[1] = z - (y[0] - w); if (sign == 1) { y[0] = -y[0]; y[1] = -y[1]; return (-n); } return (n); }
long double tanl(long double x) { union IEEEl2bits z; int i, e0, s; double xd[NX], yd[PREC]; long double hi, lo; z.e = x; s = z.bits.sign; z.bits.sign = 0; /* If x = +-0 or x is subnormal, then tan(x) = x. */ if (z.bits.exp == 0) return (x); /* If x = NaN or Inf, then tan(x) = NaN. */ if (z.bits.exp == 32767) return ((x - x) / (x - x)); /* Optimize the case where x is already within range. */ if (z.e < M_PI_4) { hi = __kernel_tanl(z.e, 0, 0); return (s ? -hi : hi); } /* Split z.e into a 24-bit representation. */ e0 = ilogbl(z.e) - 23; z.e = scalbnl(z.e, -e0); for (i = 0; i < NX; i++) { xd[i] = (double)((int32_t)z.e); z.e = (z.e - xd[i]) * two24; } /* yd contains the pieces of xd rem pi/2 such that |yd| < pi/4. */ e0 = __kernel_rem_pio2(xd, yd, e0, NX, PREC); #if PREC == 2 hi = (long double)yd[0] + yd[1]; lo = yd[1] - (hi - yd[0]); #else /* PREC == 3 */ long double t; t = (long double)yd[2] + yd[1]; hi = t + yd[0]; lo = yd[0] - (hi - t); #endif switch (e0 & 3) { case 0: case 2: hi = __kernel_tanl(hi, lo, 0); break; case 1: case 3: hi = __kernel_tanl(hi, lo, 1); break; } return (s ? -hi : hi); }
long double cbrtl(long double x) { long double s, t, r, w, y; double dx, dy; int *py = (int *) &dy; int n, m, m3, sx; if (!finitel(x)) return (x + x); if (iszerol(x)) return (x); sx = signbitl(x); x = fabsl(x); n = ilogbl(x); m = n / 3; m3 = m + m + m; y = scalbnl(x, -m3); dx = (double) y; dy = cbrt(dx); py[1 - n0] += 2; if (py[1 - n0] == 0) py[n0] += 1; /* one step newton iteration to 113 bits with error < 0.667ulps */ t = (long double) dy; t = scalbnl(t, m); s = t * t; r = x / s; w = t + t; r = (r - t) / (w + r); t += t * r; return (sx == 0 ? t : -t); }
long double log10l(long double x) { long double y, z; enum fp_direction_type rd; int n; if (!finitel(x)) return (x + fabsl(x)); /* x is +-INF or NaN */ else if (x > zero) { n = ilogbl(x); if (n < 0) n += 1; rd = __swapRD(fp_nearest); y = n; x = scalbnl(x, -n); z = y * log10_2lo + ivln10 * logl(x); z += y * log10_2hi; if (rd != fp_nearest) (void) __swapRD(rd); return (z); } else if (x == zero) /* -INF */ return (-one / zero); else /* x <0 , return NaN */ return (zero / zero); }
void test_ilogb() { static_assert((std::is_same<decltype(ilogb((double)0)), int>::value), ""); static_assert((std::is_same<decltype(ilogbf(0)), int>::value), ""); static_assert((std::is_same<decltype(ilogbl(0)), int>::value), ""); assert(ilogb(1) == 0); }
long double logbl(long double x) { int i = ilogbl(x); if (i == FP_ILOGB0) return -1.0/fabsl(x); if (i == FP_ILOGBNAN || i == INT_MAX) return x * x; return i; }
ATF_TC_BODY(ilogb, tc) { ATF_CHECK(ilogbf(0) == FP_ILOGB0); ATF_CHECK_RAISED_INVALID; ATF_CHECK(ilogb(0) == FP_ILOGB0); ATF_CHECK_RAISED_INVALID; #ifdef __HAVE_LONG_DOUBLE ATF_CHECK(ilogbl(0) == FP_ILOGB0); ATF_CHECK_RAISED_INVALID; #endif ATF_CHECK(ilogbf(-0) == FP_ILOGB0); ATF_CHECK_RAISED_INVALID; ATF_CHECK(ilogb(-0) == FP_ILOGB0); ATF_CHECK_RAISED_INVALID; #ifdef __HAVE_LONG_DOUBLE ATF_CHECK(ilogbl(-0) == FP_ILOGB0); ATF_CHECK_RAISED_INVALID; #endif ATF_CHECK(ilogbf(INFINITY) == INT_MAX); ATF_CHECK_RAISED_INVALID; ATF_CHECK(ilogb(INFINITY) == INT_MAX); ATF_CHECK_RAISED_INVALID; #ifdef __HAVE_LONG_DOUBLE ATF_CHECK(ilogbl(INFINITY) == INT_MAX); ATF_CHECK_RAISED_INVALID; #endif ATF_CHECK(ilogbf(-INFINITY) == INT_MAX); ATF_CHECK_RAISED_INVALID; ATF_CHECK(ilogb(-INFINITY) == INT_MAX); ATF_CHECK_RAISED_INVALID; #ifdef __HAVE_LONG_DOUBLE ATF_CHECK(ilogbl(-INFINITY) == INT_MAX); ATF_CHECK_RAISED_INVALID; #endif ATF_CHECK(ilogbf(1024) == 10); ATF_CHECK_RAISED_NOTHING; ATF_CHECK(ilogb(1024) == 10); ATF_CHECK_RAISED_NOTHING; #ifdef __HAVE_LONG_DOUBLE ATF_CHECK(ilogbl(1024) == 10); ATF_CHECK_RAISED_NOTHING; #endif #ifndef __vax__ ATF_CHECK(ilogbf(NAN) == FP_ILOGBNAN); ATF_CHECK_RAISED_INVALID; ATF_CHECK(ilogb(NAN) == FP_ILOGBNAN); ATF_CHECK_RAISED_INVALID; #ifdef __HAVE_LONG_DOUBLE ATF_CHECK(ilogbl(NAN) == FP_ILOGBNAN); ATF_CHECK_RAISED_INVALID; #endif #endif }
int ilogbl(long double x) { PRAGMA_STDC_FENV_ACCESS_ON union ldshape u = {x}; int e = u.i.se & 0x7fff; if (!e) { if (x == 0) { FORCE_EVAL(0 / 0.0f); return FP_ILOGB0; } /* subnormal x */ x *= 0x1p120; return ilogbl(x) - 120; } if (e == 0x7fff) { FORCE_EVAL(0 / 0.0f); u.i.se = 0; return u.f ? FP_ILOGBNAN : INT_MAX; } return e - 0x3fff; }
long double atan2l(long double y, long double x) { long double t, z; int k, m, signy, signx; if (x != x || y != y) return (x + y); /* return NaN if x or y is NAN */ signy = signbitl(y); signx = signbitl(x); if (x == one) return (atanl(y)); m = signy + signx + signx; /* when y = 0 */ if (y == zero) switch (m) { case 0: return (y); /* atan(+0,+anything) */ case 1: return (y); /* atan(-0,+anything) */ case 2: return (PI + tiny); /* atan(+0,-anything) */ case 3: return (-PI - tiny); /* atan(-0,-anything) */ } /* when x = 0 */ if (x == zero) return (signy == 1 ? -PIo2 - tiny : PIo2 + tiny); /* when x is INF */ if (!finitel(x)) if (!finitel(y)) { switch (m) { case 0: return (PIo4 + tiny); /* atan(+INF,+INF) */ case 1: return (-PIo4 - tiny); /* atan(-INF,+INF) */ case 2: return (PI3o4 + tiny); /* atan(+INF,-INF) */ case 3: return (-PI3o4 - tiny); /* atan(-INF,-INF) */ } } else { switch (m) { case 0: return (zero); /* atan(+...,+INF) */ case 1: return (-zero); /* atan(-...,+INF) */ case 2: return (PI + tiny); /* atan(+...,-INF) */ case 3: return (-PI - tiny); /* atan(-...,-INF) */ } } /* when y is INF */ if (!finitel(y)) return (signy == 1 ? -PIo2 - tiny : PIo2 + tiny); /* compute y/x */ x = fabsl(x); y = fabsl(y); t = PI_lo; k = (ilogbl(y) - ilogbl(x)); if (k > 120) z = PIo2 + half * t; else if (m > 1 && k < -120) z = zero; else z = atanl(y / x); switch (m) { case 0: return (z); /* atan(+,+) */ case 1: return (-z); /* atan(-,+) */ case 2: return (PI - (z - t)); /* atan(+,-) */ case 3: return ((z - t) - PI); /* atan(-,-) */ } /* NOTREACHED */ }
void domathl (void) { #ifndef NO_LONG_DOUBLE long double f1; long double f2; int i1; f1 = acosl(0.0); fprintf( stdout, "acosl : %Lf\n", f1); f1 = acoshl(0.0); fprintf( stdout, "acoshl : %Lf\n", f1); f1 = asinl(1.0); fprintf( stdout, "asinl : %Lf\n", f1); f1 = asinhl(1.0); fprintf( stdout, "asinhl : %Lf\n", f1); f1 = atanl(M_PI_4); fprintf( stdout, "atanl : %Lf\n", f1); f1 = atan2l(2.3, 2.3); fprintf( stdout, "atan2l : %Lf\n", f1); f1 = atanhl(1.0); fprintf( stdout, "atanhl : %Lf\n", f1); f1 = cbrtl(27.0); fprintf( stdout, "cbrtl : %Lf\n", f1); f1 = ceill(3.5); fprintf( stdout, "ceill : %Lf\n", f1); f1 = copysignl(3.5, -2.5); fprintf( stdout, "copysignl : %Lf\n", f1); f1 = cosl(M_PI_2); fprintf( stdout, "cosl : %Lf\n", f1); f1 = coshl(M_PI_2); fprintf( stdout, "coshl : %Lf\n", f1); f1 = erfl(42.0); fprintf( stdout, "erfl : %Lf\n", f1); f1 = erfcl(42.0); fprintf( stdout, "erfcl : %Lf\n", f1); f1 = expl(0.42); fprintf( stdout, "expl : %Lf\n", f1); f1 = exp2l(0.42); fprintf( stdout, "exp2l : %Lf\n", f1); f1 = expm1l(0.00042); fprintf( stdout, "expm1l : %Lf\n", f1); f1 = fabsl(-1.123); fprintf( stdout, "fabsl : %Lf\n", f1); f1 = fdiml(1.123, 2.123); fprintf( stdout, "fdiml : %Lf\n", f1); f1 = floorl(0.5); fprintf( stdout, "floorl : %Lf\n", f1); f1 = floorl(-0.5); fprintf( stdout, "floorl : %Lf\n", f1); f1 = fmal(2.1, 2.2, 3.01); fprintf( stdout, "fmal : %Lf\n", f1); f1 = fmaxl(-0.42, 0.42); fprintf( stdout, "fmaxl : %Lf\n", f1); f1 = fminl(-0.42, 0.42); fprintf( stdout, "fminl : %Lf\n", f1); f1 = fmodl(42.0, 3.0); fprintf( stdout, "fmodl : %Lf\n", f1); /* no type-specific variant */ i1 = fpclassify(1.0); fprintf( stdout, "fpclassify : %d\n", i1); f1 = frexpl(42.0, &i1); fprintf( stdout, "frexpl : %Lf\n", f1); f1 = hypotl(42.0, 42.0); fprintf( stdout, "hypotl : %Lf\n", f1); i1 = ilogbl(42.0); fprintf( stdout, "ilogbl : %d\n", i1); /* no type-specific variant */ i1 = isfinite(3.0); fprintf( stdout, "isfinite : %d\n", i1); /* no type-specific variant */ i1 = isgreater(3.0, 3.1); fprintf( stdout, "isgreater : %d\n", i1); /* no type-specific variant */ i1 = isgreaterequal(3.0, 3.1); fprintf( stdout, "isgreaterequal : %d\n", i1); /* no type-specific variant */ i1 = isinf(3.0); fprintf( stdout, "isinf : %d\n", i1); /* no type-specific variant */ i1 = isless(3.0, 3.1); fprintf( stdout, "isless : %d\n", i1); /* no type-specific variant */ i1 = islessequal(3.0, 3.1); fprintf( stdout, "islessequal : %d\n", i1); /* no type-specific variant */ i1 = islessgreater(3.0, 3.1); fprintf( stdout, "islessgreater : %d\n", i1); /* no type-specific variant */ i1 = isnan(0.0); fprintf( stdout, "isnan : %d\n", i1); /* no type-specific variant */ i1 = isnormal(3.0); fprintf( stdout, "isnormal : %d\n", i1); /* no type-specific variant */ f1 = isunordered(1.0, 2.0); fprintf( stdout, "isunordered : %d\n", i1); f1 = j0l(1.2); fprintf( stdout, "j0l : %Lf\n", f1); f1 = j1l(1.2); fprintf( stdout, "j1l : %Lf\n", f1); f1 = jnl(2,1.2); fprintf( stdout, "jnl : %Lf\n", f1); f1 = ldexpl(1.2,3); fprintf( stdout, "ldexpl : %Lf\n", f1); f1 = lgammal(42.0); fprintf( stdout, "lgammal : %Lf\n", f1); f1 = llrintl(-0.5); fprintf( stdout, "llrintl : %Lf\n", f1); f1 = llrintl(0.5); fprintf( stdout, "llrintl : %Lf\n", f1); f1 = llroundl(-0.5); fprintf( stdout, "lroundl : %Lf\n", f1); f1 = llroundl(0.5); fprintf( stdout, "lroundl : %Lf\n", f1); f1 = logl(42.0); fprintf( stdout, "logl : %Lf\n", f1); f1 = log10l(42.0); fprintf( stdout, "log10l : %Lf\n", f1); f1 = log1pl(42.0); fprintf( stdout, "log1pl : %Lf\n", f1); f1 = log2l(42.0); fprintf( stdout, "log2l : %Lf\n", f1); f1 = logbl(42.0); fprintf( stdout, "logbl : %Lf\n", f1); f1 = lrintl(-0.5); fprintf( stdout, "lrintl : %Lf\n", f1); f1 = lrintl(0.5); fprintf( stdout, "lrintl : %Lf\n", f1); f1 = lroundl(-0.5); fprintf( stdout, "lroundl : %Lf\n", f1); f1 = lroundl(0.5); fprintf( stdout, "lroundl : %Lf\n", f1); f1 = modfl(42.0,&f2); fprintf( stdout, "lmodfl : %Lf\n", f1); f1 = nanl(""); fprintf( stdout, "nanl : %Lf\n", f1); f1 = nearbyintl(1.5); fprintf( stdout, "nearbyintl : %Lf\n", f1); f1 = nextafterl(1.5,2.0); fprintf( stdout, "nextafterl : %Lf\n", f1); f1 = powl(3.01, 2.0); fprintf( stdout, "powl : %Lf\n", f1); f1 = remainderl(3.01,2.0); fprintf( stdout, "remainderl : %Lf\n", f1); f1 = remquol(29.0,3.0,&i1); fprintf( stdout, "remquol : %Lf\n", f1); f1 = rintl(0.5); fprintf( stdout, "rintl : %Lf\n", f1); f1 = rintl(-0.5); fprintf( stdout, "rintl : %Lf\n", f1); f1 = roundl(0.5); fprintf( stdout, "roundl : %Lf\n", f1); f1 = roundl(-0.5); fprintf( stdout, "roundl : %Lf\n", f1); f1 = scalblnl(1.2,3); fprintf( stdout, "scalblnl : %Lf\n", f1); f1 = scalbnl(1.2,3); fprintf( stdout, "scalbnl : %Lf\n", f1); /* no type-specific variant */ i1 = signbit(1.0); fprintf( stdout, "signbit : %i\n", i1); f1 = sinl(M_PI_4); fprintf( stdout, "sinl : %Lf\n", f1); f1 = sinhl(M_PI_4); fprintf( stdout, "sinhl : %Lf\n", f1); f1 = sqrtl(9.0); fprintf( stdout, "sqrtl : %Lf\n", f1); f1 = tanl(M_PI_4); fprintf( stdout, "tanl : %Lf\n", f1); f1 = tanhl(M_PI_4); fprintf( stdout, "tanhl : %Lf\n", f1); f1 = tgammal(2.1); fprintf( stdout, "tgammal : %Lf\n", f1); f1 = truncl(3.5); fprintf( stdout, "truncl : %Lf\n", f1); f1 = y0l(1.2); fprintf( stdout, "y0l : %Lf\n", f1); f1 = y1l(1.2); fprintf( stdout, "y1l : %Lf\n", f1); f1 = ynl(3,1.2); fprintf( stdout, "ynl : %Lf\n", f1); #endif }
/* * Fused multiply-add: Compute x * y + z with a single rounding error. * * We use scaling to avoid overflow/underflow, along with the * canonical precision-doubling technique adapted from: * * Dekker, T. A Floating-Point Technique for Extending the * Available Precision. Numer. Math. 18, 224-242 (1971). */ long double fmal(long double x, long double y, long double z) { long double xs, ys, zs, adj; struct dd xy, r; int oround; int ex, ey, ez; int spread; /* * Handle special cases. The order of operations and the particular * return values here are crucial in handling special cases involving * infinities, NaNs, overflows, and signed zeroes correctly. */ if (x == 0.0 || y == 0.0) return (x * y + z); if (z == 0.0) return (x * y); if (!isfinite(x) || !isfinite(y)) return (x * y + z); if (!isfinite(z)) return (z); xs = frexpl(x, &ex); ys = frexpl(y, &ey); zs = frexpl(z, &ez); oround = fegetround(); spread = ex + ey - ez; /* * If x * y and z are many orders of magnitude apart, the scaling * will overflow, so we handle these cases specially. Rounding * modes other than FE_TONEAREST are painful. */ if (spread < -LDBL_MANT_DIG) { feraiseexcept(FE_INEXACT); if (!isnormal(z)) feraiseexcept(FE_UNDERFLOW); switch (oround) { case FE_TONEAREST: return (z); case FE_TOWARDZERO: if (x > 0.0 ^ y < 0.0 ^ z < 0.0) return (z); else return (nextafterl(z, 0)); case FE_DOWNWARD: if (x > 0.0 ^ y < 0.0) return (z); else return (nextafterl(z, -INFINITY)); default: /* FE_UPWARD */ if (x > 0.0 ^ y < 0.0) return (nextafterl(z, INFINITY)); else return (z); } } if (spread <= LDBL_MANT_DIG * 2) zs = ldexpl(zs, -spread); else zs = copysignl(LDBL_MIN, zs); fesetround(FE_TONEAREST); /* work around clang bug 8100 */ volatile long double vxs = xs; /* * Basic approach for round-to-nearest: * * (xy.hi, xy.lo) = x * y (exact) * (r.hi, r.lo) = xy.hi + z (exact) * adj = xy.lo + r.lo (inexact; low bit is sticky) * result = r.hi + adj (correctly rounded) */ xy = dd_mul(vxs, ys); r = dd_add(xy.hi, zs); spread = ex + ey; if (r.hi == 0.0) { /* * When the addends cancel to 0, ensure that the result has * the correct sign. */ fesetround(oround); volatile long double vzs = zs; /* XXX gcc CSE bug workaround */ return (xy.hi + vzs + ldexpl(xy.lo, spread)); } if (oround != FE_TONEAREST) { /* * There is no need to worry about double rounding in directed * rounding modes. */ fesetround(oround); /* work around clang bug 8100 */ volatile long double vrlo = r.lo; adj = vrlo + xy.lo; return (ldexpl(r.hi + adj, spread)); } adj = add_adjusted(r.lo, xy.lo); if (spread + ilogbl(r.hi) > -16383) return (ldexpl(r.hi + adj, spread)); else return (add_and_denormalize(r.hi, adj, spread)); }
/* * Fused multiply-add: Compute x * y + z with a single rounding error. * * We use scaling to avoid overflow/underflow, along with the * canonical precision-doubling technique adapted from: * * Dekker, T. A Floating-Point Technique for Extending the * Available Precision. Numer. Math. 18, 224-242 (1971). */ long double fmal(long double x, long double y, long double z) { #if LDBL_MANT_DIG == 64 static const long double split = 0x1p32L + 1.0; #elif LDBL_MANT_DIG == 113 static const long double split = 0x1p57L + 1.0; #endif long double xs, ys, zs; long double c, cc, hx, hy, p, q, tx, ty; long double r, rr, s; int oround; int ex, ey, ez; int spread; if (z == 0.0) return (x * y); if (x == 0.0 || y == 0.0) return (x * y + z); /* Results of frexp() are undefined for these cases. */ if (!isfinite(x) || !isfinite(y) || !isfinite(z)) return (x * y + z); xs = frexpl(x, &ex); ys = frexpl(y, &ey); zs = frexpl(z, &ez); oround = fegetround(); spread = ex + ey - ez; /* * If x * y and z are many orders of magnitude apart, the scaling * will overflow, so we handle these cases specially. Rounding * modes other than FE_TONEAREST are painful. */ if (spread > LDBL_MANT_DIG * 2) { fenv_t env; feraiseexcept(FE_INEXACT); switch(oround) { case FE_TONEAREST: return (x * y); case FE_TOWARDZERO: if (x > 0.0 ^ y < 0.0 ^ z < 0.0) return (x * y); feholdexcept(&env); r = x * y; if (!fetestexcept(FE_INEXACT)) r = nextafterl(r, 0); feupdateenv(&env); return (r); case FE_DOWNWARD: if (z > 0.0) return (x * y); feholdexcept(&env); r = x * y; if (!fetestexcept(FE_INEXACT)) r = nextafterl(r, -INFINITY); feupdateenv(&env); return (r); default: /* FE_UPWARD */ if (z < 0.0) return (x * y); feholdexcept(&env); r = x * y; if (!fetestexcept(FE_INEXACT)) r = nextafterl(r, INFINITY); feupdateenv(&env); return (r); } } if (spread < -LDBL_MANT_DIG) { feraiseexcept(FE_INEXACT); if (!isnormal(z)) feraiseexcept(FE_UNDERFLOW); switch (oround) { case FE_TONEAREST: return (z); case FE_TOWARDZERO: if (x > 0.0 ^ y < 0.0 ^ z < 0.0) return (z); else return (nextafterl(z, 0)); case FE_DOWNWARD: if (x > 0.0 ^ y < 0.0) return (z); else return (nextafterl(z, -INFINITY)); default: /* FE_UPWARD */ if (x > 0.0 ^ y < 0.0) return (nextafterl(z, INFINITY)); else return (z); } } /* * Use Dekker's algorithm to perform the multiplication and * subsequent addition in twice the machine precision. * Arrange so that x * y = c + cc, and x * y + z = r + rr. */ fesetround(FE_TONEAREST); p = xs * split; hx = xs - p; hx += p; tx = xs - hx; p = ys * split; hy = ys - p; hy += p; ty = ys - hy; p = hx * hy; q = hx * ty + tx * hy; c = p + q; cc = p - c + q + tx * ty; zs = ldexpl(zs, -spread); r = c + zs; s = r - c; rr = (c - (r - s)) + (zs - s) + cc; spread = ex + ey; if (spread + ilogbl(r) > -16383) { fesetround(oround); r = r + rr; } else { /* * The result is subnormal, so we round before scaling to * avoid double rounding. */ p = ldexpl(copysignl(0x1p-16382L, r), -spread); c = r + p; s = c - r; cc = (r - (c - s)) + (p - s) + rr; fesetround(oround); r = (c + cc) - p; } return (ldexpl(r, spread)); }
static int testl(long double long_double_x, int int_x, long long_x) { int r = 0; r += __finitel(long_double_x); r += __fpclassifyl(long_double_x); r += __isinfl(long_double_x); r += __isnanl(long_double_x); r += __signbitl(long_double_x); r += acoshl(long_double_x); r += acosl(long_double_x); r += asinhl(long_double_x); r += asinl(long_double_x); r += atan2l(long_double_x, long_double_x); r += atanhl(long_double_x); r += atanl(long_double_x); r += cbrtl(long_double_x); r += ceill(long_double_x); r += copysignl(long_double_x, long_double_x); r += coshl(long_double_x); r += cosl(long_double_x); r += erfcl(long_double_x); r += erfl(long_double_x); r += exp2l(long_double_x); r += expl(long_double_x); r += expm1l(long_double_x); r += fabsl(long_double_x); r += fdiml(long_double_x, long_double_x); r += floorl(long_double_x); r += fmal(long_double_x, long_double_x, long_double_x); r += fmaxl(long_double_x, long_double_x); r += fminl(long_double_x, long_double_x); r += fmodl(long_double_x, long_double_x); r += frexpl(long_double_x, &int_x); r += hypotl(long_double_x, long_double_x); r += ilogbl(long_double_x); r += ldexpl(long_double_x, int_x); r += lgammal(long_double_x); r += llrintl(long_double_x); r += llroundl(long_double_x); r += log10l(long_double_x); r += log1pl(long_double_x); r += log2l(long_double_x); r += logbl(long_double_x); r += logl(long_double_x); r += lrintl(long_double_x); r += lroundl(long_double_x); r += modfl(long_double_x, &long_double_x); r += nearbyintl(long_double_x); r += nextafterl(long_double_x, long_double_x); r += nexttowardl(long_double_x, long_double_x); r += powl(long_double_x, long_double_x); r += remainderl(long_double_x, long_double_x); r += remquol(long_double_x, long_double_x, &int_x); r += rintl(long_double_x); r += roundl(long_double_x); r += scalblnl(long_double_x, long_x); r += scalbnl(long_double_x, int_x); r += sinhl(long_double_x); r += sinl(long_double_x); r += sqrtl(long_double_x); r += tanhl(long_double_x); r += tanl(long_double_x); r += tgammal(long_double_x); r += truncl(long_double_x); return r; }
/* * Fused multiply-add: Compute x * y + z with a single rounding error. * * We use scaling to avoid overflow/underflow, along with the * canonical precision-doubling technique adapted from: * * Dekker, T. A Floating-Point Technique for Extending the * Available Precision. Numer. Math. 18, 224-242 (1971). */ long double fmal(long double x, long double y, long double z) { #pragma STDC FENV_ACCESS ON long double xs, ys, zs, adj; struct dd xy, r; int oround; int ex, ey, ez; int spread; /* * Handle special cases. The order of operations and the particular * return values here are crucial in handling special cases involving * infinities, NaNs, overflows, and signed zeroes correctly. */ if (!isfinite(x) || !isfinite(y)) return (x * y + z); if (!isfinite(z)) return (z); if (x == 0.0 || y == 0.0) return (x * y + z); if (z == 0.0) return (x * y); xs = frexpl(x, &ex); ys = frexpl(y, &ey); zs = frexpl(z, &ez); oround = fegetround(); spread = ex + ey - ez; /* * If x * y and z are many orders of magnitude apart, the scaling * will overflow, so we handle these cases specially. Rounding * modes other than FE_TONEAREST are painful. */ if (spread < -LDBL_MANT_DIG) { #ifdef FE_INEXACT feraiseexcept(FE_INEXACT); #endif #ifdef FE_UNDERFLOW if (!isnormal(z)) feraiseexcept(FE_UNDERFLOW); #endif switch (oround) { default: /* FE_TONEAREST */ return (z); #ifdef FE_TOWARDZERO case FE_TOWARDZERO: if (x > 0.0 ^ y < 0.0 ^ z < 0.0) return (z); else return (nextafterl(z, 0)); #endif #ifdef FE_DOWNWARD case FE_DOWNWARD: if (x > 0.0 ^ y < 0.0) return (z); else return (nextafterl(z, -INFINITY)); #endif #ifdef FE_UPWARD case FE_UPWARD: if (x > 0.0 ^ y < 0.0) return (nextafterl(z, INFINITY)); else return (z); #endif } } if (spread <= LDBL_MANT_DIG * 2) zs = scalbnl(zs, -spread); else zs = copysignl(LDBL_MIN, zs); fesetround(FE_TONEAREST); /* * Basic approach for round-to-nearest: * * (xy.hi, xy.lo) = x * y (exact) * (r.hi, r.lo) = xy.hi + z (exact) * adj = xy.lo + r.lo (inexact; low bit is sticky) * result = r.hi + adj (correctly rounded) */ xy = dd_mul(xs, ys); r = dd_add(xy.hi, zs); spread = ex + ey; if (r.hi == 0.0) { /* * When the addends cancel to 0, ensure that the result has * the correct sign. */ fesetround(oround); volatile long double vzs = zs; /* XXX gcc CSE bug workaround */ return xy.hi + vzs + scalbnl(xy.lo, spread); } if (oround != FE_TONEAREST) { /* * There is no need to worry about double rounding in directed * rounding modes. * But underflow may not be raised correctly, example in downward rounding: * fmal(0x1.0000000001p-16000L, 0x1.0000000001p-400L, -0x1p-16440L) */ long double ret; #if defined(FE_INEXACT) && defined(FE_UNDERFLOW) int e = fetestexcept(FE_INEXACT); feclearexcept(FE_INEXACT); #endif fesetround(oround); adj = r.lo + xy.lo; ret = scalbnl(r.hi + adj, spread); #if defined(FE_INEXACT) && defined(FE_UNDERFLOW) if (ilogbl(ret) < -16382 && fetestexcept(FE_INEXACT)) feraiseexcept(FE_UNDERFLOW); else if (e) feraiseexcept(FE_INEXACT); #endif return ret; } adj = add_adjusted(r.lo, xy.lo); if (spread + ilogbl(r.hi) > -16383) return scalbnl(r.hi + adj, spread); else return add_and_denormalize(r.hi, adj, spread); }