1*34120Sbostic /*
2*34120Sbostic  * Copyright (c) 1985 Regents of the University of California.
3*34120Sbostic  * All rights reserved.  The Berkeley software License Agreement
4*34120Sbostic  * specifies the terms and conditions for redistribution.
5*34120Sbostic  */
6*34120Sbostic 
724600Szliu #ifndef lint
8*34120Sbostic static char sccsid[] = "@(#)lgamma.c	5.2 (Berkeley) 04/29/88";
9*34120Sbostic #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 
2624600Szliu #include <math.h>
2731853Szliu #if defined(vax)||defined(tahoe)
2824600Szliu #include <errno.h>
2931853Szliu #endif	/* defined(vax)||defined(tahoe) */
3024600Szliu int	signgam = 0;
3124600Szliu static double goobie	= 0.9189385332046727417803297;	/* log(2*pi)/2 */
3224600Szliu static double pi	= 3.1415926535897932384626434;
3324600Szliu 
3424600Szliu #define M 6
3524600Szliu #define N 8
3624600Szliu static double p1[] = {
3724600Szliu 	0.83333333333333101837e-1,
3824600Szliu 	-.277777777735865004e-2,
3924600Szliu 	0.793650576493454e-3,
4024600Szliu 	-.5951896861197e-3,
4124600Szliu 	0.83645878922e-3,
4224600Szliu 	-.1633436431e-2,
4324600Szliu };
4424600Szliu static double p2[] = {
4524600Szliu 	-.42353689509744089647e5,
4624600Szliu 	-.20886861789269887364e5,
4724600Szliu 	-.87627102978521489560e4,
4824600Szliu 	-.20085274013072791214e4,
4924600Szliu 	-.43933044406002567613e3,
5024600Szliu 	-.50108693752970953015e2,
5124600Szliu 	-.67449507245925289918e1,
5224600Szliu 	0.0,
5324600Szliu };
5424600Szliu static double q2[] = {
5524600Szliu 	-.42353689509744090010e5,
5624600Szliu 	-.29803853309256649932e4,
5724600Szliu 	0.99403074150827709015e4,
5824600Szliu 	-.15286072737795220248e4,
5924600Szliu 	-.49902852662143904834e3,
6024600Szliu 	0.18949823415702801641e3,
6124600Szliu 	-.23081551524580124562e2,
6224600Szliu 	0.10000000000000000000e1,
6324600Szliu };
6424600Szliu 
6524600Szliu double
6624705Selefunt lgamma(arg)
6724600Szliu double arg;
6824600Szliu {
6924600Szliu 	double log(), pos(), neg(), asym();
7024600Szliu 
7124600Szliu 	signgam = 1.;
7224600Szliu 	if(arg <= 0.) return(neg(arg));
7324600Szliu 	if(arg > 8.) return(asym(arg));
7424600Szliu 	return(log(pos(arg)));
7524600Szliu }
7624600Szliu 
7724600Szliu static double
7824600Szliu asym(arg)
7924600Szliu double arg;
8024600Szliu {
8124600Szliu 	double log();
8224600Szliu 	double n, argsq;
8324600Szliu 	int i;
8424600Szliu 
8524600Szliu 	argsq = 1./(arg*arg);
8624600Szliu 	for(n=0,i=M-1; i>=0; i--){
8724600Szliu 		n = n*argsq + p1[i];
8824600Szliu 	}
8924600Szliu 	return((arg-.5)*log(arg) - arg + goobie + n/arg);
9024600Szliu }
9124600Szliu 
9224600Szliu static double
9324600Szliu neg(arg)
9424600Szliu double arg;
9524600Szliu {
9624600Szliu 	double t;
9724600Szliu 	double log(), sin(), floor(), pos();
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 	    extern double infnan();
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