about summary refs log tree commit diff
path: root/src/math/__tan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/math/__tan.c')
-rw-r--r--src/math/__tan.c57
1 files changed, 24 insertions, 33 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);
 }