148402Sbostic /*- 2*56957Sbostic * Copyright (c) 1992 The Regents of the University of California. 348402Sbostic * All rights reserved. 448402Sbostic * 5*56957Sbostic * %sccs.include.redist.c% 634120Sbostic */ 734120Sbostic 824600Szliu #ifndef lint 9*56957Sbostic static char sccsid[] = "@(#)lgamma.c 5.6 (Berkeley) 12/02/92"; 1034120Sbostic #endif /* not lint */ 1124600Szliu 1256952Sbostic #include <math.h> 1356952Sbostic #include <errno.h> 1424600Szliu 1556952Sbostic #include "mathimpl.h" 1624600Szliu 1756952Sbostic /* TRUNC sets trailing bits in a floating-point number to zero. 1856952Sbostic * ptrx points to the second half of the floating-point number. 1956952Sbostic * x1 is a temporary variable. 2024600Szliu */ 2124600Szliu 2256952Sbostic #if defined(vax) || defined(tahoe) 2356952Sbostic #define LSHFT_PLUS_1 (134217728.+1.) 2456952Sbostic #define TRUNC(x, dummy, x1) x1 = x*LSHFT_PLUS_1, x -= x1, x += x1 2556952Sbostic #else 2656952Sbostic #define MASK 0xf8000000 2756952Sbostic #define TRUNC(x, ptrx, dummy) *ptrx &= MASK 2856952Sbostic #endif 2935679Sbostic 3056952Sbostic #define x0 0.461632144968362356785 3156952Sbostic #define x0_lo -.000000000000000015522348162858676890521 3256952Sbostic #define a0_hi -0.12148629053584961146 3356952Sbostic #define a0_lo 3.07435645275902737e-18 3456952Sbostic #define LEFT (1.0 - (x0 + .25)) 3556952Sbostic #define RIGHT (x0 - .218) 3656952Sbostic #define lns2pi_hi 0.418945312500000 3756952Sbostic #define lns2pi_lo -.000006779295327258219670263595 3824600Szliu 3956952Sbostic #define UNDERFL (1e-1020 * 1e-1020) 4056952Sbostic int signgam; 4156952Sbostic 4256952Sbostic #define r0 -0.02771227512955130520 4356952Sbostic #define r1 -0.2980729795228150847 4456952Sbostic #define r2 -0.3257411333183093394 4556952Sbostic #define r3 -0.1126814387531706041 4656952Sbostic #define r4 -0.01129130057170225562 4756952Sbostic #define r5 -2.259650588213369095e-05 4856952Sbostic #define s0 1.7144571600017144419 4956952Sbostic #define s1 2.7864695046181946481 5056952Sbostic #define s2 1.5645463655191798047 5156952Sbostic #define s3 0.34858463899811098496 5256952Sbostic #define s4 0.024677593453636563481 5356952Sbostic 5456952Sbostic #define p0 -7.721566490153286087127140e-02 5556952Sbostic #define p1 2.077324848654884653970785e-01 5656952Sbostic #define p2 3.474331160945523535787194e-01 5756952Sbostic #define p3 1.724375677840324429295524e-01 5856952Sbostic #define p4 3.546181984297784658205969e-02 5956952Sbostic #define p5 2.866163630124151557532506e-03 6056952Sbostic #define p6 6.143168512963655570532770e-05 6156952Sbostic #define q0 1.000000000000000000000000e+00 6256952Sbostic #define q1 1.485897307300750567469226e+00 6356952Sbostic #define q2 8.336064915387758261556045e-01 6456952Sbostic #define q3 2.185469782512070977585556e-01 6556952Sbostic #define q4 2.671060746990048983840354e-02 6656952Sbostic #define q5 1.296631961305647947057711e-03 6756952Sbostic #define q6 1.484566091079246905938151e-05 6856952Sbostic 6956952Sbostic #define NP2 8 7056952Sbostic double P2[] = { 7156952Sbostic .0833333333333333148296162562474, 7256952Sbostic -.00277777777774548123579378966497, 7356952Sbostic .000793650778754435631476282786423, 7456952Sbostic -.000595235082566672847950717262222, 7556952Sbostic .000841428560346653702135821806252, 7656952Sbostic -.00189773526463879200348872089421, 7756952Sbostic .00569394463439411649408050664078, 7856952Sbostic -.0144705562421428915453880392761 7924600Szliu }; 8024600Szliu 8156952Sbostic static double neg_lgam __P((double)); 8256952Sbostic static double small_lgam __P((double)); 8356952Sbostic static double large_lgam __P((double)); 8435679Sbostic 8524600Szliu double 8656952Sbostic lgamma(x) 8756952Sbostic double x; 8824600Szliu { 8956952Sbostic double zero = 0.0, one = 1.0; 9056952Sbostic double r; 9156952Sbostic signgam = 1; 9256952Sbostic if (!finite(x)) { 9356952Sbostic errno = EDOM; 9456952Sbostic if (x < 0) 9556952Sbostic x = -x; 9656952Sbostic else if (x > 0) 9756952Sbostic errno = ERANGE; 9856952Sbostic return (x); 9956952Sbostic } 10056952Sbostic if (x > 6 + RIGHT) { 10156952Sbostic if (x > 1.0e20) 10256952Sbostic return (x*(log(x)-one)); 10356952Sbostic r = large_lgam(x); 10456952Sbostic return (r); 10556952Sbostic } else if (x > 1e-17) 10656952Sbostic return (small_lgam(x)); 10756952Sbostic else if(x > -1e-17) { 10856952Sbostic if (x < 0) 10956952Sbostic signgam = -1, x = -x; 11056952Sbostic return (-log(x)); 11156952Sbostic } else 11256952Sbostic return (neg_lgam(x)); 11324600Szliu } 11424600Szliu 11556952Sbostic /* Accurate to max(ulp(1/128) absolute, 2^-75 relative) error. */ 11624600Szliu static double 11756952Sbostic large_lgam(x) 11856952Sbostic double x; 11924600Szliu { 12056952Sbostic double z, p, x1; 12124600Szliu int i; 12256952Sbostic long *pva, *pua; 12356952Sbostic struct Double t, u, v; 12456952Sbostic pua = (long *) &u.a, pua++; 12556952Sbostic pva = (long *) &v.a, pva++; 12656952Sbostic z = 1.0/(x*x); 12756952Sbostic for (p = P2[i = NP2-1]; --i >= 0;) 12856952Sbostic p = P2[i] + p*z; /* error in approximation = 2.8e-18 */ 12924600Szliu 13056952Sbostic p = p/x; /* ulp = 1.7e-18; error < 1.6ulp */ 13156952Sbostic /* 0 < frac < 1/64 (at x = 5.5) */ 13256952Sbostic t = log__D(x); 13356952Sbostic t.a -= 1.0; 13456952Sbostic u.a = t.a + t.b; 13556952Sbostic TRUNC (u.a, pua, x1); /* truncate u.a */ 13656952Sbostic u.b = (t.a - u.a); 13756952Sbostic u.b += t.b; 13856952Sbostic x -= .5; 13956952Sbostic v.a = x; 14056952Sbostic TRUNC(v.a, pva, x1); /* truncate v.a */ 14156952Sbostic v.b = x - v.a; 14256952Sbostic t.a = v.a*u.a; /* t = (x-.5)*(log(x)-1) */ 14356952Sbostic t.b = v.b*u.a + x*u.b; 14456952Sbostic z = t.b + lns2pi_lo; /* return t + lns2pi + p */ 14556952Sbostic z += p; z += lns2pi_hi; 14656952Sbostic z += t.a; 14756952Sbostic return (z); 14824600Szliu } 14956952Sbostic /* Good to < 1 ulp. (provably .90 ulp; .87 ulp on 1,000,000 runs.) 15056952Sbostic It also has correct monotonicity. 15156952Sbostic */ 15224600Szliu static double 15356952Sbostic small_lgam(x) 15456952Sbostic double x; 15524600Szliu { 15656952Sbostic int xi; 15756952Sbostic double y, z, t, r = 0, p, q; 15856952Sbostic struct Double rr; 15924600Szliu 16056952Sbostic /* Do nasty area near the minimum. No good for 1.25 < x < 2.5 */ 16156952Sbostic if (x < 2.0 - LEFT && x > 1.0 + RIGHT) { 16256952Sbostic t = x - 1.0; t -= x0; 16356952Sbostic z = t - x0_lo; 16456952Sbostic p = r0+z*(r1+z*(r2+z*(r3+z*(r4+z*r5)))); 16556952Sbostic q = s0+z*(s1+z*(s2+z*(s3+z*s4))); 16656952Sbostic r = t*(z*(p/q) - x0_lo) + a0_lo; 16756952Sbostic r += .5*t*t; r += a0_hi; 16856952Sbostic return (r); 16924600Szliu } 17056952Sbostic xi = (x + .5); 17156952Sbostic y = x - xi; 17256952Sbostic rr.a = rr.b = 0; 17356952Sbostic if (y < -LEFT) { /* necessary for 2.5 < x < 2.72.. */ 17456952Sbostic t = y + (1.0 - x0); 17556952Sbostic z = t - x0_lo; 17656952Sbostic p = r0+z*(r1+z*(r2+z*(r3+z*(r4+z*r5)))); 17756952Sbostic q = s0+z*(s1+z*(s2+z*(s3+z*s4))); 17856952Sbostic r = t*(z*(p/q) - x0_lo) + a0_lo; 17956952Sbostic r += .5*t*t; 18056952Sbostic q = a0_hi; 18156952Sbostic printf("(0)q = %.18lg r = %.18lg\n", q, r); 18256952Sbostic } else { 18356952Sbostic p = y*(p0+y*(p1+y*(p2+y*(p3+y*(p4+y*(p5+y*p6)))))); 18456952Sbostic q = q0+y*(q1+y*(q2+y*(q3+y*(q4+y*(q5+y*q6))))); 18556952Sbostic r = p/q; 18656952Sbostic q = .5*y; 18756952Sbostic printf("(1)q = %.18lg r = %.18lg\n", q, r); 18824600Szliu } 18956952Sbostic printf("y = %lg, r = %.18lg\n", y, r); 19056952Sbostic z = 1.0; 19156952Sbostic switch (xi) { 19256952Sbostic case 6: z = (y + 5); 19356952Sbostic case 5: z *= (y + 4); 19456952Sbostic case 4: z *= (y + 3); 19556952Sbostic case 3: z *= (y + 2); 19656952Sbostic rr = log__D(z); 19756952Sbostic printf("%.21lg, %lg\n", rr.a, rr.b); 19856952Sbostic r += rr.b; q += r; 19956952Sbostic return(q + rr.a); 20056952Sbostic case 2: return (q + r); 20156952Sbostic 20256952Sbostic case 0: printf("r = %lg\n", r); 20356952Sbostic r -= log1p(x); printf("\t%lg\n", r); 20456952Sbostic default: rr = log__D(x); 20556952Sbostic r -= rr.b; printf("\t%lg\n", r); 20656952Sbostic } 20756952Sbostic if (q > .5 *rr.a) { 20856952Sbostic printf("q = %lg, rr = %lg, r = %lg\n", q, rr.a, r); 20956952Sbostic q -= rr.a; 21056952Sbostic return(r + q); 21156952Sbostic } else 21256952Sbostic printf("q = %lg, rr = %lg, r = %lg\n", q, rr.a, r); 21356952Sbostic return((r + q) - rr.a); 21424600Szliu } 21524600Szliu 21656952Sbostic #define lpi_hi 1.1447298858494001638 21756952Sbostic #define lpi_lo .0000000000000000102659511627078262 21856952Sbostic /* Error: within 3.5 ulp for x < 171. For large x, see lgamma. */ 21924600Szliu static double 22056952Sbostic neg_lgam(x) 22156952Sbostic double x; 22224600Szliu { 22356952Sbostic struct Double lg, lsine; 22456952Sbostic double y, z, one = 1.0, zero = 0.0; 22524600Szliu 22656952Sbostic z = floor(x + .5); 22756952Sbostic if (z == x) { 22856952Sbostic errno = EDOM; 22956952Sbostic return (one/zero); /* convention: G(-(integer)) -> +oo */ 23056952Sbostic } 23156952Sbostic y = ceil(x); 23256952Sbostic if (y*.5 == ceil(.5*y)) 23356952Sbostic signgam = -1; 23424600Szliu 23556952Sbostic x = -x; 23656952Sbostic z = fabs(x + z); /* 0 < z <= .5 */ 23756952Sbostic if (z < .25) 23856952Sbostic z = sin(M_PI*z); 23956952Sbostic else 24056952Sbostic z = cos(M_PI*(.5-z)); 24156952Sbostic z = -log(z*x/M_PI); 24256952Sbostic 24356952Sbostic if (x > 6.5) 24456952Sbostic y -= large_lgam(x); 24556952Sbostic else 24656952Sbostic y = -small_lgam (x); 24756952Sbostic return (y + z); 24824600Szliu } 249