Blame sysdeps/ieee754/dbl-64/e_lgamma_r.c

Packit 6c4009
/* @(#)er_lgamma.c 5.1 93/09/24 */
Packit 6c4009
/*
Packit 6c4009
 * ====================================================
Packit 6c4009
 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
Packit 6c4009
 *
Packit 6c4009
 * Developed at SunPro, a Sun Microsystems, Inc. business.
Packit 6c4009
 * Permission to use, copy, modify, and distribute this
Packit 6c4009
 * software is freely granted, provided that this notice
Packit 6c4009
 * is preserved.
Packit 6c4009
 * ====================================================
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
/* __ieee754_lgamma_r(x, signgamp)
Packit 6c4009
 * Reentrant version of the logarithm of the Gamma function
Packit 6c4009
 * with user provide pointer for the sign of Gamma(x).
Packit 6c4009
 *
Packit 6c4009
 * Method:
Packit 6c4009
 *   1. Argument Reduction for 0 < x <= 8
Packit 6c4009
 *	Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
Packit 6c4009
 *	reduce x to a number in [1.5,2.5] by
Packit 6c4009
 *		lgamma(1+s) = log(s) + lgamma(s)
Packit 6c4009
 *	for example,
Packit 6c4009
 *		lgamma(7.3) = log(6.3) + lgamma(6.3)
Packit 6c4009
 *			    = log(6.3*5.3) + lgamma(5.3)
Packit 6c4009
 *			    = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
Packit 6c4009
 *   2. Polynomial approximation of lgamma around its
Packit 6c4009
 *	minimun ymin=1.461632144968362245 to maintain monotonicity.
Packit 6c4009
 *	On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
Packit 6c4009
 *		Let z = x-ymin;
Packit 6c4009
 *		lgamma(x) = -1.214862905358496078218 + z^2*poly(z)
Packit 6c4009
 *	where
Packit 6c4009
 *		poly(z) is a 14 degree polynomial.
Packit 6c4009
 *   2. Rational approximation in the primary interval [2,3]
Packit 6c4009
 *	We use the following approximation:
Packit 6c4009
 *		s = x-2.0;
Packit 6c4009
 *		lgamma(x) = 0.5*s + s*P(s)/Q(s)
Packit 6c4009
 *	with accuracy
Packit 6c4009
 *		|P/Q - (lgamma(x)-0.5s)| < 2**-61.71
Packit 6c4009
 *	Our algorithms are based on the following observation
Packit 6c4009
 *
Packit 6c4009
 *                             zeta(2)-1    2    zeta(3)-1    3
Packit 6c4009
 * lgamma(2+s) = s*(1-Euler) + --------- * s  -  --------- * s  + ...
Packit 6c4009
 *                                 2                 3
Packit 6c4009
 *
Packit 6c4009
 *	where Euler = 0.5771... is the Euler constant, which is very
Packit 6c4009
 *	close to 0.5.
Packit 6c4009
 *
Packit 6c4009
 *   3. For x>=8, we have
Packit 6c4009
 *	lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
Packit 6c4009
 *	(better formula:
Packit 6c4009
 *	   lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
Packit 6c4009
 *	Let z = 1/x, then we approximation
Packit 6c4009
 *		f(z) = lgamma(x) - (x-0.5)(log(x)-1)
Packit 6c4009
 *	by
Packit 6c4009
 *				    3       5             11
Packit 6c4009
 *		w = w0 + w1*z + w2*z  + w3*z  + ... + w6*z
Packit 6c4009
 *	where
Packit 6c4009
 *		|w - f(z)| < 2**-58.74
Packit 6c4009
 *
Packit 6c4009
 *   4. For negative x, since (G is gamma function)
Packit 6c4009
 *		-x*G(-x)*G(x) = pi/sin(pi*x),
Packit 6c4009
 *	we have
Packit 6c4009
 *		G(x) = pi/(sin(pi*x)*(-x)*G(-x))
Packit 6c4009
 *	since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
Packit 6c4009
 *	Hence, for x<0, signgam = sign(sin(pi*x)) and
Packit 6c4009
 *		lgamma(x) = log(|Gamma(x)|)
Packit 6c4009
 *			  = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
Packit 6c4009
 *	Note: one should avoid compute pi*(-x) directly in the
Packit 6c4009
 *	      computation of sin(pi*(-x)).
Packit 6c4009
 *
Packit 6c4009
 *   5. Special Cases
Packit 6c4009
 *		lgamma(2+s) ~ s*(1-Euler) for tiny s
Packit 6c4009
 *		lgamma(1)=lgamma(2)=0
Packit 6c4009
 *		lgamma(x) ~ -log(x) for tiny x
Packit 6c4009
 *		lgamma(0) = lgamma(inf) = inf
Packit 6c4009
 *		lgamma(-integer) = +-inf
Packit 6c4009
 *
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
#include <math.h>
Packit 6c4009
#include <math-narrow-eval.h>
Packit 6c4009
#include <math_private.h>
Packit 6c4009
#include <libc-diag.h>
Packit 6c4009
Packit 6c4009
static const double
Packit 6c4009
two52=  4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
Packit 6c4009
half=  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
Packit 6c4009
one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
Packit 6c4009
pi  =  3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
Packit 6c4009
a0  =  7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */
Packit 6c4009
a1  =  3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */
Packit 6c4009
a2  =  6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */
Packit 6c4009
a3  =  2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */
Packit 6c4009
a4  =  7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */
Packit 6c4009
a5  =  2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */
Packit 6c4009
a6  =  1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */
Packit 6c4009
a7  =  5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */
Packit 6c4009
a8  =  2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */
Packit 6c4009
a9  =  1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */
Packit 6c4009
a10 =  2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */
Packit 6c4009
a11 =  4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */
Packit 6c4009
tc  =  1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */
Packit 6c4009
tf  = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */
Packit 6c4009
/* tt = -(tail of tf) */
Packit 6c4009
tt  = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */
Packit 6c4009
t0  =  4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */
Packit 6c4009
t1  = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */
Packit 6c4009
t2  =  6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */
Packit 6c4009
t3  = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */
Packit 6c4009
t4  =  1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */
Packit 6c4009
t5  = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */
Packit 6c4009
t6  =  6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */
Packit 6c4009
t7  = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */
Packit 6c4009
t8  =  2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */
Packit 6c4009
t9  = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */
Packit 6c4009
t10 =  8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */
Packit 6c4009
t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */
Packit 6c4009
t12 =  3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */
Packit 6c4009
t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */
Packit 6c4009
t14 =  3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */
Packit 6c4009
u0  = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
Packit 6c4009
u1  =  6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */
Packit 6c4009
u2  =  1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */
Packit 6c4009
u3  =  9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */
Packit 6c4009
u4  =  2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */
Packit 6c4009
u5  =  1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */
Packit 6c4009
v1  =  2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */
Packit 6c4009
v2  =  2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */
Packit 6c4009
v3  =  7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */
Packit 6c4009
v4  =  1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */
Packit 6c4009
v5  =  3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */
Packit 6c4009
s0  = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
Packit 6c4009
s1  =  2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */
Packit 6c4009
s2  =  3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */
Packit 6c4009
s3  =  1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */
Packit 6c4009
s4  =  2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */
Packit 6c4009
s5  =  1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */
Packit 6c4009
s6  =  3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */
Packit 6c4009
r1  =  1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */
Packit 6c4009
r2  =  7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */
Packit 6c4009
r3  =  1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */
Packit 6c4009
r4  =  1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */
Packit 6c4009
r5  =  7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */
Packit 6c4009
r6  =  7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */
Packit 6c4009
w0  =  4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */
Packit 6c4009
w1  =  8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */
Packit 6c4009
w2  = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */
Packit 6c4009
w3  =  7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */
Packit 6c4009
w4  = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */
Packit 6c4009
w5  =  8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */
Packit 6c4009
w6  = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */
Packit 6c4009
Packit 6c4009
static const double zero=  0.00000000000000000000e+00;
Packit 6c4009
Packit 6c4009
static double
Packit 6c4009
sin_pi(double x)
Packit 6c4009
{
Packit 6c4009
	double y,z;
Packit 6c4009
	int n,ix;
Packit 6c4009
Packit 6c4009
	GET_HIGH_WORD(ix,x);
Packit 6c4009
	ix &= 0x7fffffff;
Packit 6c4009
Packit 6c4009
	if(ix<0x3fd00000) return __sin(pi*x);
Packit 6c4009
	y = -x;		/* x is assume negative */
Packit 6c4009
Packit 6c4009
    /*
Packit 6c4009
     * argument reduction, make sure inexact flag not raised if input
Packit 6c4009
     * is an integer
Packit 6c4009
     */
Packit 6c4009
	z = __floor(y);
Packit 6c4009
	if(z!=y) {				/* inexact anyway */
Packit 6c4009
	    y  *= 0.5;
Packit 6c4009
	    y   = 2.0*(y - __floor(y));		/* y = |x| mod 2.0 */
Packit 6c4009
	    n   = (int) (y*4.0);
Packit 6c4009
	} else {
Packit 6c4009
	    if(ix>=0x43400000) {
Packit 6c4009
		y = zero; n = 0;                 /* y must be even */
Packit 6c4009
	    } else {
Packit 6c4009
		if(ix<0x43300000) z = y+two52;	/* exact */
Packit 6c4009
		GET_LOW_WORD(n,z);
Packit 6c4009
		n &= 1;
Packit 6c4009
		y  = n;
Packit 6c4009
		n<<= 2;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
	switch (n) {
Packit 6c4009
	    case 0:   y =  __sin(pi*y); break;
Packit 6c4009
	    case 1:
Packit 6c4009
	    case 2:   y =  __cos(pi*(0.5-y)); break;
Packit 6c4009
	    case 3:
Packit 6c4009
	    case 4:   y =  __sin(pi*(one-y)); break;
Packit 6c4009
	    case 5:
Packit 6c4009
	    case 6:   y = -__cos(pi*(y-1.5)); break;
Packit 6c4009
	    default:  y =  __sin(pi*(y-2.0)); break;
Packit 6c4009
	    }
Packit 6c4009
	return -y;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
double
Packit 6c4009
__ieee754_lgamma_r(double x, int *signgamp)
Packit 6c4009
{
Packit 6c4009
	double t,y,z,nadj,p,p1,p2,p3,q,r,w;
Packit 6c4009
	int i,hx,lx,ix;
Packit 6c4009
Packit 6c4009
	EXTRACT_WORDS(hx,lx,x);
Packit 6c4009
Packit 6c4009
    /* purge off +-inf, NaN, +-0, and negative arguments */
Packit 6c4009
	*signgamp = 1;
Packit 6c4009
	ix = hx&0x7fffffff;
Packit 6c4009
	if(__builtin_expect(ix>=0x7ff00000, 0)) return x*x;
Packit 6c4009
	if(__builtin_expect((ix|lx)==0, 0))
Packit 6c4009
	  {
Packit 6c4009
	    if (hx < 0)
Packit 6c4009
	      *signgamp = -1;
Packit 6c4009
	    return one/fabs(x);
Packit 6c4009
	  }
Packit 6c4009
	if(__builtin_expect(ix<0x3b900000, 0)) {
Packit 6c4009
	    /* |x|<2**-70, return -log(|x|) */
Packit 6c4009
	    if(hx<0) {
Packit 6c4009
		*signgamp = -1;
Packit 6c4009
		return -__ieee754_log(-x);
Packit 6c4009
	    } else return -__ieee754_log(x);
Packit 6c4009
	}
Packit 6c4009
	if(hx<0) {
Packit 6c4009
	    if(__builtin_expect(ix>=0x43300000, 0))
Packit 6c4009
		/* |x|>=2**52, must be -integer */
Packit 6c4009
		return fabs (x)/zero;
Packit 6c4009
	    if (x < -2.0 && x > -28.0)
Packit 6c4009
		return __lgamma_neg (x, signgamp);
Packit 6c4009
	    t = sin_pi(x);
Packit 6c4009
	    if(t==zero) return one/fabsf(t); /* -integer */
Packit 6c4009
	    nadj = __ieee754_log(pi/fabs(t*x));
Packit 6c4009
	    if(t
Packit 6c4009
	    x = -x;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
    /* purge off 1 and 2 */
Packit 6c4009
	if((((ix-0x3ff00000)|lx)==0)||(((ix-0x40000000)|lx)==0)) r = 0;
Packit 6c4009
    /* for x < 2.0 */
Packit 6c4009
	else if(ix<0x40000000) {
Packit 6c4009
	    if(ix<=0x3feccccc) {	/* lgamma(x) = lgamma(x+1)-log(x) */
Packit 6c4009
		r = -__ieee754_log(x);
Packit 6c4009
		if(ix>=0x3FE76944) {y = one-x; i= 0;}
Packit 6c4009
		else if(ix>=0x3FCDA661) {y= x-(tc-one); i=1;}
Packit 6c4009
		else {y = x; i=2;}
Packit 6c4009
	    } else {
Packit 6c4009
		r = zero;
Packit 6c4009
		if(ix>=0x3FFBB4C3) {y=2.0-x;i=0;} /* [1.7316,2] */
Packit 6c4009
		else if(ix>=0x3FF3B4C4) {y=x-tc;i=1;} /* [1.23,1.73] */
Packit 6c4009
		else {y=x-one;i=2;}
Packit 6c4009
	    }
Packit 6c4009
	    switch(i) {
Packit 6c4009
	      case 0:
Packit 6c4009
		z = y*y;
Packit 6c4009
		p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
Packit 6c4009
		p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
Packit 6c4009
		p  = y*p1+p2;
Packit 6c4009
		r  += (p-0.5*y); break;
Packit 6c4009
	      case 1:
Packit 6c4009
		z = y*y;
Packit 6c4009
		w = z*y;
Packit 6c4009
		p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12)));	/* parallel comp */
Packit 6c4009
		p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
Packit 6c4009
		p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
Packit 6c4009
		p  = z*p1-(tt-w*(p2+y*p3));
Packit 6c4009
		r += (tf + p); break;
Packit 6c4009
	      case 2:
Packit 6c4009
		p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
Packit 6c4009
		p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
Packit 6c4009
		r += (-0.5*y + p1/p2);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
	else if(ix<0x40200000) {			/* x < 8.0 */
Packit 6c4009
	    i = (int)x;
Packit 6c4009
	    t = zero;
Packit 6c4009
	    y = x-(double)i;
Packit 6c4009
	    p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
Packit 6c4009
	    q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
Packit 6c4009
	    r = half*y+p/q;
Packit 6c4009
	    z = one;	/* lgamma(1+s) = log(s) + lgamma(s) */
Packit 6c4009
	    switch(i) {
Packit 6c4009
	    case 7: z *= (y+6.0);	/* FALLTHRU */
Packit 6c4009
	    case 6: z *= (y+5.0);	/* FALLTHRU */
Packit 6c4009
	    case 5: z *= (y+4.0);	/* FALLTHRU */
Packit 6c4009
	    case 4: z *= (y+3.0);	/* FALLTHRU */
Packit 6c4009
	    case 3: z *= (y+2.0);	/* FALLTHRU */
Packit 6c4009
		    r += __ieee754_log(z); break;
Packit 6c4009
	    }
Packit 6c4009
    /* 8.0 <= x < 2**58 */
Packit 6c4009
	} else if (ix < 0x43900000) {
Packit 6c4009
	    t = __ieee754_log(x);
Packit 6c4009
	    z = one/x;
Packit 6c4009
	    y = z*z;
Packit 6c4009
	    w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
Packit 6c4009
	    r = (x-half)*(t-one)+w;
Packit 6c4009
	} else
Packit 6c4009
    /* 2**58 <= x <= inf */
Packit 6c4009
	    r =  math_narrow_eval (x*(__ieee754_log(x)-one));
Packit 6c4009
	/* NADJ is set for negative arguments but not otherwise,
Packit 6c4009
	   resulting in warnings that it may be used uninitialized
Packit 6c4009
	   although in the cases where it is used it has always been
Packit 6c4009
	   set.  */
Packit 6c4009
	DIAG_PUSH_NEEDS_COMMENT;
Packit 6c4009
	DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wmaybe-uninitialized");
Packit 6c4009
	if(hx<0) r = nadj - r;
Packit 6c4009
	DIAG_POP_NEEDS_COMMENT;
Packit 6c4009
	return r;
Packit 6c4009
}
Packit 6c4009
strong_alias (__ieee754_lgamma_r, __lgamma_r_finite)