summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/math/__tan.c57
-rw-r--r--src/math/__tandf.c5
-rw-r--r--src/math/__tanl.c32
-rw-r--r--src/math/tan.c23
-rw-r--r--src/math/tanf.c32
-rw-r--r--src/math/tanl.c37
6 files changed, 80 insertions, 106 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/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..3b51e011 100644
--- a/src/math/tanl.c
+++ b/src/math/tanl.c
@@ -41,42 +41,27 @@ 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 = +-0 or x is subnormal */
+ if (z.bits.exp == 0)
+ /* inexact and underflow if x!=0 */
+ return x + x*0x1p-120f;
+ /* can raise spurious underflow */
+ 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