about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2013-05-18 12:06:42 -0400
committerRich Felker <dalias@aerifal.cx>2013-05-18 12:06:42 -0400
commit83af1dd65a11f3da3f99ba861248a841c402ccaa (patch)
treedece0960d64fb52abcf7a8195bf5082523cea70b
parent69ee9b2cb169ee843ac9e209f919d088499152f7 (diff)
parentbfda37935867f9bf271d6074db0accf05c63ad10 (diff)
downloadmusl-83af1dd65a11f3da3f99ba861248a841c402ccaa.tar.gz
musl-83af1dd65a11f3da3f99ba861248a841c402ccaa.tar.xz
musl-83af1dd65a11f3da3f99ba861248a841c402ccaa.zip
Merge remote-tracking branch 'nsz/review'
-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/cos.c20
-rw-r--r--src/math/cosf.c33
-rw-r--r--src/math/cosl.c22
-rw-r--r--src/math/sin.c15
-rw-r--r--src/math/sincos.c12
-rw-r--r--src/math/sincosf.c45
-rw-r--r--src/math/sincosl.c20
-rw-r--r--src/math/sinf.c33
-rw-r--r--src/math/sinl.c29
-rw-r--r--src/math/tan.c23
-rw-r--r--src/math/tanf.c32
-rw-r--r--src/math/tanl.c38
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