示例#1
0
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));
}
示例#2
0
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);
}
示例#3
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);
}
示例#4
0
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);
}
示例#5
0
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);
}
示例#6
0
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);
}
示例#7
0
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);
}
示例#8
0
文件: logbl.c 项目: GregorR/musl
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;
}
示例#9
0
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
}
示例#10
0
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;
}
示例#11
0
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 */
}
示例#12
0
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
}
示例#13
0
/*
 * 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));
}
示例#14
0
/*
 * 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));
}
示例#15
0
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;
}
示例#16
0
文件: fmal.c 项目: 4ian/emscripten
/*
 * 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);
}