124600Szliu #ifndef lint 2*24705Selefunt static char sccsid[] = 3*24705Selefunt "@(#)lgamma.c 4.4 (Berkeley) 9/11/85; 1.2 (ucb.elefunt) 09/11/85"; 424600Szliu #endif not lint 524600Szliu 624600Szliu /* 724600Szliu C program for floating point log Gamma function 824600Szliu 9*24705Selefunt lgamma(x) computes the log of the absolute 1024600Szliu value of the Gamma function. 1124600Szliu The sign of the Gamma function is returned in the 1224600Szliu external quantity signgam. 1324600Szliu 1424600Szliu The coefficients for expansion around zero 1524600Szliu are #5243 from Hart & Cheney; for expansion 1624600Szliu around infinity they are #5404. 1724600Szliu 1824600Szliu Calls log, floor and sin. 1924600Szliu */ 2024600Szliu 2124600Szliu #include <math.h> 2224600Szliu #ifdef VAX 2324600Szliu #include <errno.h> 2424600Szliu #endif 2524600Szliu int signgam = 0; 2624600Szliu static double goobie = 0.9189385332046727417803297; /* log(2*pi)/2 */ 2724600Szliu static double pi = 3.1415926535897932384626434; 2824600Szliu 2924600Szliu #define M 6 3024600Szliu #define N 8 3124600Szliu static double p1[] = { 3224600Szliu 0.83333333333333101837e-1, 3324600Szliu -.277777777735865004e-2, 3424600Szliu 0.793650576493454e-3, 3524600Szliu -.5951896861197e-3, 3624600Szliu 0.83645878922e-3, 3724600Szliu -.1633436431e-2, 3824600Szliu }; 3924600Szliu static double p2[] = { 4024600Szliu -.42353689509744089647e5, 4124600Szliu -.20886861789269887364e5, 4224600Szliu -.87627102978521489560e4, 4324600Szliu -.20085274013072791214e4, 4424600Szliu -.43933044406002567613e3, 4524600Szliu -.50108693752970953015e2, 4624600Szliu -.67449507245925289918e1, 4724600Szliu 0.0, 4824600Szliu }; 4924600Szliu static double q2[] = { 5024600Szliu -.42353689509744090010e5, 5124600Szliu -.29803853309256649932e4, 5224600Szliu 0.99403074150827709015e4, 5324600Szliu -.15286072737795220248e4, 5424600Szliu -.49902852662143904834e3, 5524600Szliu 0.18949823415702801641e3, 5624600Szliu -.23081551524580124562e2, 5724600Szliu 0.10000000000000000000e1, 5824600Szliu }; 5924600Szliu 6024600Szliu double 61*24705Selefunt lgamma(arg) 6224600Szliu double arg; 6324600Szliu { 6424600Szliu double log(), pos(), neg(), asym(); 6524600Szliu 6624600Szliu signgam = 1.; 6724600Szliu if(arg <= 0.) return(neg(arg)); 6824600Szliu if(arg > 8.) return(asym(arg)); 6924600Szliu return(log(pos(arg))); 7024600Szliu } 7124600Szliu 7224600Szliu static double 7324600Szliu asym(arg) 7424600Szliu double arg; 7524600Szliu { 7624600Szliu double log(); 7724600Szliu double n, argsq; 7824600Szliu int i; 7924600Szliu 8024600Szliu argsq = 1./(arg*arg); 8124600Szliu for(n=0,i=M-1; i>=0; i--){ 8224600Szliu n = n*argsq + p1[i]; 8324600Szliu } 8424600Szliu return((arg-.5)*log(arg) - arg + goobie + n/arg); 8524600Szliu } 8624600Szliu 8724600Szliu static double 8824600Szliu neg(arg) 8924600Szliu double arg; 9024600Szliu { 9124600Szliu double t; 9224600Szliu double log(), sin(), floor(), pos(); 9324600Szliu 9424600Szliu arg = -arg; 9524600Szliu /* 9624600Szliu * to see if arg were a true integer, the old code used the 9724600Szliu * mathematically correct observation: 9824600Szliu * sin(n*pi) = 0 <=> n is an integer. 9924600Szliu * but in finite precision arithmetic, sin(n*PI) will NEVER 10024600Szliu * be zero simply because n*PI is a rational number. hence 10124600Szliu * it failed to work with our newer, more accurate sin() 10224600Szliu * which uses true pi to do the argument reduction... 10324600Szliu * temp = sin(pi*arg); 10424600Szliu */ 10524600Szliu t = floor(arg); 10624600Szliu if (arg - t > 0.5e0) 10724600Szliu t += 1.e0; /* t := integer nearest arg */ 10824600Szliu #ifdef VAX 10924600Szliu if (arg == t) { 11024600Szliu extern double infnan(); 11124600Szliu return(infnan(ERANGE)); /* +INF */ 11224600Szliu } 11324600Szliu #endif 11424600Szliu signgam = (int) (t - 2*floor(t/2)); /* signgam = 1 if t was odd, */ 11524600Szliu /* 0 if t was even */ 11624600Szliu signgam = signgam - 1 + signgam; /* signgam = 1 if t was odd, */ 11724600Szliu /* -1 if t was even */ 11824600Szliu t = arg - t; /* -0.5 <= t <= 0.5 */ 11924600Szliu if (t < 0.e0) { 12024600Szliu t = -t; 12124600Szliu signgam = -signgam; 12224600Szliu } 12324600Szliu return(-log(arg*pos(arg)*sin(pi*t)/pi)); 12424600Szliu } 12524600Szliu 12624600Szliu static double 12724600Szliu pos(arg) 12824600Szliu double arg; 12924600Szliu { 13024600Szliu double n, d, s; 13124600Szliu register i; 13224600Szliu 13324600Szliu if(arg < 2.) return(pos(arg+1.)/arg); 13424600Szliu if(arg > 3.) return((arg-1.)*pos(arg-1.)); 13524600Szliu 13624600Szliu s = arg - 2.; 13724600Szliu for(n=0,d=0,i=N-1; i>=0; i--){ 13824600Szliu n = n*s + p2[i]; 13924600Szliu d = d*s + q2[i]; 14024600Szliu } 14124600Szliu return(n/d); 14224600Szliu } 143