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