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