diff options
author | Rich Felker <dalias@aerifal.cx> | 2013-05-18 12:06:42 -0400 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2013-05-18 12:06:42 -0400 |
commit | 83af1dd65a11f3da3f99ba861248a841c402ccaa (patch) | |
tree | dece0960d64fb52abcf7a8195bf5082523cea70b | |
parent | 69ee9b2cb169ee843ac9e209f919d088499152f7 (diff) | |
parent | bfda37935867f9bf271d6074db0accf05c63ad10 (diff) | |
download | musl-83af1dd65a11f3da3f99ba861248a841c402ccaa.tar.gz musl-83af1dd65a11f3da3f99ba861248a841c402ccaa.tar.xz musl-83af1dd65a11f3da3f99ba861248a841c402ccaa.zip |
Merge remote-tracking branch 'nsz/review'
-rw-r--r-- | src/math/__tan.c | 57 | ||||
-rw-r--r-- | src/math/__tandf.c | 5 | ||||
-rw-r--r-- | src/math/__tanl.c | 32 | ||||
-rw-r--r-- | src/math/cos.c | 20 | ||||
-rw-r--r-- | src/math/cosf.c | 33 | ||||
-rw-r--r-- | src/math/cosl.c | 22 | ||||
-rw-r--r-- | src/math/sin.c | 15 | ||||
-rw-r--r-- | src/math/sincos.c | 12 | ||||
-rw-r--r-- | src/math/sincosf.c | 45 | ||||
-rw-r--r-- | src/math/sincosl.c | 20 | ||||
-rw-r--r-- | src/math/sinf.c | 33 | ||||
-rw-r--r-- | src/math/sinl.c | 29 | ||||
-rw-r--r-- | src/math/tan.c | 23 | ||||
-rw-r--r-- | src/math/tanf.c | 32 | ||||
-rw-r--r-- | src/math/tanl.c | 38 |
15 files changed, 203 insertions, 213 deletions
diff --git a/src/math/__tan.c b/src/math/__tan.c index fc739f95..8019844d 100644 --- a/src/math/__tan.c +++ b/src/math/__tan.c @@ -12,7 +12,7 @@ * kernel tan function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854 * Input x is assumed to be bounded by ~pi/4 in magnitude. * Input y is the tail of x. - * Input k indicates whether tan (if k = 1) or -1/tan (if k = -1) is returned. + * Input odd indicates whether tan (if odd = 0) or -1/tan (if odd = 1) is returned. * * Algorithm * 1. Since tan(-x) = -tan(x), we need only to consider positive x. @@ -63,21 +63,22 @@ static const double T[] = { pio4 = 7.85398163397448278999e-01, /* 3FE921FB, 54442D18 */ pio4lo = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */ -double __tan(double x, double y, int iy) +double __tan(double x, double y, int odd) { - double_t z, r, v, w, s, sign; - int32_t ix, hx; + double_t z, r, v, w, s, a; + double w0, a0; + uint32_t hx; + int big, sign; GET_HIGH_WORD(hx,x); - ix = hx & 0x7fffffff; /* high word of |x| */ - if (ix >= 0x3FE59428) { /* |x| >= 0.6744 */ - if (hx < 0) { + big = (hx&0x7fffffff) >= 0x3FE59428; /* |x| >= 0.6744 */ + if (big) { + sign = hx>>31; + if (sign) { x = -x; y = -y; } - z = pio4 - x; - w = pio4lo - y; - x = z + w; + x = (pio4 - x) + (pio4lo - y); y = 0.0; } z = x * x; @@ -90,30 +91,20 @@ double __tan(double x, double y, int iy) r = T[1] + w*(T[3] + w*(T[5] + w*(T[7] + w*(T[9] + w*T[11])))); v = z*(T[2] + w*(T[4] + w*(T[6] + w*(T[8] + w*(T[10] + w*T[12]))))); s = z * x; - r = y + z * (s * (r + v) + y); - r += T[0] * s; + r = y + z*(s*(r + v) + y) + s*T[0]; w = x + r; - if (ix >= 0x3FE59428) { - v = iy; - sign = 1 - ((hx >> 30) & 2); - return sign * (v - 2.0 * (x - (w * w / (w + v) - r))); + if (big) { + s = 1 - 2*odd; + v = s - 2.0 * (x + (r - w*w/(w + s))); + return sign ? -v : v; } - if (iy == 1) + if (!odd) return w; - else { - /* - * if allow error up to 2 ulp, simply return - * -1.0 / (x+r) here - */ - /* compute -1.0 / (x+r) accurately */ - double_t a; - double z, t; - z = w; - SET_LOW_WORD(z,0); - v = r - (z - x); /* z+v = r+x */ - t = a = -1.0 / w; /* a = -1.0/w */ - SET_LOW_WORD(t,0); - s = 1.0 + t * z; - return t + a * (s + t * v); - } + /* -1.0/(x+r) has up to 2ulp error, so compute it accurately */ + w0 = w; + SET_LOW_WORD(w0, 0); + v = r - (w0 - x); /* w0+v = r+x */ + a0 = a = -1.0 / w; + SET_LOW_WORD(a0, 0); + return a0 + a*(1.0 + a0*w0 + a0*v); } diff --git a/src/math/__tandf.c b/src/math/__tandf.c index 3e632fdf..25047eee 100644 --- a/src/math/__tandf.c +++ b/src/math/__tandf.c @@ -25,7 +25,7 @@ static const double T[] = { 0x1362b9bf971bcd.0p-59, /* 0.00946564784943673166728 */ }; -float __tandf(double x, int iy) +float __tandf(double x, int odd) { double_t z,r,w,s,t,u; @@ -50,6 +50,5 @@ float __tandf(double x, int iy) s = z*x; u = T[0] + z*T[1]; r = (x + s*u) + (s*w)*(t + w*r); - if(iy==1) return r; - else return -1.0/r; + return odd ? -1.0/r : r; } diff --git a/src/math/__tanl.c b/src/math/__tanl.c index 50ba2140..4b36e616 100644 --- a/src/math/__tanl.c +++ b/src/math/__tanl.c @@ -45,25 +45,21 @@ T29 = 0.0000078293456938132840, /* 0x106b59141a6cb3.0p-69 */ T31 = -0.0000032609076735050182, /* -0x1b5abef3ba4b59.0p-71 */ T33 = 0.0000023261313142559411; /* 0x13835436c0c87f.0p-71 */ -long double __tanl(long double x, long double y, int iy) { +long double __tanl(long double x, long double y, int odd) { long double z, r, v, w, s, a, t; - long double osign; - int i; + int big, sign; - iy = iy == 1 ? -1 : 1; /* XXX recover original interface */ - osign = copysignl(1.0, x); - if (fabsl(x) >= 0.67434) { + big = fabsl(x) >= 0.67434; + if (big) { + sign = 0; if (x < 0) { + sign = 1; x = -x; y = -y; } - z = pio4 - x; - w = pio4lo - y; - x = z + w; + x = (pio4 - x) + (pio4lo - y); y = 0.0; - i = 1; - } else - i = 0; + } z = x * x; w = z * z; r = T5 + w * (T9 + w * (T13 + w * (T17 + w * (T21 + @@ -71,14 +67,14 @@ long double __tanl(long double x, long double y, int iy) { v = z * (T7 + w * (T11 + w * (T15 + w * (T19 + w * (T23 + w * (T27 + w * T31)))))); s = z * x; - r = y + z * (s * (r + v) + y); - r += T3 * s; + r = y + z * (s * (r + v) + y) + T3 * s; w = x + r; - if (i == 1) { - v = (long double)iy; - return osign * (v - 2.0 * (x - (w * w / (w + v) - r))); + if (big) { + s = 1 - 2*odd; + v = s - 2.0 * (x + (r - w * w / (w + s))); + return sign ? -v : v; } - if (iy == 1) + if (!odd) return w; /* diff --git a/src/math/cos.c b/src/math/cos.c index 76990e7f..ee97f68b 100644 --- a/src/math/cos.c +++ b/src/math/cos.c @@ -44,26 +44,28 @@ double cos(double x) { - double y[2],z=0.0; - int32_t n, ix; + double y[2]; + uint32_t ix; + unsigned n; GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; /* |x| ~< pi/4 */ - ix &= 0x7fffffff; if (ix <= 0x3fe921fb) { - if (ix < 0x3e46a09e) /* if x < 2**-27 * sqrt(2) */ - /* raise inexact if x != 0 */ - if ((int)x == 0) - return 1.0; - return __cos(x, z); + if (ix < 0x3e46a09e) { /* |x| < 2**-27 * sqrt(2) */ + /* raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return 1.0; + } + return __cos(x, 0); } /* cos(Inf or NaN) is NaN */ if (ix >= 0x7ff00000) return x-x; - /* argument reduction needed */ + /* argument reduction */ n = __rem_pio2(x, y); switch (n&3) { case 0: return __cos(y[0], y[1]); diff --git a/src/math/cosf.c b/src/math/cosf.c index 4d94130f..23f3e5bf 100644 --- a/src/math/cosf.c +++ b/src/math/cosf.c @@ -26,34 +26,39 @@ c4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ float cosf(float x) { double y; - int32_t n, hx, ix; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; - GET_FLOAT_WORD(hx, x); - ix = hx & 0x7fffffff; if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ - if (ix < 0x39800000) /* |x| < 2**-12 */ - if ((int)x == 0) /* raise inexact if x != 0 */ - return 1.0; + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x != 0 */ + FORCE_EVAL(x + 0x1p120f); + return 1.0f; + } return __cosdf(x); } if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ if (ix > 0x4016cbe3) /* |x| ~> 3*pi/4 */ - return -__cosdf(hx > 0 ? x-c2pio2 : x+c2pio2); + return -__cosdf(sign ? x+c2pio2 : x-c2pio2); else { - if (hx > 0) - return __sindf(c1pio2 - x); - else + if (sign) return __sindf(x + c1pio2); + else + return __sindf(c1pio2 - x); } } if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ if (ix > 0x40afeddf) /* |x| ~> 7*pi/4 */ - return __cosdf(hx > 0 ? x-c4pio2 : x+c4pio2); + return __cosdf(sign ? x+c4pio2 : x-c4pio2); else { - if (hx > 0) - return __sindf(x - c3pio2); + if (sign) + return __sindf(-x - c3pio2); else - return __sindf(-c3pio2 - x); + return __sindf(x - c3pio2); } } diff --git a/src/math/cosl.c b/src/math/cosl.c index 25d9005a..0794d284 100644 --- a/src/math/cosl.c +++ b/src/math/cosl.c @@ -39,30 +39,30 @@ long double cosl(long double x) { long double cosl(long double x) { union IEEEl2bits z; - int e0; + unsigned n; long double y[2]; long double hi, lo; z.e = x; z.bits.sign = 0; - /* If x = +-0 or x is a subnormal number, then cos(x) = 1 */ - if (z.bits.exp == 0) - return 1.0; - /* If x = NaN or Inf, then cos(x) = NaN. */ - if (z.bits.exp == 32767) + if (z.bits.exp == 0x7fff) return (x - x) / (x - x); - /* Optimize the case where x is already within range. */ - if (z.e < M_PI_4) + /* |x| < (double)pi/4 */ + if (z.e < M_PI_4) { + /* |x| < 0x1p-64 */ + if (z.bits.exp < 0x3fff - 64) + /* raise inexact if x!=0 */ + return 1.0 + x; return __cosl(z.e, 0); + } - e0 = __rem_pio2l(x, y); + n = __rem_pio2l(x, y); hi = y[0]; lo = y[1]; - - switch (e0 & 3) { + switch (n & 3) { case 0: hi = __cosl(hi, lo); break; diff --git a/src/math/sin.c b/src/math/sin.c index 8e430f85..055e215b 100644 --- a/src/math/sin.c +++ b/src/math/sin.c @@ -44,21 +44,22 @@ double sin(double x) { - double y[2], z=0.0; - int32_t n, ix; + double y[2]; + uint32_t ix; + unsigned n; /* High word of x. */ GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; /* |x| ~< pi/4 */ - ix &= 0x7fffffff; if (ix <= 0x3fe921fb) { if (ix < 0x3e500000) { /* |x| < 2**-26 */ - /* raise inexact if x != 0 */ - if ((int)x == 0) - return x; + /* raise inexact if x != 0 and underflow if subnormal*/ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + return x; } - return __sin(x, z, 0); + return __sin(x, 0.0, 0); } /* sin(Inf or NaN) is NaN */ diff --git a/src/math/sincos.c b/src/math/sincos.c index 442e285e..49f8a098 100644 --- a/src/math/sincos.c +++ b/src/math/sincos.c @@ -15,7 +15,8 @@ void sincos(double x, double *sin, double *cos) { double y[2], s, c; - uint32_t n, ix; + uint32_t ix; + unsigned n; GET_HIGH_WORD(ix, x); ix &= 0x7fffffff; @@ -24,11 +25,10 @@ void sincos(double x, double *sin, double *cos) if (ix <= 0x3fe921fb) { /* if |x| < 2**-27 * sqrt(2) */ if (ix < 0x3e46a09e) { - /* raise inexact if x != 0 */ - if ((int)x == 0) { - *sin = x; - *cos = 1.0; - } + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + *sin = x; + *cos = 1.0; return; } *sin = __sin(x, 0.0, 0); diff --git a/src/math/sincosf.c b/src/math/sincosf.c index 5e3b9a41..1b50f01c 100644 --- a/src/math/sincosf.c +++ b/src/math/sincosf.c @@ -25,21 +25,23 @@ s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ void sincosf(float x, float *sin, float *cos) { - double y, s, c; - uint32_t n, hx, ix; + double y; + float_t s, c; + uint32_t ix; + unsigned n, sign; - GET_FLOAT_WORD(hx, x); - ix = hx & 0x7fffffff; + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; /* |x| ~<= pi/4 */ if (ix <= 0x3f490fda) { /* |x| < 2**-12 */ if (ix < 0x39800000) { - /* raise inexact if x != 0 */ - if((int)x == 0) { - *sin = x; - *cos = 1.0f; - } + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + *sin = x; + *cos = 1.0f; return; } *sin = __sindf(x); @@ -50,34 +52,35 @@ void sincosf(float x, float *sin, float *cos) /* |x| ~<= 5*pi/4 */ if (ix <= 0x407b53d1) { if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ - if (hx < 0x80000000) { - *sin = __cosdf(x - s1pio2); - *cos = __sindf(s1pio2 - x); - } else { + if (sign) { *sin = -__cosdf(x + s1pio2); *cos = __sindf(x + s1pio2); + } else { + *sin = __cosdf(s1pio2 - x); + *cos = __sindf(s1pio2 - x); } return; } - *sin = __sindf(hx < 0x80000000 ? s2pio2 - x : -s2pio2 - x); - *cos = -__cosdf(hx < 0x80000000 ? x - s2pio2 : x + s2pio2); + /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ + *sin = -__sindf(sign ? x + s2pio2 : x - s2pio2); + *cos = -__cosdf(sign ? x + s2pio2 : x - s2pio2); return; } /* |x| ~<= 9*pi/4 */ if (ix <= 0x40e231d5) { if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ - if (hx < 0x80000000) { + if (sign) { + *sin = __cosdf(x + s3pio2); + *cos = -__sindf(x + s3pio2); + } else { *sin = -__cosdf(x - s3pio2); *cos = __sindf(x - s3pio2); - } else { - *sin = __cosdf(x + s3pio2); - *cos = __sindf(-s3pio2 - x); } return; } - *sin = __sindf(hx < 0x80000000 ? x - s4pio2 : x + s4pio2); - *cos = __cosdf(hx < 0x80000000 ? x - s4pio2 : x + s4pio2); + *sin = __sindf(sign ? x + s4pio2 : x - s4pio2); + *cos = __cosdf(sign ? x + s4pio2 : x - s4pio2); return; } diff --git a/src/math/sincosl.c b/src/math/sincosl.c index d632fe6f..5db69bd6 100644 --- a/src/math/sincosl.c +++ b/src/math/sincosl.c @@ -10,27 +10,29 @@ void sincosl(long double x, long double *sin, long double *cos) void sincosl(long double x, long double *sin, long double *cos) { union IEEEl2bits u; - int n; + unsigned n; long double y[2], s, c; u.e = x; u.bits.sign = 0; - /* x = +-0 or subnormal */ - if (!u.bits.exp) { - *sin = x; - *cos = 1.0; - return; - } - /* x = nan or inf */ if (u.bits.exp == 0x7fff) { *sin = *cos = x - x; return; } - /* |x| < pi/4 */ + /* |x| < (double)pi/4 */ if (u.e < M_PI_4) { + /* |x| < 0x1p-64 */ + if (u.bits.exp < 0x3fff - 64) { + /* raise underflow if subnormal */ + if (u.bits.exp == 0) FORCE_EVAL(x*0x1p-120f); + *sin = x; + /* raise inexact if x!=0 */ + *cos = 1.0 + x; + return; + } *sin = __sinl(x, 0, 0); *cos = __cosl(x, 0); return; diff --git a/src/math/sinf.c b/src/math/sinf.c index dcca67af..64e39f50 100644 --- a/src/math/sinf.c +++ b/src/math/sinf.c @@ -26,35 +26,38 @@ s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ float sinf(float x) { double y; - int32_t n, hx, ix; + uint32_t ix; + int n, sign; - GET_FLOAT_WORD(hx, x); - ix = hx & 0x7fffffff; + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ - if (ix < 0x39800000) /* |x| < 2**-12 */ - /* raise inexact if x != 0 */ - if((int)x == 0) - return x; + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00800000 ? x/0x1p120f : x+0x1p120f); + return x; + } return __sindf(x); } if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ - if (hx > 0) - return __cosdf(x - s1pio2); - else + if (sign) return -__cosdf(x + s1pio2); + else + return __cosdf(x - s1pio2); } - return __sindf(hx > 0 ? s2pio2 - x : -s2pio2 - x); + return __sindf(sign ? -(x + s2pio2) : -(x - s2pio2)); } if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ - if (hx > 0) - return -__cosdf(x - s3pio2); - else + if (sign) return __cosdf(x + s3pio2); + else + return -__cosdf(x - s3pio2); } - return __sindf(hx > 0 ? x - s4pio2 : x + s4pio2); + return __sindf(sign ? x + s4pio2 : x - s4pio2); } /* sin(Inf or NaN) is NaN */ diff --git a/src/math/sinl.c b/src/math/sinl.c index 7e0b44f4..6ca99986 100644 --- a/src/math/sinl.c +++ b/src/math/sinl.c @@ -37,33 +37,32 @@ long double sinl(long double x) long double sinl(long double x) { union IEEEl2bits z; - int e0, s; + unsigned n; long double y[2]; long double hi, lo; z.e = x; - s = z.bits.sign; z.bits.sign = 0; - /* If x = +-0 or x is a subnormal number, then sin(x) = x */ - if (z.bits.exp == 0) - return x; - /* If x = NaN or Inf, then sin(x) = NaN. */ - if (z.bits.exp == 32767) + if (z.bits.exp == 0x7fff) return (x - x) / (x - x); - /* Optimize the case where x is already within range. */ + /* |x| < (double)pi/4 */ if (z.e < M_PI_4) { - hi = __sinl(z.e, 0, 0); - return s ? -hi : hi; + /* |x| < 0x1p-64 */ + if (z.bits.exp < 0x3fff - 64) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(z.bits.exp == 0 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __sinl(x, 0.0, 0); } - e0 = __rem_pio2l(x, y); + n = __rem_pio2l(x, y); hi = y[0]; lo = y[1]; - - switch (e0 & 3) { + switch (n & 3) { case 0: hi = __sinl(hi, lo, 1); break; @@ -71,10 +70,10 @@ long double sinl(long double x) hi = __cosl(hi, lo); break; case 2: - hi = - __sinl(hi, lo, 1); + hi = -__sinl(hi, lo, 1); break; case 3: - hi = - __cosl(hi, lo); + hi = -__cosl(hi, lo); break; } return hi; diff --git a/src/math/tan.c b/src/math/tan.c index 2e1f3c83..9c724a45 100644 --- a/src/math/tan.c +++ b/src/math/tan.c @@ -43,27 +43,28 @@ double tan(double x) { - double y[2], z = 0.0; - int32_t n, ix; + double y[2]; + uint32_t ix; + unsigned n; - /* High word of x. */ GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; /* |x| ~< pi/4 */ - ix &= 0x7fffffff; if (ix <= 0x3fe921fb) { - if (ix < 0x3e400000) /* x < 2**-27 */ - /* raise inexact if x != 0 */ - if ((int)x == 0) - return x; - return __tan(x, z, 1); + if (ix < 0x3e400000) { /* |x| < 2**-27 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __tan(x, 0.0, 0); } /* tan(Inf or NaN) is NaN */ if (ix >= 0x7ff00000) return x - x; - /* argument reduction needed */ + /* argument reduction */ n = __rem_pio2(x, y); - return __tan(y[0], y[1], 1 - ((n&1)<<1)); /* n even: 1, n odd: -1 */ + return __tan(y[0], y[1], n&1); } diff --git a/src/math/tanf.c b/src/math/tanf.c index 8b0dfb20..aba19777 100644 --- a/src/math/tanf.c +++ b/src/math/tanf.c @@ -26,37 +26,39 @@ t4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ float tanf(float x) { double y; - int32_t n, hx, ix; + uint32_t ix; + unsigned n, sign; - GET_FLOAT_WORD(hx, x); - ix = hx & 0x7fffffff; + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ - if (ix < 0x39800000) /* |x| < 2**-12 */ - /* return x and raise inexact if x != 0 */ - if ((int)x == 0) - return x; - return __tandf(x, 1); + if (ix < 0x39800000) { /* |x| < 2**-12 */ + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00800000 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __tandf(x, 0); } if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ if (ix <= 0x4016cbe3) /* |x| ~<= 3pi/4 */ - return __tandf((hx > 0 ? x-t1pio2 : x+t1pio2), -1); + return __tandf((sign ? x+t1pio2 : x-t1pio2), 1); else - return __tandf((hx > 0 ? x-t2pio2 : x+t2pio2), 1); + return __tandf((sign ? x+t2pio2 : x-t2pio2), 0); } if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ if (ix <= 0x40afeddf) /* |x| ~<= 7*pi/4 */ - return __tandf((hx > 0 ? x-t3pio2 : x+t3pio2), -1); + return __tandf((sign ? x+t3pio2 : x-t3pio2), 1); else - return __tandf((hx > 0 ? x-t4pio2 : x+t4pio2), 1); + return __tandf((sign ? x+t4pio2 : x-t4pio2), 0); } /* tan(Inf or NaN) is NaN */ if (ix >= 0x7f800000) return x - x; - /* general argument reduction needed */ + /* argument reduction */ n = __rem_pio2f(x, &y); - /* integer parameter: n even: 1; n odd: -1 */ - return __tandf(y, 1-((n&1)<<1)); + return __tandf(y, n&1); } diff --git a/src/math/tanl.c b/src/math/tanl.c index 0194eaf7..546c7a02 100644 --- a/src/math/tanl.c +++ b/src/math/tanl.c @@ -41,42 +41,28 @@ long double tanl(long double x) long double tanl(long double x) { union IEEEl2bits z; - int e0, s; long double y[2]; - long double hi, lo; + unsigned n; 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) + if (z.bits.exp == 0x7fff) return (x - x) / (x - x); - /* Optimize the case where x is already within range. */ + /* |x| < (double)pi/4 */ if (z.e < M_PI_4) { - hi = __tanl(z.e, 0, 0); - return s ? -hi : hi; + /* |x| < 0x1p-64 */ + if (z.bits.exp < 0x3fff - 64) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(z.bits.exp == 0 ? x/0x1p120f : x+0x1p120f); + return x; + } + return __tanl(x, 0, 0); } - e0 = __rem_pio2l(x, y); - hi = y[0]; - lo = y[1]; - - switch (e0 & 3) { - case 0: - case 2: - hi = __tanl(hi, lo, 0); - break; - case 1: - case 3: - hi = __tanl(hi, lo, 1); - break; - } - return hi; + n = __rem_pio2l(x, y); + return __tanl(y[0], y[1], n&1); } #endif |