134120Sbostic /* 234120Sbostic * Copyright (c) 1985 Regents of the University of California. 334120Sbostic * All rights reserved. The Berkeley software License Agreement 434120Sbostic * specifies the terms and conditions for redistribution. 534120Sbostic */ 634120Sbostic 724600Szliu #ifndef lint 8*35679Sbostic static char sccsid[] = "@(#)lgamma.c 5.3 (Berkeley) 09/22/88"; 934120Sbostic #endif /* not lint */ 1024600Szliu 1124600Szliu /* 1224600Szliu C program for floating point log Gamma function 1324600Szliu 1424705Selefunt lgamma(x) computes the log of the absolute 1524600Szliu value of the Gamma function. 1624600Szliu The sign of the Gamma function is returned in the 1724600Szliu external quantity signgam. 1824600Szliu 1924600Szliu The coefficients for expansion around zero 2024600Szliu are #5243 from Hart & Cheney; for expansion 2124600Szliu around infinity they are #5404. 2224600Szliu 2324600Szliu Calls log, floor and sin. 2424600Szliu */ 2524600Szliu 26*35679Sbostic #include "mathimpl.h" 2731853Szliu #if defined(vax)||defined(tahoe) 2824600Szliu #include <errno.h> 2931853Szliu #endif /* defined(vax)||defined(tahoe) */ 30*35679Sbostic 3124600Szliu int signgam = 0; 32*35679Sbostic static const double goobie = 0.9189385332046727417803297; /* log(2*pi)/2 */ 33*35679Sbostic static const double pi = 3.1415926535897932384626434; 3424600Szliu 3524600Szliu #define M 6 3624600Szliu #define N 8 37*35679Sbostic static const double p1[] = { 3824600Szliu 0.83333333333333101837e-1, 3924600Szliu -.277777777735865004e-2, 4024600Szliu 0.793650576493454e-3, 4124600Szliu -.5951896861197e-3, 4224600Szliu 0.83645878922e-3, 4324600Szliu -.1633436431e-2, 4424600Szliu }; 45*35679Sbostic static const double p2[] = { 4624600Szliu -.42353689509744089647e5, 4724600Szliu -.20886861789269887364e5, 4824600Szliu -.87627102978521489560e4, 4924600Szliu -.20085274013072791214e4, 5024600Szliu -.43933044406002567613e3, 5124600Szliu -.50108693752970953015e2, 5224600Szliu -.67449507245925289918e1, 5324600Szliu 0.0, 5424600Szliu }; 55*35679Sbostic static const double q2[] = { 5624600Szliu -.42353689509744090010e5, 5724600Szliu -.29803853309256649932e4, 5824600Szliu 0.99403074150827709015e4, 5924600Szliu -.15286072737795220248e4, 6024600Szliu -.49902852662143904834e3, 6124600Szliu 0.18949823415702801641e3, 6224600Szliu -.23081551524580124562e2, 6324600Szliu 0.10000000000000000000e1, 6424600Szliu }; 6524600Szliu 66*35679Sbostic static double pos(), neg(), asym(); 67*35679Sbostic 6824600Szliu double 6924705Selefunt lgamma(arg) 7024600Szliu double arg; 7124600Szliu { 7224600Szliu 7324600Szliu signgam = 1.; 7424600Szliu if(arg <= 0.) return(neg(arg)); 7524600Szliu if(arg > 8.) return(asym(arg)); 7624600Szliu return(log(pos(arg))); 7724600Szliu } 7824600Szliu 7924600Szliu static double 8024600Szliu asym(arg) 8124600Szliu double arg; 8224600Szliu { 8324600Szliu double n, argsq; 8424600Szliu int i; 8524600Szliu 8624600Szliu argsq = 1./(arg*arg); 8724600Szliu for(n=0,i=M-1; i>=0; i--){ 8824600Szliu n = n*argsq + p1[i]; 8924600Szliu } 9024600Szliu return((arg-.5)*log(arg) - arg + goobie + n/arg); 9124600Szliu } 9224600Szliu 9324600Szliu static double 9424600Szliu neg(arg) 9524600Szliu double arg; 9624600Szliu { 9724600Szliu double t; 9824600Szliu 9924600Szliu arg = -arg; 10024600Szliu /* 10124600Szliu * to see if arg were a true integer, the old code used the 10224600Szliu * mathematically correct observation: 10324600Szliu * sin(n*pi) = 0 <=> n is an integer. 10424600Szliu * but in finite precision arithmetic, sin(n*PI) will NEVER 10524600Szliu * be zero simply because n*PI is a rational number. hence 10624600Szliu * it failed to work with our newer, more accurate sin() 10724600Szliu * which uses true pi to do the argument reduction... 10824600Szliu * temp = sin(pi*arg); 10924600Szliu */ 11024600Szliu t = floor(arg); 11124600Szliu if (arg - t > 0.5e0) 11224600Szliu t += 1.e0; /* t := integer nearest arg */ 11331853Szliu #if defined(vax)||defined(tahoe) 11424600Szliu if (arg == t) { 11524600Szliu return(infnan(ERANGE)); /* +INF */ 11624600Szliu } 11731853Szliu #endif /* defined(vax)||defined(tahoe) */ 11824600Szliu signgam = (int) (t - 2*floor(t/2)); /* signgam = 1 if t was odd, */ 11924600Szliu /* 0 if t was even */ 12024600Szliu signgam = signgam - 1 + signgam; /* signgam = 1 if t was odd, */ 12124600Szliu /* -1 if t was even */ 12224600Szliu t = arg - t; /* -0.5 <= t <= 0.5 */ 12324600Szliu if (t < 0.e0) { 12424600Szliu t = -t; 12524600Szliu signgam = -signgam; 12624600Szliu } 12724600Szliu return(-log(arg*pos(arg)*sin(pi*t)/pi)); 12824600Szliu } 12924600Szliu 13024600Szliu static double 13124600Szliu pos(arg) 13224600Szliu double arg; 13324600Szliu { 13424600Szliu double n, d, s; 13524600Szliu register i; 13624600Szliu 13724600Szliu if(arg < 2.) return(pos(arg+1.)/arg); 13824600Szliu if(arg > 3.) return((arg-1.)*pos(arg-1.)); 13924600Szliu 14024600Szliu s = arg - 2.; 14124600Szliu for(n=0,d=0,i=N-1; i>=0; i--){ 14224600Szliu n = n*s + p2[i]; 14324600Szliu d = d*s + q2[i]; 14424600Szliu } 14524600Szliu return(n/d); 14624600Szliu } 147