math: clean up inverse trigonometric functions
[musl] / src / math / acos.c
index 0eb15be..be95d25 100644 (file)
 #include "libm.h"
 
 static const double
-pi      = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
-pio2_hi = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */
-// FIXME
-static const volatile double
-pio2_lo = 6.12323399573676603587e-17; /* 0x3C91A626, 0x33145C07 */
-static const double
+pio2_hi = 1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo = 6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
 pS0 =  1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
 pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
 pS2 =  2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
@@ -53,49 +49,53 @@ qS2 =  2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
 qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
 qS4 =  7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
 
+static double R(double z)
+{
+       double p, q;
+       p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+       q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+       return p/q;
+}
+
 double acos(double x)
 {
-       double z,p,q,r,w,s,c,df;
-       int32_t hx,ix;
+       double z,w,s,c,df;
+       uint32_t hx,ix;
 
        GET_HIGH_WORD(hx, x);
        ix = hx & 0x7fffffff;
-       if (ix >= 0x3ff00000) {  /* |x| >= 1 */
+       /* |x| >= 1 or nan */
+       if (ix >= 0x3ff00000) {
                uint32_t lx;
 
                GET_LOW_WORD(lx,x);
-               if ((ix-0x3ff00000 | lx) == 0) {  /* |x|==1 */
-                       if (hx > 0) return 0.0;  /* acos(1) = 0  */
-                       return pi + 2.0*pio2_lo; /* acos(-1)= pi */
+               if ((ix-0x3ff00000 | lx) == 0) {
+                       /* acos(1)=0, acos(-1)=pi */
+                       if (hx >> 31)
+                               return 2*pio2_hi + 0x1p-1000;
+                       return 0;
                }
-               return (x-x)/(x-x);  /* acos(|x|>1) is NaN */
+               return 0/(x-x);
        }
-       if (ix < 0x3fe00000) {   /* |x| < 0.5 */
+       /* |x| < 0.5 */
+       if (ix < 0x3fe00000) {
                if (ix <= 0x3c600000)  /* |x| < 2**-57 */
-                       return pio2_hi + pio2_lo;
-               z = x*x;
-               p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
-               q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
-               r = p/q;
-               return pio2_hi - (x - (pio2_lo-x*r));
-       } else if (hx < 0) {     /* x < -0.5 */
+                       return pio2_hi + 0x1p-1000;
+               return pio2_hi - (x - (pio2_lo-x*R(x*x)));
+       }
+       /* x < -0.5 */
+       if (hx >> 31) {
                z = (1.0+x)*0.5;
-               p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
-               q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
-               s = sqrt(z);
-               r = p/q;
-               w = r*s-pio2_lo;
-               return pi - 2.0*(s+w);
-       } else {                 /* x > 0.5 */
-               z = (1.0-x)*0.5;
                s = sqrt(z);
-               df = s;
-               SET_LOW_WORD(df,0);
-               c  = (z-df*df)/(s+df);
-               p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
-               q = 1.0+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
-               r = p/q;
-               w = r*s+c;
-               return 2.0*(df+w);
+               w = R(z)*s-pio2_lo;
+               return 2*(pio2_hi - (s+w));
        }
+       /* x > 0.5 */
+       z = (1.0-x)*0.5;
+       s = sqrt(z);
+       df = s;
+       SET_LOW_WORD(df,0);
+       c = (z-df*df)/(s+df);
+       w = R(z)*s+c;
+       return 2*(df+w);
 }