148402Sbostic /*-
2*56957Sbostic  * Copyright (c) 1992 The Regents of the University of California.
348402Sbostic  * All rights reserved.
448402Sbostic  *
5*56957Sbostic  * %sccs.include.redist.c%
634120Sbostic  */
734120Sbostic 
824600Szliu #ifndef lint
9*56957Sbostic static char sccsid[] = "@(#)lgamma.c	5.6 (Berkeley) 12/02/92";
1034120Sbostic #endif /* not lint */
1124600Szliu 
1256952Sbostic #include <math.h>
1356952Sbostic #include <errno.h>
1424600Szliu 
1556952Sbostic #include "mathimpl.h"
1624600Szliu 
1756952Sbostic /* TRUNC sets trailing bits in a floating-point number to zero.
1856952Sbostic  * ptrx points to the second half of the floating-point number.
1956952Sbostic  * x1 is a temporary variable.
2024600Szliu */
2124600Szliu 
2256952Sbostic #if defined(vax) || defined(tahoe)
2356952Sbostic #define LSHFT_PLUS_1	(134217728.+1.)
2456952Sbostic #define TRUNC(x, dummy, x1) x1 = x*LSHFT_PLUS_1, x -= x1, x += x1
2556952Sbostic #else
2656952Sbostic #define MASK 0xf8000000
2756952Sbostic #define TRUNC(x, ptrx, dummy) *ptrx &= MASK
2856952Sbostic #endif
2935679Sbostic 
3056952Sbostic #define x0	0.461632144968362356785
3156952Sbostic #define x0_lo	-.000000000000000015522348162858676890521
3256952Sbostic #define a0_hi	-0.12148629053584961146
3356952Sbostic #define a0_lo	3.07435645275902737e-18
3456952Sbostic #define LEFT	(1.0 - (x0 + .25))
3556952Sbostic #define RIGHT	(x0 - .218)
3656952Sbostic #define lns2pi_hi 0.418945312500000
3756952Sbostic #define lns2pi_lo -.000006779295327258219670263595
3824600Szliu 
3956952Sbostic #define UNDERFL (1e-1020 * 1e-1020)
4056952Sbostic int signgam;
4156952Sbostic 
4256952Sbostic #define r0	-0.02771227512955130520
4356952Sbostic #define r1	-0.2980729795228150847
4456952Sbostic #define r2	-0.3257411333183093394
4556952Sbostic #define r3	-0.1126814387531706041
4656952Sbostic #define r4	-0.01129130057170225562
4756952Sbostic #define r5	-2.259650588213369095e-05
4856952Sbostic #define s0	1.7144571600017144419
4956952Sbostic #define s1	2.7864695046181946481
5056952Sbostic #define s2	1.5645463655191798047
5156952Sbostic #define s3	0.34858463899811098496
5256952Sbostic #define s4	0.024677593453636563481
5356952Sbostic 
5456952Sbostic #define p0     -7.721566490153286087127140e-02
5556952Sbostic #define p1	2.077324848654884653970785e-01
5656952Sbostic #define p2	3.474331160945523535787194e-01
5756952Sbostic #define p3	1.724375677840324429295524e-01
5856952Sbostic #define p4	3.546181984297784658205969e-02
5956952Sbostic #define p5	2.866163630124151557532506e-03
6056952Sbostic #define p6	6.143168512963655570532770e-05
6156952Sbostic #define q0	1.000000000000000000000000e+00
6256952Sbostic #define q1	1.485897307300750567469226e+00
6356952Sbostic #define q2	8.336064915387758261556045e-01
6456952Sbostic #define q3	2.185469782512070977585556e-01
6556952Sbostic #define q4	2.671060746990048983840354e-02
6656952Sbostic #define q5	1.296631961305647947057711e-03
6756952Sbostic #define q6	1.484566091079246905938151e-05
6856952Sbostic 
6956952Sbostic #define NP2 8
7056952Sbostic double P2[] = {
7156952Sbostic .0833333333333333148296162562474,
7256952Sbostic -.00277777777774548123579378966497,
7356952Sbostic .000793650778754435631476282786423,
7456952Sbostic -.000595235082566672847950717262222,
7556952Sbostic .000841428560346653702135821806252,
7656952Sbostic -.00189773526463879200348872089421,
7756952Sbostic .00569394463439411649408050664078,
7856952Sbostic -.0144705562421428915453880392761
7924600Szliu };
8024600Szliu 
8156952Sbostic static double neg_lgam __P((double));
8256952Sbostic static double small_lgam __P((double));
8356952Sbostic static double large_lgam __P((double));
8435679Sbostic 
8524600Szliu double
8656952Sbostic lgamma(x)
8756952Sbostic 	double x;
8824600Szliu {
8956952Sbostic 	double zero = 0.0, one = 1.0;
9056952Sbostic 	double r;
9156952Sbostic 	signgam = 1;
9256952Sbostic 	if (!finite(x)) {
9356952Sbostic 		errno = EDOM;
9456952Sbostic 		if (x < 0)
9556952Sbostic 			x = -x;
9656952Sbostic 		else if (x > 0)
9756952Sbostic 			errno = ERANGE;
9856952Sbostic 		return (x);
9956952Sbostic 	}
10056952Sbostic 	if (x > 6 + RIGHT) {
10156952Sbostic 		if (x > 1.0e20)
10256952Sbostic 			return (x*(log(x)-one));
10356952Sbostic 		r = large_lgam(x);
10456952Sbostic 		return (r);
10556952Sbostic 	} else if (x > 1e-17)
10656952Sbostic 		return (small_lgam(x));
10756952Sbostic 	else if(x > -1e-17) {
10856952Sbostic 		if (x < 0)
10956952Sbostic 			signgam = -1, x = -x;
11056952Sbostic 		return (-log(x));
11156952Sbostic 	} else
11256952Sbostic 		return (neg_lgam(x));
11324600Szliu }
11424600Szliu 
11556952Sbostic /* Accurate to max(ulp(1/128) absolute, 2^-75 relative) error. */
11624600Szliu static double
11756952Sbostic large_lgam(x)
11856952Sbostic 	double x;
11924600Szliu {
12056952Sbostic 	double z, p, x1;
12124600Szliu 	int i;
12256952Sbostic 	long *pva, *pua;
12356952Sbostic 	struct Double t, u, v;
12456952Sbostic 	pua = (long *) &u.a, pua++;
12556952Sbostic 	pva = (long *) &v.a, pva++;
12656952Sbostic 	z = 1.0/(x*x);
12756952Sbostic 	for (p = P2[i = NP2-1]; --i >= 0;)
12856952Sbostic 		p = P2[i] + p*z;	/* error in approximation = 2.8e-18 */
12924600Szliu 
13056952Sbostic 	p = p/x;			/* ulp = 1.7e-18; error < 1.6ulp */
13156952Sbostic 					/* 0 < frac < 1/64 (at x = 5.5) */
13256952Sbostic 	t = log__D(x);
13356952Sbostic 	t.a -= 1.0;
13456952Sbostic 	u.a = t.a + t.b;
13556952Sbostic 	TRUNC (u.a, pua, x1);		/* truncate u.a */
13656952Sbostic 	u.b = (t.a - u.a);
13756952Sbostic 	u.b += t.b;
13856952Sbostic 	x -= .5;
13956952Sbostic 	v.a = x;
14056952Sbostic 	TRUNC(v.a, pva, x1);		/* truncate v.a */
14156952Sbostic 	v.b = x - v.a;
14256952Sbostic 	t.a = v.a*u.a;			/* t = (x-.5)*(log(x)-1) */
14356952Sbostic 	t.b = v.b*u.a + x*u.b;
14456952Sbostic 	z = t.b + lns2pi_lo;		/* return t + lns2pi + p */
14556952Sbostic 	z += p; z += lns2pi_hi;
14656952Sbostic 	z += t.a;
14756952Sbostic 	return (z);
14824600Szliu }
14956952Sbostic /* Good to < 1 ulp.  (provably .90 ulp; .87 ulp on 1,000,000 runs.)
15056952Sbostic    It also has correct monotonicity.
15156952Sbostic  */
15224600Szliu static double
15356952Sbostic small_lgam(x)
15456952Sbostic 	double x;
15524600Szliu {
15656952Sbostic 	int xi;
15756952Sbostic 	double y, z, t, r = 0, p, q;
15856952Sbostic 	struct Double rr;
15924600Szliu 
16056952Sbostic 	/* Do nasty area near the minimum.  No good for 1.25 < x < 2.5 */
16156952Sbostic 	if (x < 2.0 - LEFT && x > 1.0 + RIGHT) {
16256952Sbostic 		t = x - 1.0; t -= x0;
16356952Sbostic 		z = t - x0_lo;
16456952Sbostic 		p = r0+z*(r1+z*(r2+z*(r3+z*(r4+z*r5))));
16556952Sbostic 		q = s0+z*(s1+z*(s2+z*(s3+z*s4)));
16656952Sbostic 		r = t*(z*(p/q) - x0_lo) + a0_lo;
16756952Sbostic 		r += .5*t*t; r += a0_hi;
16856952Sbostic 		return (r);
16924600Szliu 	}
17056952Sbostic 	xi = (x + .5);
17156952Sbostic 	y = x - xi;
17256952Sbostic 	rr.a = rr.b = 0;
17356952Sbostic 	if (y < -LEFT) {	/* necessary for 2.5 < x < 2.72.. */
17456952Sbostic 		t = y + (1.0 - x0);
17556952Sbostic 		z = t - x0_lo;
17656952Sbostic 		p = r0+z*(r1+z*(r2+z*(r3+z*(r4+z*r5))));
17756952Sbostic 		q = s0+z*(s1+z*(s2+z*(s3+z*s4)));
17856952Sbostic 		r = t*(z*(p/q) - x0_lo) + a0_lo;
17956952Sbostic 		r += .5*t*t;
18056952Sbostic 		q = a0_hi;
18156952Sbostic 		printf("(0)q = %.18lg r = %.18lg\n", q, r);
18256952Sbostic 	} else {
18356952Sbostic 		p = y*(p0+y*(p1+y*(p2+y*(p3+y*(p4+y*(p5+y*p6))))));
18456952Sbostic 		q = q0+y*(q1+y*(q2+y*(q3+y*(q4+y*(q5+y*q6)))));
18556952Sbostic 		r = p/q;
18656952Sbostic 		q = .5*y;
18756952Sbostic 		printf("(1)q = %.18lg r = %.18lg\n", q, r);
18824600Szliu 	}
18956952Sbostic 	printf("y = %lg, r = %.18lg\n", y, r);
19056952Sbostic 	z = 1.0;
19156952Sbostic 	switch (xi) {
19256952Sbostic 	case 6:	z  = (y + 5);
19356952Sbostic 	case 5:	z *= (y + 4);
19456952Sbostic 	case 4:	z *= (y + 3);
19556952Sbostic 	case 3:	z *= (y + 2);
19656952Sbostic 		rr = log__D(z);
19756952Sbostic 		printf("%.21lg, %lg\n", rr.a, rr.b);
19856952Sbostic 		r += rr.b; q += r;
19956952Sbostic 		return(q + rr.a);
20056952Sbostic 	case 2:	return (q + r);
20156952Sbostic 
20256952Sbostic 	case 0: printf("r = %lg\n", r);
20356952Sbostic 		r -= log1p(x); printf("\t%lg\n", r);
20456952Sbostic 	default: rr = log__D(x);
20556952Sbostic 		r -= rr.b; printf("\t%lg\n", r);
20656952Sbostic 	}
20756952Sbostic 	if (q > .5 *rr.a) {
20856952Sbostic 		printf("q = %lg, rr = %lg, r = %lg\n", q, rr.a, r);
20956952Sbostic 		q -= rr.a;
21056952Sbostic 		return(r + q);
21156952Sbostic 	} else
21256952Sbostic 		printf("q = %lg, rr = %lg, r = %lg\n", q, rr.a, r);
21356952Sbostic 		return((r + q) - rr.a);
21424600Szliu }
21524600Szliu 
21656952Sbostic #define lpi_hi 1.1447298858494001638
21756952Sbostic #define lpi_lo .0000000000000000102659511627078262
21856952Sbostic /* Error: within 3.5 ulp for x < 171.  For large x, see lgamma. */
21924600Szliu static double
22056952Sbostic neg_lgam(x)
22156952Sbostic 	double x;
22224600Szliu {
22356952Sbostic 	struct Double lg, lsine;
22456952Sbostic 	double y, z, one = 1.0, zero = 0.0;
22524600Szliu 
22656952Sbostic 	z = floor(x + .5);
22756952Sbostic 	if (z == x) {
22856952Sbostic 		errno = EDOM;
22956952Sbostic 		return (one/zero);	/* convention: G(-(integer)) -> +oo */
23056952Sbostic 	}
23156952Sbostic 	y = ceil(x);
23256952Sbostic 	if (y*.5 == ceil(.5*y))
23356952Sbostic 		signgam = -1;
23424600Szliu 
23556952Sbostic 	x = -x;
23656952Sbostic 	z = fabs(x + z);	/* 0 < z <= .5 */
23756952Sbostic 	if (z < .25)
23856952Sbostic 		z = sin(M_PI*z);
23956952Sbostic 	else
24056952Sbostic 		z = cos(M_PI*(.5-z));
24156952Sbostic 	z = -log(z*x/M_PI);
24256952Sbostic 
24356952Sbostic 	if (x > 6.5)
24456952Sbostic 		y -= large_lgam(x);
24556952Sbostic 	else
24656952Sbostic 		y = -small_lgam (x);
24756952Sbostic 	return (y + z);
24824600Szliu }
249