rework langinfo code for ABI compat and for use by time code
[musl] / src / math / tgammal.c
index e590550..5c1a02a 100644 (file)
@@ -21,7 +21,6 @@
  * SYNOPSIS:
  *
  * long double x, y, tgammal();
- * extern int signgam;
  *
  * y = tgammal( x );
  *
  * DESCRIPTION:
  *
  * Returns gamma function of the argument.  The result is
- * correctly signed, and the sign (+1 or -1) is also
- * returned in a global (extern) variable named signgam.
- * This variable is also filled in by the logarithmic gamma
- * function lgamma().
+ * correctly signed.
  *
  * Arguments |x| <= 13 are reduced by recurrence and the function
  * approximated by a rational function of degree 7/8 in the
@@ -68,7 +64,7 @@ n=7, d=8
 Peak error =  1.83e-20
 Relative error spread =  8.4e-23
 */
-static long double P[8] = {
+static const long double P[8] = {
  4.212760487471622013093E-5L,
  4.542931960608009155600E-4L,
  4.092666828394035500949E-3L,
@@ -78,7 +74,7 @@ static long double P[8] = {
  8.378004301573126728826E-1L,
  1.000000000000000000009E0L,
 };
-static long double Q[9] = {
+static const long double Q[9] = {
 -1.397148517476170440917E-5L,
  2.346584059160635244282E-4L,
 -1.237799246653152231188E-3L,
@@ -91,7 +87,7 @@ static long double Q[9] = {
 };
 
 /*
-static long double P[] = {
+static const long double P[] = {
 -3.01525602666895735709e0L,
 -3.25157411956062339893e1L,
 -2.92929976820724030353e2L,
@@ -101,7 +97,7 @@ static long double P[] = {
 -5.99650230220855581642e4L,
 -7.15743521530849602425e4L
 };
-static long double Q[] = {
+static const long double Q[] = {
  1.00000000000000000000e0L,
 -1.67955233807178858919e1L,
  8.85946791747759881659e1L,
@@ -125,7 +121,7 @@ n=8, d=0
 Peak error =  9.44e-21
 Relative error spread =  8.8e-4
 */
-static long double STIR[9] = {
+static const long double STIR[9] = {
  7.147391378143610789273E-4L,
 -2.363848809501759061727E-5L,
 -5.950237554056330156018E-4L,
@@ -145,7 +141,7 @@ static const long double SQTPI = 2.50662827463100050242E0L;
  * 0 < x < 0.03125
  * Peak relative error 4.2e-23
  */
-static long double S[9] = {
+static const long double S[9] = {
 -1.193945051381510095614E-3L,
  7.220599478036909672331E-3L,
 -9.622023360406271645744E-3L,
@@ -163,7 +159,7 @@ static long double S[9] = {
  * Peak relative error 5.16e-23
  * Relative error spread =  2.5e-24
  */
-static long double SN[9] = {
+static const long double SN[9] = {
  1.133374167243894382010E-3L,
  7.220837261893170325704E-3L,
  9.621911155035976733706E-3L,
@@ -183,18 +179,18 @@ static long double stirf(long double x)
 {
        long double y, w, v;
 
-       w = 1.0L/x;
+       w = 1.0/x;
        /* For large x, use rational coefficients from the analytical expansion.  */
-       if (x > 1024.0L)
+       if (x > 1024.0)
                w = (((((6.97281375836585777429E-5L * w
                 + 7.84039221720066627474E-4L) * w
                 - 2.29472093621399176955E-4L) * w
                 - 2.68132716049382716049E-3L) * w
                 + 3.47222222222222222222E-3L) * w
                 + 8.33333333333333333333E-2L) * w
-                + 1.0L;
+                + 1.0;
        else
-               w = 1.0L + w * __polevll(w, STIR, 8);
+               w = 1.0 + w * __polevll(w, STIR, 8);
        y = expl(x);
        if (x > MAXSTIR) { /* Avoid overflow in pow() */
                v = powl(x, 0.5L * x - 0.25L);
@@ -209,77 +205,69 @@ static long double stirf(long double x)
 long double tgammal(long double x)
 {
        long double p, q, z;
-       int i;
 
-       signgam = 1;
-       if (isnan(x))
-               return NAN;
-       if (x == INFINITY)
-               return INFINITY;
-       if (x == -INFINITY)
-               return x - x;
+       if (!isfinite(x))
+               return x + INFINITY;
+
        q = fabsl(x);
-       if (q > 13.0L) {
-               if (q > MAXGAML)
-                       goto goverf;
-               if (x < 0.0L) {
+       if (q > 13.0) {
+               if (x < 0.0) {
                        p = floorl(q);
-                       if (p == q)
-                               return (x - x) / (x - x);
-                       i = p;
-                       if ((i & 1) == 0)
-                               signgam = -1;
                        z = q - p;
-                       if (z > 0.5L) {
-                               p += 1.0L;
-                               z = q - p;
-                       }
-                       z = q * sinl(PIL * z);
-                       z = fabsl(z) * stirf(q);
-                       if (z <= PIL/LDBL_MAX) {
-goverf:
-                               return signgam * INFINITY;
+                       if (z == 0)
+                               return 0 / z;
+                       if (q > MAXGAML) {
+                               z = 0;
+                       } else {
+                               if (z > 0.5) {
+                                       p += 1.0;
+                                       z = q - p;
+                               }
+                               z = q * sinl(PIL * z);
+                               z = fabsl(z) * stirf(q);
+                               z = PIL/z;
                        }
-                       z = PIL/z;
+                       if (0.5 * p == floorl(q * 0.5))
+                               z = -z;
+               } else if (x > MAXGAML) {
+                       z = x * 0x1p16383L;
                } else {
                        z = stirf(x);
                }
-               return signgam * z;
+               return z;
        }
 
-       z = 1.0L;
-       while (x >= 3.0L) {
-               x -= 1.0L;
+       z = 1.0;
+       while (x >= 3.0) {
+               x -= 1.0;
                z *= x;
        }
        while (x < -0.03125L) {
                z /= x;
-               x += 1.0L;
+               x += 1.0;
        }
        if (x <= 0.03125L)
                goto small;
-       while (x < 2.0L) {
+       while (x < 2.0) {
                z /= x;
-               x += 1.0L;
+               x += 1.0;
        }
-       if (x == 2.0L)
+       if (x == 2.0)
                return z;
 
-       x -= 2.0L;
+       x -= 2.0;
        p = __polevll(x, P, 7);
        q = __polevll(x, Q, 8);
        z = z * p / q;
-       if(z < 0)
-               signgam = -1;
        return z;
 
 small:
-       if (x == 0.0L)
-               return (x - x) / (x - x);
-       if (x < 0.0L) {
+       /* z==1 if x was originally +-0 */
+       if (x == 0 && z != 1)
+               return x / x;
+       if (x < 0.0) {
                x = -x;
                q = z / (x * __polevll(x, SN, 8));
-               signgam = -1;
        } else
                q = z / (x * __polevll(x, S, 8));
        return q;