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*57129Smcilroy static char sccsid[] = "@(#)lgamma.c 5.8 (Berkeley) 12/14/92"; 1034120Sbostic #endif /* not lint */ 1124600Szliu 1256952Sbostic #include <math.h> 1356952Sbostic #include <errno.h> 1424600Szliu 1556952Sbostic #include "mathimpl.h" 1624600Szliu 1757128Smcilroy /* Log gamma function. 1857128Smcilroy * Error: x > 0 error < 1.3ulp. 1957128Smcilroy * x > 4, error < 1ulp. 2057128Smcilroy * x > 9, error < .6ulp. 2157128Smcilroy * x < 0, all bets are off. 2257128Smcilroy * Method: 2357128Smcilroy * x > 6: 2457128Smcilroy * Use the asymptotic expansion (Stirling's Formula) 2557128Smcilroy * 0 < x < 6: 2657128Smcilroy * Use gamma(x+1) = x*gamma(x) 2757128Smcilroy * Use rational approximation in 2857128Smcilroy * the range 1.2, 2.5 2957128Smcilroy * x < 0: 3057128Smcilroy * Use the reflection formula, 3157128Smcilroy * G(1-x)G(x) = PI/sin(PI*x) 3257128Smcilroy * Special values: 3357128Smcilroy * non-positive integer returns +Inf. 3457128Smcilroy * NaN returns NaN 3524600Szliu */ 3656952Sbostic #if defined(vax) || defined(tahoe) 3757128Smcilroy /* double and float have same size exponent field */ 3857128Smcilroy #define TRUNC(x) (double) (float) (x) 3957128Smcilroy #define _IEEE 0 4056952Sbostic #else 4157128Smcilroy #define TRUNC(x) *(((int *) &x) + 1) &= 0xf8000000 4257128Smcilroy #define _IEEE 1 4357128Smcilroy #define infnan(x) (zero/zero) 4456952Sbostic #endif 4535679Sbostic 4657128Smcilroy extern double log1p(double); 4757128Smcilroy static double small_lgam(double); 4857128Smcilroy static double large_lgam(double); 4957128Smcilroy static double neg_lgam(double); 5057128Smcilroy static double zero = 0.0, one = 1.0; 5157128Smcilroy int signgam; 5224600Szliu 5357128Smcilroy #define lns2pi .418938533204672741780329736405 5456952Sbostic #define UNDERFL (1e-1020 * 1e-1020) 5556952Sbostic 5657128Smcilroy #define LEFT (1.0 - (x0 + .25)) 5757128Smcilroy #define RIGHT (x0 - .218) 5857128Smcilroy /* 5957128Smcilroy /* Constants for approximation in [1.244,1.712] 6057128Smcilroy */ 6157128Smcilroy #define x0 0.461632144968362356785 6257128Smcilroy #define x0_lo -.000000000000000015522348162858676890521 6357128Smcilroy #define a0_hi -0.12148629128932952880859 6457128Smcilroy #define a0_lo .0000000007534799204229502 6557128Smcilroy #define r0 -2.771227512955130520e-002 6657128Smcilroy #define r1 -2.980729795228150847e-001 6757128Smcilroy #define r2 -3.257411333183093394e-001 6857128Smcilroy #define r3 -1.126814387531706041e-001 6957128Smcilroy #define r4 -1.129130057170225562e-002 7057128Smcilroy #define r5 -2.259650588213369095e-005 7157128Smcilroy #define s0 1.714457160001714442e+000 7257128Smcilroy #define s1 2.786469504618194648e+000 7357128Smcilroy #define s2 1.564546365519179805e+000 7457128Smcilroy #define s3 3.485846389981109850e-001 7557128Smcilroy #define s4 2.467759345363656348e-002 7657128Smcilroy /* 7757128Smcilroy * Constants for approximation in [1.71, 2.5] 7857128Smcilroy */ 7957128Smcilroy #define a1_hi 4.227843350984671344505727574870e-01 8057128Smcilroy #define a1_lo 4.670126436531227189e-18 8157128Smcilroy #define p0 3.224670334241133695662995251041e-01 8257128Smcilroy #define p1 3.569659696950364669021382724168e-01 8357128Smcilroy #define p2 1.342918716072560025853732668111e-01 8457128Smcilroy #define p3 1.950702176409779831089963408886e-02 8557128Smcilroy #define p4 8.546740251667538090796227834289e-04 8657128Smcilroy #define q0 1.000000000000000444089209850062e+00 8757128Smcilroy #define q1 1.315850076960161985084596381057e+00 8857128Smcilroy #define q2 6.274644311862156431658377186977e-01 8957128Smcilroy #define q3 1.304706631926259297049597307705e-01 9057128Smcilroy #define q4 1.102815279606722369265536798366e-02 9157128Smcilroy #define q5 2.512690594856678929537585620579e-04 9257128Smcilroy #define q6 -1.003597548112371003358107325598e-06 9357128Smcilroy /* 9457128Smcilroy * Stirling's Formula, adjusted for equal-ripple. x in [6,Inf]. 9557128Smcilroy */ 9657128Smcilroy #define pb0 .0833333333333333148296162562474 9757128Smcilroy #define pb1 -.00277777777774548123579378966497 9857128Smcilroy #define pb2 .000793650778754435631476282786423 9957128Smcilroy #define pb3 -.000595235082566672847950717262222 10057128Smcilroy #define pb4 .000841428560346653702135821806252 10157128Smcilroy #define pb5 -.00189773526463879200348872089421 10257128Smcilroy #define pb6 .00569394463439411649408050664078 10357128Smcilroy #define pb7 -.0144705562421428915453880392761 10456952Sbostic 10524600Szliu double 10657128Smcilroy lgamma(double x) 10724600Szliu { 10856952Sbostic double r; 10956952Sbostic signgam = 1; 11057128Smcilroy if (!finite(x)) 11157128Smcilroy if (_IEEE) 11257128Smcilroy return (x+x); 11357128Smcilroy else return (infnan(EDOM)); 11457128Smcilroy 11556952Sbostic if (x > 6 + RIGHT) { 11656952Sbostic r = large_lgam(x); 11756952Sbostic return (r); 11857128Smcilroy } else if (x > 1e-16) 11956952Sbostic return (small_lgam(x)); 12057128Smcilroy 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 12957128Smcilroy large_lgam(double x) 13024600Szliu { 13156952Sbostic double z, p, x1; 13224600Szliu int i; 13356952Sbostic struct Double t, u, v; 13457128Smcilroy u = log__D(x); 13557128Smcilroy u.a -= 1.0; 13657128Smcilroy if (x > 1e15) { 13757128Smcilroy v.a = x - 0.5; 13857128Smcilroy TRUNC(v.a); 13957128Smcilroy v.b = (x - v.a) - 0.5; 14057128Smcilroy t.a = u.a*v.a; 14157128Smcilroy t.b = x*u.b + v.b*u.a; 14257128Smcilroy if (_IEEE == 0 && !finite(t.a)) 14357128Smcilroy return(infnan(ERANGE)); 14457128Smcilroy return(t.a + t.b); 14557128Smcilroy } 14657128Smcilroy x1 = 1./x; 14757128Smcilroy z = x1*x1; 14857128Smcilroy p = pb0+z*(pb1+z*(pb2+z*(pb3+z*(pb4+z*(pb5+z*(pb6+z*pb7)))))); 14957128Smcilroy /* error in approximation = 2.8e-19 */ 15024600Szliu 15157128Smcilroy p = p*x1; /* error < 2.3e-18 absolute */ 15257128Smcilroy /* 0 < p < 1/64 (at x = 5.5) */ 15357128Smcilroy x = x - 0.5; 15457128Smcilroy 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*57129Smcilroy t.b = v.b*u.a + x*u.b; 15857128Smcilroy t.b += p; t.b += lns2pi; /* return t + lns2pi + p */ 15957128Smcilroy return (t.a + t.b); 16024600Szliu } 16157128Smcilroy 16224600Szliu static double 16357128Smcilroy small_lgam(double x) 16424600Szliu { 16557128Smcilroy int x_int; 16657128Smcilroy double y, z, t, r = 0, p, q, hi, lo; 16756952Sbostic struct Double rr; 16857128Smcilroy x_int = (x + .5); 16957128Smcilroy y = x - x_int; 17057128Smcilroy if (x_int <= 2 && y > RIGHT) { 17157128Smcilroy t = y - x0; 17257128Smcilroy y--; x_int++; 17357128Smcilroy goto CONTINUE; 17457128Smcilroy } else if (y < -LEFT) { 17557128Smcilroy t = y +(1.0-x0); 17657128Smcilroy 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))); 18057128Smcilroy r = t*(z*(p/q) - x0_lo); 18157128Smcilroy t = .5*t*t; 18257128Smcilroy z = 1.0; 18357128Smcilroy switch (x_int) { 18457128Smcilroy case 6: z = (y + 5); 18557128Smcilroy case 5: z *= (y + 4); 18657128Smcilroy case 4: z *= (y + 3); 18757128Smcilroy case 3: z *= (y + 2); 18857128Smcilroy rr = log__D(z); 18957128Smcilroy rr.b += a0_lo; rr.a += a0_hi; 19057128Smcilroy return(((r+rr.b)+t+rr.a)); 19157128Smcilroy case 2: return(((r+a0_lo)+t)+a0_hi); 19257128Smcilroy case 0: r -= log1p(x); 19357128Smcilroy default: rr = log__D(x); 19457128Smcilroy rr.a -= a0_hi; rr.b -= a0_lo; 19557128Smcilroy return(((r - rr.b) + t) - rr.a); 19657128Smcilroy } 19756952Sbostic } else { 19857128Smcilroy 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))))); 20057128Smcilroy p = p*(y/q); 20157128Smcilroy t = (double)(float) y; 20257128Smcilroy z = y-t; 20357128Smcilroy hi = (double)(float) (p+a1_hi); 20457128Smcilroy lo = a1_hi - hi; lo += p; lo += a1_lo; 20557128Smcilroy r = lo*y + z*hi; /* q + r = y*(a0+p/q) */ 20657128Smcilroy q = hi*t; 20757128Smcilroy z = 1.0; 20857128Smcilroy switch (x_int) { 20957128Smcilroy case 6: z = (y + 5); 21057128Smcilroy case 5: z *= (y + 4); 21157128Smcilroy case 4: z *= (y + 3); 21257128Smcilroy case 3: z *= (y + 2); 21357128Smcilroy rr = log__D(z); 21457128Smcilroy r += rr.b; r += q; 21557128Smcilroy return(rr.a + r); 21657128Smcilroy case 2: return (q+ r); 21757128Smcilroy case 0: rr = log__D(x); 21857128Smcilroy r -= rr.b; r -= log1p(x); 21957128Smcilroy r += q; r-= rr.a; 22057128Smcilroy return(r); 22157128Smcilroy default: rr = log__D(x); 22257128Smcilroy r -= rr.b; 22357128Smcilroy q -= rr.a; 22457128Smcilroy return (r+q); 22557128Smcilroy } 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 23357128Smcilroy neg_lgam(double x) 23424600Szliu { 23556952Sbostic double y, z, one = 1.0, zero = 0.0; 23624600Szliu 23756952Sbostic z = floor(x + .5); 23857128Smcilroy if (z == x) { /* convention: G(-(integer)) -> +Inf */ 23957128Smcilroy if (_IEEE) 24057128Smcilroy return (one/zero); 24157128Smcilroy else 24257128Smcilroy return (infnan(ERANGE)); 24356952Sbostic } 24457128Smcilroy y = .5*ceil(x); 24557128Smcilroy 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 25257128Smcilroy z = cos(M_PI*(0.5-z)); 25356952Sbostic z = -log(z*x/M_PI); 25456952Sbostic 25557128Smcilroy if (x > 6. + RIGHT) 25656952Sbostic y -= large_lgam(x); 25756952Sbostic else 25856952Sbostic y = -small_lgam (x); 25956952Sbostic return (y + z); 26024600Szliu } 261