diff options
Diffstat (limited to 'src/math')
-rw-r--r-- | src/math/__signbit.c | 2 | ||||
-rw-r--r-- | src/math/__signbitf.c | 2 | ||||
-rw-r--r-- | src/math/cbrtl.c | 33 | ||||
-rw-r--r-- | src/math/nearbyint.c | 23 | ||||
-rw-r--r-- | src/math/nearbyintf.c | 14 | ||||
-rw-r--r-- | src/math/nearbyintl.c | 11 | ||||
-rw-r--r-- | src/math/pow.c | 65 | ||||
-rw-r--r-- | src/math/powf.c | 35 | ||||
-rw-r--r-- | src/math/powl.c | 139 | ||||
-rw-r--r-- | src/math/remquo.c | 1 |
10 files changed, 127 insertions, 198 deletions
diff --git a/src/math/__signbit.c b/src/math/__signbit.c index ffe717ce..e700b6b7 100644 --- a/src/math/__signbit.c +++ b/src/math/__signbit.c @@ -1,6 +1,6 @@ #include "libm.h" -// FIXME: macro +// FIXME: macro in math.h int __signbit(double x) { union { diff --git a/src/math/__signbitf.c b/src/math/__signbitf.c index ff3e81ff..40ad3cfd 100644 --- a/src/math/__signbitf.c +++ b/src/math/__signbitf.c @@ -1,6 +1,6 @@ #include "libm.h" -// FIXME +// FIXME: macro in math.h int __signbitf(float x) { union { diff --git a/src/math/cbrtl.c b/src/math/cbrtl.c index 5297d68f..0af65ef5 100644 --- a/src/math/cbrtl.c +++ b/src/math/cbrtl.c @@ -23,9 +23,9 @@ long double cbrtl(long double x) return cbrt(x); } #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 -#define BIAS (LDBL_MAX_EXP - 1) -static const unsigned -B1 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ + +#define BIAS (LDBL_MAX_EXP - 1) +static const unsigned B1 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ long double cbrtl(long double x) { @@ -48,25 +48,10 @@ long double cbrtl(long double x) if (k == BIAS + LDBL_MAX_EXP) return x + x; -// FIXME: extended precision is default on linux.. -#undef __i386__ -#ifdef __i386__ - fp_prec_t oprec; - - oprec = fpgetprec(); - if (oprec != FP_PE) - fpsetprec(FP_PE); -#endif - if (k == 0) { /* If x = +-0, then cbrt(x) = +-0. */ - if ((u.bits.manh | u.bits.manl) == 0) { -#ifdef __i386__ - if (oprec != FP_PE) - fpsetprec(oprec); -#endif - return (x); - } + if ((u.bits.manh | u.bits.manl) == 0) + return x; /* Adjust subnormal numbers. */ u.e *= 0x1.0p514; k = u.bits.exp; @@ -118,7 +103,7 @@ long double cbrtl(long double x) * Round it away from zero to 32 bits (32 so that t*t is exact, and * away from zero for technical reasons). */ - t = dt + (0x1.0p32L + 0x1.0p-32L) - 0x1.0p32; + t = dt + (0x1.0p32L + 0x1.0p-31L) - 0x1.0p32; #elif LDBL_MANT_DIG == 113 /* * Round dt away from zero to 47 bits. Since we don't trust the 47, @@ -129,8 +114,6 @@ long double cbrtl(long double x) * dt is much more accurate than needed. */ t = dt + 0x2.0p-46 + 0x1.0p60L - 0x1.0p60; -#else -#error "Unsupported long double format" #endif /* @@ -144,10 +127,6 @@ long double cbrtl(long double x) t = t+t*r; /* error <= 0.5 + 0.5/3 + epsilon */ t *= v.e; -#ifdef __i386__ - if (oprec != FP_PE) - fpsetprec(oprec); -#endif return t; } #endif diff --git a/src/math/nearbyint.c b/src/math/nearbyint.c index 714c55ca..7a4c58cf 100644 --- a/src/math/nearbyint.c +++ b/src/math/nearbyint.c @@ -1,20 +1,19 @@ #include <fenv.h> #include <math.h> -/* -rint may raise inexact (and it should not alter the fenv otherwise) -nearbyint must not raise inexact +/* nearbyint is the same as rint, but it must not raise the inexact exception */ -(according to ieee754r section 7.9 both functions should raise invalid -when the input is signaling nan, but c99 does not define snan so saving -and restoring the entire fenv should be fine) -*/ +double nearbyint(double x) +{ +#ifdef FE_INEXACT + int e; -double nearbyint(double x) { - fenv_t e; - - fegetenv(&e); + e = fetestexcept(FE_INEXACT); +#endif x = rint(x); - fesetenv(&e); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif return x; } diff --git a/src/math/nearbyintf.c b/src/math/nearbyintf.c index 07df8f54..39c3d73b 100644 --- a/src/math/nearbyintf.c +++ b/src/math/nearbyintf.c @@ -1,11 +1,17 @@ #include <fenv.h> #include <math.h> -float nearbyintf(float x) { - fenv_t e; +float nearbyintf(float x) +{ +#ifdef FE_INEXACT + int e; - fegetenv(&e); + e = fetestexcept(FE_INEXACT); +#endif x = rintf(x); - fesetenv(&e); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif return x; } diff --git a/src/math/nearbyintl.c b/src/math/nearbyintl.c index 2906f383..0ff4b1f9 100644 --- a/src/math/nearbyintl.c +++ b/src/math/nearbyintl.c @@ -10,11 +10,16 @@ long double nearbyintl(long double x) #include <fenv.h> long double nearbyintl(long double x) { - fenv_t e; +#ifdef FE_INEXACT + int e; - fegetenv(&e); + e = fetestexcept(FE_INEXACT); +#endif x = rintl(x); - fesetenv(&e); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif return x; } #endif diff --git a/src/math/pow.c b/src/math/pow.c index 052825a6..f257814e 100644 --- a/src/math/pow.c +++ b/src/math/pow.c @@ -21,24 +21,28 @@ * * Special cases: * 1. (anything) ** 0 is 1 - * 2. (anything) ** 1 is itself - * 3. (anything except 1) ** NAN is NAN, 1 ** NAN is 1 + * 2. 1 ** (anything) is 1 + * 3. (anything except 1) ** NAN is NAN * 4. NAN ** (anything except 0) is NAN * 5. +-(|x| > 1) ** +INF is +INF * 6. +-(|x| > 1) ** -INF is +0 * 7. +-(|x| < 1) ** +INF is +0 * 8. +-(|x| < 1) ** -INF is +INF - * 9. +-1 ** +-INF is 1 + * 9. -1 ** +-INF is 1 * 10. +0 ** (+anything except 0, NAN) is +0 * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 - * 12. +0 ** (-anything except 0, NAN) is +INF - * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF - * 14. -0 ** (odd integer) = -( +0 ** (odd integer) ) - * 15. +INF ** (+anything except 0,NAN) is +INF - * 16. +INF ** (-anything except 0,NAN) is +0 - * 17. -INF ** (anything) = -0 ** (-anything) - * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) - * 19. (-anything except 0 and inf) ** (non-integer) is NAN + * 12. +0 ** (-anything except 0, NAN) is +INF, raise divbyzero + * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF, raise divbyzero + * 14. -0 ** (+odd integer) is -0 + * 15. -0 ** (-odd integer) is -INF, raise divbyzero + * 16. +INF ** (+anything except 0,NAN) is +INF + * 17. +INF ** (-anything except 0,NAN) is +0 + * 18. -INF ** (+odd integer) is -INF + * 19. -INF ** (anything) = -0 ** (-anything), (anything except odd integer) + * 20. (anything) ** 1 is (anything) + * 21. (anything) ** -1 is 1/(anything) + * 22. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) + * 23. (-anything except 0 and inf) ** (non-integer) is NAN * * Accuracy: * pow(x,y) returns x**y nearly rounded. In particular @@ -98,18 +102,16 @@ double pow(double x, double y) ix = hx & 0x7fffffff; iy = hy & 0x7fffffff; - /* y == 0.0: x**0 = 1 */ + /* x**0 = 1, even if x is NaN */ if ((iy|ly) == 0) return 1.0; - - /* x == 1: 1**y = 1, even if y is NaN */ + /* 1**y = 1, even if y is NaN */ if (hx == 0x3ff00000 && lx == 0) return 1.0; - - /* y != 0.0: result is NaN if either arg is NaN */ + /* NaN if either arg is NaN */ if (ix > 0x7ff00000 || (ix == 0x7ff00000 && lx != 0) || iy > 0x7ff00000 || (iy == 0x7ff00000 && ly != 0)) - return (x+0.0) + (y+0.0); + return x + y; /* determine if y is an odd int when x < 0 * yisint = 0 ... y is not an integer @@ -142,13 +144,10 @@ double pow(double x, double y) else if (ix >= 0x3ff00000) /* (|x|>1)**+-inf = inf,0 */ return hy >= 0 ? y : 0.0; else /* (|x|<1)**+-inf = 0,inf */ - return hy < 0 ? -y : 0.0; - } - if (iy == 0x3ff00000) { /* y is +-1 */ - if (hy < 0) - return 1.0/x; - return x; + return hy >= 0 ? 0.0 : -y; } + if (iy == 0x3ff00000) /* y is +-1 */ + return hy >= 0 ? x : 1.0/x; if (hy == 0x40000000) /* y is 2 */ return x*x; if (hy == 0x3fe00000) { /* y is 0.5 */ @@ -174,19 +173,13 @@ double pow(double x, double y) } } - /* CYGNUS LOCAL + fdlibm-5.3 fix: This used to be - n = (hx>>31)+1; - but ANSI C says a right shift of a signed negative quantity is - implementation defined. */ - n = ((uint32_t)hx>>31) - 1; - - /* (x<0)**(non-int) is NaN */ - if ((n|yisint) == 0) - return (x-x)/(x-x); - - s = 1.0; /* s (sign of result -ve**odd) = -1 else = 1 */ - if ((n|(yisint-1)) == 0) - s = -1.0;/* (-ve)**(odd int) */ + s = 1.0; /* sign of result */ + if (hx < 0) { + if (yisint == 0) /* (x<0)**(non-int) is NaN */ + return (x-x)/(x-x); + if (yisint == 1) /* (x<0)**(odd int) */ + s = -1.0; + } /* |y| is huge */ if (iy > 0x41e00000) { /* if |y| > 2**31 */ diff --git a/src/math/powf.c b/src/math/powf.c index c101d95c..427c8965 100644 --- a/src/math/powf.c +++ b/src/math/powf.c @@ -57,17 +57,15 @@ float powf(float x, float y) ix = hx & 0x7fffffff; iy = hy & 0x7fffffff; - /* y == 0: x**0 = 1 */ + /* x**0 = 1, even if x is NaN */ if (iy == 0) return 1.0f; - - /* x == 1: 1**y = 1, even if y is NaN */ + /* 1**y = 1, even if y is NaN */ if (hx == 0x3f800000) return 1.0f; - - /* y != 0: result is NaN if either arg is NaN */ + /* NaN if either arg is NaN */ if (ix > 0x7f800000 || iy > 0x7f800000) - return (x+0.0f) + (y+0.0f); + return x + y; /* determine if y is an odd int when x < 0 * yisint = 0 ... y is not an integer @@ -93,13 +91,10 @@ float powf(float x, float y) else if (ix > 0x3f800000) /* (|x|>1)**+-inf = inf,0 */ return hy >= 0 ? y : 0.0f; else /* (|x|<1)**+-inf = 0,inf */ - return hy < 0 ? -y : 0.0f; - } - if (iy == 0x3f800000) { /* y is +-1 */ - if (hy < 0) - return 1.0f/x; - return x; + return hy >= 0 ? 0.0f: -y; } + if (iy == 0x3f800000) /* y is +-1 */ + return hy >= 0 ? x : 1.0f/x; if (hy == 0x40000000) /* y is 2 */ return x*x; if (hy == 0x3f000000) { /* y is 0.5 */ @@ -122,15 +117,13 @@ float powf(float x, float y) return z; } - n = ((uint32_t)hx>>31) - 1; - - /* (x<0)**(non-int) is NaN */ - if ((n|yisint) == 0) - return (x-x)/(x-x); - - sn = 1.0f; /* s (sign of result -ve**odd) = -1 else = 1 */ - if ((n|(yisint-1)) == 0) /* (-ve)**(odd int) */ - sn = -1.0f; + sn = 1.0f; /* sign of result */ + if (hx < 0) { + if (yisint == 0) /* (x<0)**(non-int) is NaN */ + return (x-x)/(x-x); + if (yisint == 1) /* (x<0)**(odd int) */ + sn = -1.0f; + } /* |y| is huge */ if (iy > 0x4d000000) { /* if |y| > 2**27 */ diff --git a/src/math/powl.c b/src/math/powl.c index a1d2f076..2ee0b10b 100644 --- a/src/math/powl.c +++ b/src/math/powl.c @@ -78,8 +78,6 @@ long double powl(long double x, long double y) /* Table size */ #define NXT 32 -/* log2(Table size) */ -#define LNXT 5 /* log(1+x) = x - .5x^2 + x^3 * P(z)/Q(z) * on the domain 2^(-1/32) - 1 <= x <= 2^(1/32) - 1 @@ -203,38 +201,35 @@ long double powl(long double x, long double y) volatile long double z=0; long double w=0, W=0, Wa=0, Wb=0, ya=0, yb=0, u=0; - if (y == 0.0) - return 1.0; - if (isnan(x)) + /* make sure no invalid exception is raised by nan comparision */ + if (isnan(x)) { + if (!isnan(y) && y == 0.0) + return 1.0; return x; - if (isnan(y)) + } + if (isnan(y)) { + if (x == 1.0) + return 1.0; return y; + } + if (x == 1.0) + return 1.0; /* 1**y = 1, even if y is nan */ + if (x == -1.0 && !isfinite(y)) + return 1.0; /* -1**inf = 1 */ + if (y == 0.0) + return 1.0; /* x**0 = 1, even if x is nan */ if (y == 1.0) return x; - - // FIXME: this is wrong, see pow special cases in c99 F.9.4.4 - if (!isfinite(y) && (x == -1.0 || x == 1.0) ) - return y - y; /* +-1**inf is NaN */ - if (x == 1.0) - return 1.0; if (y >= LDBL_MAX) { - if (x > 1.0) + if (x > 1.0 || x < -1.0) return INFINITY; - if (x > 0.0 && x < 1.0) - return 0.0; - if (x < -1.0) - return INFINITY; - if (x > -1.0 && x < 0.0) + if (x != 0.0) return 0.0; } if (y <= -LDBL_MAX) { - if (x > 1.0) + if (x > 1.0 || x < -1.0) return 0.0; - if (x > 0.0 && x < 1.0) - return INFINITY; - if (x < -1.0) - return 0.0; - if (x > -1.0 && x < 0.0) + if (x != 0.0) return INFINITY; } if (x >= LDBL_MAX) { @@ -244,6 +239,7 @@ long double powl(long double x, long double y) } w = floorl(y); + /* Set iyflg to 1 if y is an integer. */ iyflg = 0; if (w == y) @@ -271,43 +267,33 @@ long double powl(long double x, long double y) return 0.0; } } - - - nflg = 0; /* flag = 1 if x<0 raised to integer power */ + nflg = 0; /* (x<0)**(odd int) */ if (x <= 0.0) { if (x == 0.0) { if (y < 0.0) { if (signbit(x) && yoddint) - return -INFINITY; - return INFINITY; + /* (-0.0)**(-odd int) = -inf, divbyzero */ + return -1.0/0.0; + /* (+-0.0)**(negative) = inf, divbyzero */ + return 1.0/0.0; } - if (y > 0.0) { - if (signbit(x) && yoddint) - return -0.0; - return 0.0; - } - if (y == 0.0) - return 1.0; /* 0**0 */ - return 0.0; /* 0**y */ + if (signbit(x) && yoddint) + return -0.0; + return 0.0; } if (iyflg == 0) return (x - x) / (x - x); /* (x<0)**(non-int) is NaN */ - nflg = 1; + /* (x<0)**(integer) */ + if (yoddint) + nflg = 1; /* negate result */ + x = -x; } - - /* Integer power of an integer. */ - if (iyflg) { - i = w; - w = floorl(x); - if (w == x && fabsl(y) < 32768.0) { - w = powil(x, (int)y); - return w; - } + /* (+integer)**(integer) */ + if (iyflg && floorl(x) == x && fabsl(y) < 32768.0) { + w = powil(x, (int)y); + return nflg ? -w : w; } - if (nflg) - x = fabsl(x); - /* separate significand from exponent */ x = frexpl(x, &i); e = i; @@ -354,9 +340,7 @@ long double powl(long double x, long double y) z += x; /* Compute exponent term of the base 2 logarithm. */ - w = -i; - // TODO: use w * 0x1p-5; - w = scalbnl(w, -LNXT); /* divide by NXT */ + w = -i / NXT; w += e; /* Now base 2 log of x is w + z. */ @@ -381,7 +365,7 @@ long double powl(long double x, long double y) H = Fb + Gb; Ha = reducl(H); - w = scalbnl( Ga+Ha, LNXT ); + w = (Ga + Ha) * NXT; /* Test the power of 2 for overflow */ if (w > MEXP) @@ -418,18 +402,8 @@ long double powl(long double x, long double y) z = z + w; z = scalbnl(z, i); /* multiply by integer power of 2 */ - if (nflg) { - /* For negative x, - * find out if the integer exponent - * is odd or even. - */ - w = 0.5*y; - w = floorl(w); - w = 2.0*w; - if (w != y) - z = -z; /* odd exponent */ - } - + if (nflg) + z = -z; return z; } @@ -439,15 +413,14 @@ static long double reducl(long double x) { long double t; - t = scalbnl(x, LNXT); + t = x * NXT; t = floorl(t); - t = scalbnl(t, -LNXT); + t = t / NXT; return t; } -/* powil.c - * - * Real raised to integer power, long double precision +/* + * Positive real raised to integer power, long double precision * * * SYNOPSIS: @@ -460,7 +433,7 @@ static long double reducl(long double x) * * DESCRIPTION: * - * Returns argument x raised to the nth power. + * Returns argument x>0 raised to the nth power. * The routine efficiently decomposes n as a sum of powers of * two. The desired power is a product of two-to-the-kth * powers of x. Thus to compute the 32767 power of x requires @@ -482,25 +455,11 @@ static long double powil(long double x, int nn) { long double ww, y; long double s; - int n, e, sign, asign, lx; - - if (x == 0.0) { - if (nn == 0) - return 1.0; - else if (nn < 0) - return LDBL_MAX; - return 0.0; - } + int n, e, sign, lx; if (nn == 0) return 1.0; - if (x < 0.0) { - asign = -1; - x = -x; - } else - asign = 0; - if (nn < 0) { sign = -1; n = -nn; @@ -539,10 +498,8 @@ static long double powil(long double x, int nn) /* First bit of the power */ if (n & 1) y = x; - else { + else y = 1.0; - asign = 0; - } ww = x; n >>= 1; @@ -553,8 +510,6 @@ static long double powil(long double x, int nn) n >>= 1; } - if (asign) - y = -y; /* odd power of negative number */ if (sign < 0) y = 1.0/y; return y; diff --git a/src/math/remquo.c b/src/math/remquo.c index 79c9a55e..e92984ed 100644 --- a/src/math/remquo.c +++ b/src/math/remquo.c @@ -35,7 +35,6 @@ double remquo(double x, double y, int *quo) hy &= 0x7fffffff; /* |y| */ /* purge off exception values */ - // FIXME: signed shift if ((hy|ly) == 0 || hx >= 0x7ff00000 || /* y = 0, or x not finite */ (hy|((ly|-ly)>>31)) > 0x7ff00000) /* or y is NaN */ return (x*y)/(x*y); |