148402Sbostic /*- 256957Sbostic * Copyright (c) 1992 The Regents of the University of California. 348402Sbostic * All rights reserved. 448402Sbostic * 556957Sbostic * %sccs.include.redist.c% 634120Sbostic */ 734120Sbostic 824600Szliu #ifndef lint 9*57128Smcilroy static char sccsid[] = "@(#)lgamma.c 5.7 (Berkeley) 12/14/92"; 1034120Sbostic #endif /* not lint */ 1124600Szliu 1256952Sbostic #include <math.h> 1356952Sbostic #include <errno.h> 1424600Szliu 1556952Sbostic #include "mathimpl.h" 1624600Szliu 17*57128Smcilroy /* Log gamma function. 18*57128Smcilroy * Error: x > 0 error < 1.3ulp. 19*57128Smcilroy * x > 4, error < 1ulp. 20*57128Smcilroy * x > 9, error < .6ulp. 21*57128Smcilroy * x < 0, all bets are off. 22*57128Smcilroy * Method: 23*57128Smcilroy * x > 6: 24*57128Smcilroy * Use the asymptotic expansion (Stirling's Formula) 25*57128Smcilroy * 0 < x < 6: 26*57128Smcilroy * Use gamma(x+1) = x*gamma(x) 27*57128Smcilroy * Use rational approximation in 28*57128Smcilroy * the range 1.2, 2.5 29*57128Smcilroy * x < 0: 30*57128Smcilroy * Use the reflection formula, 31*57128Smcilroy * G(1-x)G(x) = PI/sin(PI*x) 32*57128Smcilroy * Special values: 33*57128Smcilroy * non-positive integer returns +Inf. 34*57128Smcilroy * NaN returns NaN 3524600Szliu */ 3656952Sbostic #if defined(vax) || defined(tahoe) 37*57128Smcilroy /* double and float have same size exponent field */ 38*57128Smcilroy #define TRUNC(x) (double) (float) (x) 39*57128Smcilroy #define _IEEE 0 4056952Sbostic #else 41*57128Smcilroy #define TRUNC(x) *(((int *) &x) + 1) &= 0xf8000000 42*57128Smcilroy #define _IEEE 1 43*57128Smcilroy #define infnan(x) (zero/zero) 4456952Sbostic #endif 4535679Sbostic 46*57128Smcilroy extern double log1p(double); 47*57128Smcilroy static double small_lgam(double); 48*57128Smcilroy static double large_lgam(double); 49*57128Smcilroy static double neg_lgam(double); 50*57128Smcilroy static double zero = 0.0, one = 1.0; 51*57128Smcilroy int signgam; 5224600Szliu 53*57128Smcilroy #define lns2pi .418938533204672741780329736405 5456952Sbostic #define UNDERFL (1e-1020 * 1e-1020) 5556952Sbostic 56*57128Smcilroy #define LEFT (1.0 - (x0 + .25)) 57*57128Smcilroy #define RIGHT (x0 - .218) 58*57128Smcilroy /* 59*57128Smcilroy /* Constants for approximation in [1.244,1.712] 60*57128Smcilroy */ 61*57128Smcilroy #define x0 0.461632144968362356785 62*57128Smcilroy #define x0_lo -.000000000000000015522348162858676890521 63*57128Smcilroy #define a0_hi -0.12148629128932952880859 64*57128Smcilroy #define a0_lo .0000000007534799204229502 65*57128Smcilroy #define r0 -2.771227512955130520e-002 66*57128Smcilroy #define r1 -2.980729795228150847e-001 67*57128Smcilroy #define r2 -3.257411333183093394e-001 68*57128Smcilroy #define r3 -1.126814387531706041e-001 69*57128Smcilroy #define r4 -1.129130057170225562e-002 70*57128Smcilroy #define r5 -2.259650588213369095e-005 71*57128Smcilroy #define s0 1.714457160001714442e+000 72*57128Smcilroy #define s1 2.786469504618194648e+000 73*57128Smcilroy #define s2 1.564546365519179805e+000 74*57128Smcilroy #define s3 3.485846389981109850e-001 75*57128Smcilroy #define s4 2.467759345363656348e-002 76*57128Smcilroy /* 77*57128Smcilroy * Constants for approximation in [1.71, 2.5] 78*57128Smcilroy */ 79*57128Smcilroy #define a1_hi 4.227843350984671344505727574870e-01 80*57128Smcilroy #define a1_lo 4.670126436531227189e-18 81*57128Smcilroy #define p0 3.224670334241133695662995251041e-01 82*57128Smcilroy #define p1 3.569659696950364669021382724168e-01 83*57128Smcilroy #define p2 1.342918716072560025853732668111e-01 84*57128Smcilroy #define p3 1.950702176409779831089963408886e-02 85*57128Smcilroy #define p4 8.546740251667538090796227834289e-04 86*57128Smcilroy #define q0 1.000000000000000444089209850062e+00 87*57128Smcilroy #define q1 1.315850076960161985084596381057e+00 88*57128Smcilroy #define q2 6.274644311862156431658377186977e-01 89*57128Smcilroy #define q3 1.304706631926259297049597307705e-01 90*57128Smcilroy #define q4 1.102815279606722369265536798366e-02 91*57128Smcilroy #define q5 2.512690594856678929537585620579e-04 92*57128Smcilroy #define q6 -1.003597548112371003358107325598e-06 93*57128Smcilroy /* 94*57128Smcilroy * Stirling's Formula, adjusted for equal-ripple. x in [6,Inf]. 95*57128Smcilroy */ 96*57128Smcilroy #define pb0 .0833333333333333148296162562474 97*57128Smcilroy #define pb1 -.00277777777774548123579378966497 98*57128Smcilroy #define pb2 .000793650778754435631476282786423 99*57128Smcilroy #define pb3 -.000595235082566672847950717262222 100*57128Smcilroy #define pb4 .000841428560346653702135821806252 101*57128Smcilroy #define pb5 -.00189773526463879200348872089421 102*57128Smcilroy #define pb6 .00569394463439411649408050664078 103*57128Smcilroy #define pb7 -.0144705562421428915453880392761 10456952Sbostic 10524600Szliu double 106*57128Smcilroy lgamma(double x) 10724600Szliu { 10856952Sbostic double r; 10956952Sbostic signgam = 1; 110*57128Smcilroy if (!finite(x)) 111*57128Smcilroy if (_IEEE) 112*57128Smcilroy return (x+x); 113*57128Smcilroy else return (infnan(EDOM)); 114*57128Smcilroy 11556952Sbostic if (x > 6 + RIGHT) { 11656952Sbostic r = large_lgam(x); 11756952Sbostic return (r); 118*57128Smcilroy } else if (x > 1e-16) 11956952Sbostic return (small_lgam(x)); 120*57128Smcilroy else if (x > -1e-16) { 12156952Sbostic if (x < 0) 12256952Sbostic signgam = -1, x = -x; 12356952Sbostic return (-log(x)); 12456952Sbostic } else 12556952Sbostic return (neg_lgam(x)); 12624600Szliu } 12724600Szliu 12824600Szliu static double 129*57128Smcilroy large_lgam(double x) 13024600Szliu { 13156952Sbostic double z, p, x1; 13224600Szliu int i; 13356952Sbostic struct Double t, u, v; 134*57128Smcilroy u = log__D(x); 135*57128Smcilroy u.a -= 1.0; 136*57128Smcilroy if (x > 1e15) { 137*57128Smcilroy v.a = x - 0.5; 138*57128Smcilroy TRUNC(v.a); 139*57128Smcilroy v.b = (x - v.a) - 0.5; 140*57128Smcilroy t.a = u.a*v.a; 141*57128Smcilroy t.b = x*u.b + v.b*u.a; 142*57128Smcilroy if (_IEEE == 0 && !finite(t.a)) 143*57128Smcilroy return(infnan(ERANGE)); 144*57128Smcilroy return(t.a + t.b); 145*57128Smcilroy } 146*57128Smcilroy x1 = 1./x; 147*57128Smcilroy z = x1*x1; 148*57128Smcilroy p = pb0+z*(pb1+z*(pb2+z*(pb3+z*(pb4+z*(pb5+z*(pb6+z*pb7)))))); 149*57128Smcilroy /* error in approximation = 2.8e-19 */ 15024600Szliu 151*57128Smcilroy p = p*x1; /* error < 2.3e-18 absolute */ 152*57128Smcilroy /* 0 < p < 1/64 (at x = 5.5) */ 153*57128Smcilroy x = x - 0.5; 154*57128Smcilroy TRUNC(v.a); /* truncate v.a to 26 bits. */ 15556952Sbostic v.b = x - v.a; 15656952Sbostic t.a = v.a*u.a; /* t = (x-.5)*(log(x)-1) */ 157*57128Smcilroy t.b = v.b*u.a + z*u.b; 158*57128Smcilroy t.b += p; t.b += lns2pi; /* return t + lns2pi + p */ 159*57128Smcilroy return (t.a + t.b); 16024600Szliu } 161*57128Smcilroy 16224600Szliu static double 163*57128Smcilroy small_lgam(double x) 16424600Szliu { 165*57128Smcilroy int x_int; 166*57128Smcilroy double y, z, t, r = 0, p, q, hi, lo; 16756952Sbostic struct Double rr; 168*57128Smcilroy x_int = (x + .5); 169*57128Smcilroy y = x - x_int; 170*57128Smcilroy if (x_int <= 2 && y > RIGHT) { 171*57128Smcilroy t = y - x0; 172*57128Smcilroy y--; x_int++; 173*57128Smcilroy goto CONTINUE; 174*57128Smcilroy } else if (y < -LEFT) { 175*57128Smcilroy t = y +(1.0-x0); 176*57128Smcilroy CONTINUE: 17756952Sbostic z = t - x0_lo; 17856952Sbostic p = r0+z*(r1+z*(r2+z*(r3+z*(r4+z*r5)))); 17956952Sbostic q = s0+z*(s1+z*(s2+z*(s3+z*s4))); 180*57128Smcilroy r = t*(z*(p/q) - x0_lo); 181*57128Smcilroy t = .5*t*t; 182*57128Smcilroy z = 1.0; 183*57128Smcilroy switch (x_int) { 184*57128Smcilroy case 6: z = (y + 5); 185*57128Smcilroy case 5: z *= (y + 4); 186*57128Smcilroy case 4: z *= (y + 3); 187*57128Smcilroy case 3: z *= (y + 2); 188*57128Smcilroy rr = log__D(z); 189*57128Smcilroy rr.b += a0_lo; rr.a += a0_hi; 190*57128Smcilroy return(((r+rr.b)+t+rr.a)); 191*57128Smcilroy case 2: return(((r+a0_lo)+t)+a0_hi); 192*57128Smcilroy case 0: r -= log1p(x); 193*57128Smcilroy default: rr = log__D(x); 194*57128Smcilroy rr.a -= a0_hi; rr.b -= a0_lo; 195*57128Smcilroy return(((r - rr.b) + t) - rr.a); 196*57128Smcilroy } 19756952Sbostic } else { 198*57128Smcilroy p = p0+y*(p1+y*(p2+y*(p3+y*p4))); 19956952Sbostic q = q0+y*(q1+y*(q2+y*(q3+y*(q4+y*(q5+y*q6))))); 200*57128Smcilroy p = p*(y/q); 201*57128Smcilroy t = (double)(float) y; 202*57128Smcilroy z = y-t; 203*57128Smcilroy hi = (double)(float) (p+a1_hi); 204*57128Smcilroy lo = a1_hi - hi; lo += p; lo += a1_lo; 205*57128Smcilroy r = lo*y + z*hi; /* q + r = y*(a0+p/q) */ 206*57128Smcilroy q = hi*t; 207*57128Smcilroy z = 1.0; 208*57128Smcilroy switch (x_int) { 209*57128Smcilroy case 6: z = (y + 5); 210*57128Smcilroy case 5: z *= (y + 4); 211*57128Smcilroy case 4: z *= (y + 3); 212*57128Smcilroy case 3: z *= (y + 2); 213*57128Smcilroy rr = log__D(z); 214*57128Smcilroy r += rr.b; r += q; 215*57128Smcilroy return(rr.a + r); 216*57128Smcilroy case 2: return (q+ r); 217*57128Smcilroy case 0: rr = log__D(x); 218*57128Smcilroy r -= rr.b; r -= log1p(x); 219*57128Smcilroy r += q; r-= rr.a; 220*57128Smcilroy return(r); 221*57128Smcilroy default: rr = log__D(x); 222*57128Smcilroy r -= rr.b; 223*57128Smcilroy q -= rr.a; 224*57128Smcilroy return (r+q); 225*57128Smcilroy } 22624600Szliu } 22724600Szliu } 22824600Szliu 22956952Sbostic #define lpi_hi 1.1447298858494001638 23056952Sbostic #define lpi_lo .0000000000000000102659511627078262 23156952Sbostic /* Error: within 3.5 ulp for x < 171. For large x, see lgamma. */ 23224600Szliu static double 233*57128Smcilroy neg_lgam(double x) 23424600Szliu { 23556952Sbostic double y, z, one = 1.0, zero = 0.0; 23624600Szliu 23756952Sbostic z = floor(x + .5); 238*57128Smcilroy if (z == x) { /* convention: G(-(integer)) -> +Inf */ 239*57128Smcilroy if (_IEEE) 240*57128Smcilroy return (one/zero); 241*57128Smcilroy else 242*57128Smcilroy return (infnan(ERANGE)); 24356952Sbostic } 244*57128Smcilroy y = .5*ceil(x); 245*57128Smcilroy if (y == ceil(y)) 24656952Sbostic signgam = -1; 24756952Sbostic x = -x; 24856952Sbostic z = fabs(x + z); /* 0 < z <= .5 */ 24956952Sbostic if (z < .25) 25056952Sbostic z = sin(M_PI*z); 25156952Sbostic else 252*57128Smcilroy z = cos(M_PI*(0.5-z)); 25356952Sbostic z = -log(z*x/M_PI); 25456952Sbostic 255*57128Smcilroy if (x > 6. + RIGHT) 25656952Sbostic y -= large_lgam(x); 25756952Sbostic else 25856952Sbostic y = -small_lgam (x); 25956952Sbostic return (y + z); 26024600Szliu } 261