1*48402Sbostic /*- 2*48402Sbostic * Copyright (c) 1985 The Regents of the University of California. 3*48402Sbostic * All rights reserved. 4*48402Sbostic * 5*48402Sbostic * %sccs.include.proprietary.c% 634120Sbostic */ 734120Sbostic 824600Szliu #ifndef lint 9*48402Sbostic static char sccsid[] = "@(#)lgamma.c 5.4 (Berkeley) 04/20/91"; 1034120Sbostic #endif /* not lint */ 1124600Szliu 1224600Szliu /* 1324600Szliu C program for floating point log Gamma function 1424600Szliu 1524705Selefunt lgamma(x) computes the log of the absolute 1624600Szliu value of the Gamma function. 1724600Szliu The sign of the Gamma function is returned in the 1824600Szliu external quantity signgam. 1924600Szliu 2024600Szliu The coefficients for expansion around zero 2124600Szliu are #5243 from Hart & Cheney; for expansion 2224600Szliu around infinity they are #5404. 2324600Szliu 2424600Szliu Calls log, floor and sin. 2524600Szliu */ 2624600Szliu 2735679Sbostic #include "mathimpl.h" 2831853Szliu #if defined(vax)||defined(tahoe) 2924600Szliu #include <errno.h> 3031853Szliu #endif /* defined(vax)||defined(tahoe) */ 3135679Sbostic 3224600Szliu int signgam = 0; 3335679Sbostic static const double goobie = 0.9189385332046727417803297; /* log(2*pi)/2 */ 3435679Sbostic static const double pi = 3.1415926535897932384626434; 3524600Szliu 3624600Szliu #define M 6 3724600Szliu #define N 8 3835679Sbostic static const double p1[] = { 3924600Szliu 0.83333333333333101837e-1, 4024600Szliu -.277777777735865004e-2, 4124600Szliu 0.793650576493454e-3, 4224600Szliu -.5951896861197e-3, 4324600Szliu 0.83645878922e-3, 4424600Szliu -.1633436431e-2, 4524600Szliu }; 4635679Sbostic static const double p2[] = { 4724600Szliu -.42353689509744089647e5, 4824600Szliu -.20886861789269887364e5, 4924600Szliu -.87627102978521489560e4, 5024600Szliu -.20085274013072791214e4, 5124600Szliu -.43933044406002567613e3, 5224600Szliu -.50108693752970953015e2, 5324600Szliu -.67449507245925289918e1, 5424600Szliu 0.0, 5524600Szliu }; 5635679Sbostic static const double q2[] = { 5724600Szliu -.42353689509744090010e5, 5824600Szliu -.29803853309256649932e4, 5924600Szliu 0.99403074150827709015e4, 6024600Szliu -.15286072737795220248e4, 6124600Szliu -.49902852662143904834e3, 6224600Szliu 0.18949823415702801641e3, 6324600Szliu -.23081551524580124562e2, 6424600Szliu 0.10000000000000000000e1, 6524600Szliu }; 6624600Szliu 6735679Sbostic static double pos(), neg(), asym(); 6835679Sbostic 6924600Szliu double 7024705Selefunt lgamma(arg) 7124600Szliu double arg; 7224600Szliu { 7324600Szliu 7424600Szliu signgam = 1.; 7524600Szliu if(arg <= 0.) return(neg(arg)); 7624600Szliu if(arg > 8.) return(asym(arg)); 7724600Szliu return(log(pos(arg))); 7824600Szliu } 7924600Szliu 8024600Szliu static double 8124600Szliu asym(arg) 8224600Szliu double arg; 8324600Szliu { 8424600Szliu double n, argsq; 8524600Szliu int i; 8624600Szliu 8724600Szliu argsq = 1./(arg*arg); 8824600Szliu for(n=0,i=M-1; i>=0; i--){ 8924600Szliu n = n*argsq + p1[i]; 9024600Szliu } 9124600Szliu return((arg-.5)*log(arg) - arg + goobie + n/arg); 9224600Szliu } 9324600Szliu 9424600Szliu static double 9524600Szliu neg(arg) 9624600Szliu double arg; 9724600Szliu { 9824600Szliu double t; 9924600Szliu 10024600Szliu arg = -arg; 10124600Szliu /* 10224600Szliu * to see if arg were a true integer, the old code used the 10324600Szliu * mathematically correct observation: 10424600Szliu * sin(n*pi) = 0 <=> n is an integer. 10524600Szliu * but in finite precision arithmetic, sin(n*PI) will NEVER 10624600Szliu * be zero simply because n*PI is a rational number. hence 10724600Szliu * it failed to work with our newer, more accurate sin() 10824600Szliu * which uses true pi to do the argument reduction... 10924600Szliu * temp = sin(pi*arg); 11024600Szliu */ 11124600Szliu t = floor(arg); 11224600Szliu if (arg - t > 0.5e0) 11324600Szliu t += 1.e0; /* t := integer nearest arg */ 11431853Szliu #if defined(vax)||defined(tahoe) 11524600Szliu if (arg == t) { 11624600Szliu return(infnan(ERANGE)); /* +INF */ 11724600Szliu } 11831853Szliu #endif /* defined(vax)||defined(tahoe) */ 11924600Szliu signgam = (int) (t - 2*floor(t/2)); /* signgam = 1 if t was odd, */ 12024600Szliu /* 0 if t was even */ 12124600Szliu signgam = signgam - 1 + signgam; /* signgam = 1 if t was odd, */ 12224600Szliu /* -1 if t was even */ 12324600Szliu t = arg - t; /* -0.5 <= t <= 0.5 */ 12424600Szliu if (t < 0.e0) { 12524600Szliu t = -t; 12624600Szliu signgam = -signgam; 12724600Szliu } 12824600Szliu return(-log(arg*pos(arg)*sin(pi*t)/pi)); 12924600Szliu } 13024600Szliu 13124600Szliu static double 13224600Szliu pos(arg) 13324600Szliu double arg; 13424600Szliu { 13524600Szliu double n, d, s; 13624600Szliu register i; 13724600Szliu 13824600Szliu if(arg < 2.) return(pos(arg+1.)/arg); 13924600Szliu if(arg > 3.) return((arg-1.)*pos(arg-1.)); 14024600Szliu 14124600Szliu s = arg - 2.; 14224600Szliu for(n=0,d=0,i=N-1; i>=0; i--){ 14324600Szliu n = n*s + p2[i]; 14424600Szliu d = d*s + q2[i]; 14524600Szliu } 14624600Szliu return(n/d); 14724600Szliu } 148