2 /* @(#)er_lgamma.c 5.1 93/09/24 */
4 * ====================================================
5 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
7 * Developed at SunPro, a Sun Microsystems, Inc. business.
8 * Permission to use, copy, modify, and distribute this
9 * software is freely granted, provided that this notice
11 * ====================================================
17 <<gamma>>, <<gammaf>>, <<lgamma>>, <<lgammaf>>, <<gamma_r>>,
18 <<gammaf_r>>, <<lgamma_r>>, <<lgammaf_r>>---logarithmic gamma
39 double gamma(double <[x]>);
40 float gammaf(float <[x]>);
41 double lgamma(double <[x]>);
42 float lgammaf(float <[x]>);
43 double gamma_r(double <[x]>, int *<[signgamp]>);
44 float gammaf_r(float <[x]>, int *<[signgamp]>);
45 double lgamma_r(double <[x]>, int *<[signgamp]>);
46 float lgammaf_r(float <[x]>, int *<[signgamp]>);
51 $\mit ln\bigl(\Gamma(x)\bigr)$,
53 the natural logarithm of the gamma function of <[x]>. The gamma function
54 (<<exp(gamma(<[x]>))>>) is a generalization of factorial, and retains
57 <<exp(gamma(N))>> is equivalent to <<N*exp(gamma(N-1))>>.
60 $\mit \Gamma(N)\equiv N\times\Gamma(N-1)$.
62 Accordingly, the results of the gamma function itself grow very
63 quickly. <<gamma>> is defined as
65 $\mit ln\bigl(\Gamma(x)\bigr)$ rather than simply $\mit \Gamma(x)$
68 the natural log of the gamma function, rather than the gamma function
71 to extend the useful range of results representable.
73 The sign of the result is returned in the global variable <<signgam>>,
74 which is declared in math.h.
76 <<gammaf>> performs the same calculation as <<gamma>>, but uses and
77 returns <<float>> values.
79 <<lgamma>> and <<lgammaf>> are alternate names for <<gamma>> and
80 <<gammaf>>. The use of <<lgamma>> instead of <<gamma>> is a reminder
81 that these functions compute the log of the gamma function, rather
82 than the gamma function itself.
84 The functions <<gamma_r>>, <<gammaf_r>>, <<lgamma_r>>, and
85 <<lgammaf_r>> are just like <<gamma>>, <<gammaf>>, <<lgamma>>, and
86 <<lgammaf>>, respectively, but take an additional argument. This
87 additional argument is a pointer to an integer. This additional
88 argument is used to return the sign of the result, and the global
89 variable <<signgam>> is not used. These functions may be used for
90 reentrant calls (but they will still set the global variable <<errno>>
94 Normally, the computed result is returned.
96 When <[x]> is a nonpositive integer, <<gamma>> returns <<HUGE_VAL>>
97 and <<errno>> is set to <<EDOM>>. If the result overflows, <<gamma>>
98 returns <<HUGE_VAL>> and <<errno>> is set to <<ERANGE>>.
101 Neither <<gamma>> nor <<gammaf>> is ANSI C. */
103 /* lgamma_r(x, signgamp)
104 * Reentrant version of the logarithm of the Gamma function
105 * with user provide pointer for the sign of Gamma(x).
108 * 1. Argument Reduction for 0 < x <= 8
109 * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
110 * reduce x to a number in [1.5,2.5] by
111 * lgamma(1+s) = log(s) + lgamma(s)
113 * lgamma(7.3) = log(6.3) + lgamma(6.3)
114 * = log(6.3*5.3) + lgamma(5.3)
115 * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
116 * 2. Polynomial approximation of lgamma around its
117 * minimun ymin=1.461632144968362245 to maintain monotonicity.
118 * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
120 * lgamma(x) = -1.214862905358496078218 + z^2*poly(z)
122 * poly(z) is a 14 degree polynomial.
123 * 2. Rational approximation in the primary interval [2,3]
124 * We use the following approximation:
126 * lgamma(x) = 0.5*s + s*P(s)/Q(s)
128 * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71
129 * Our algorithms are based on the following observation
131 * zeta(2)-1 2 zeta(3)-1 3
132 * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ...
135 * where Euler = 0.5771... is the Euler constant, which is very
138 * 3. For x>=8, we have
139 * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
141 * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
142 * Let z = 1/x, then we approximation
143 * f(z) = lgamma(x) - (x-0.5)(log(x)-1)
146 * w = w0 + w1*z + w2*z + w3*z + ... + w6*z
148 * |w - f(z)| < 2**-58.74
150 * 4. For negative x, since (G is gamma function)
151 * -x*G(-x)*G(x) = pi/sin(pi*x),
153 * G(x) = pi/(sin(pi*x)*(-x)*G(-x))
154 * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
155 * Hence, for x<0, signgam = sign(sin(pi*x)) and
156 * lgamma(x) = log(|Gamma(x)|)
157 * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
158 * Note: one should avoid compute pi*(-x) directly in the
159 * computation of sin(pi*(-x)).
162 * lgamma(2+s) ~ s*(1-Euler) for tiny s
163 * lgamma(1)=lgamma(2)=0
164 * lgamma(x) ~ -log(x) for tiny x
165 * lgamma(0) = lgamma(inf) = inf
166 * lgamma(-integer) = +-inf
177 two52
= 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
178 half
= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
179 one
= 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
180 pi
= 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
181 a0
= 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */
182 a1
= 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */
183 a2
= 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */
184 a3
= 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */
185 a4
= 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */
186 a5
= 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */
187 a6
= 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */
188 a7
= 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */
189 a8
= 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */
190 a9
= 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */
191 a10
= 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */
192 a11
= 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */
193 tc
= 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */
194 tf
= -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */
195 /* tt = -(tail of tf) */
196 tt
= -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */
197 t0
= 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */
198 t1
= -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */
199 t2
= 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */
200 t3
= -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */
201 t4
= 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */
202 t5
= -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */
203 t6
= 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */
204 t7
= -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */
205 t8
= 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */
206 t9
= -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */
207 t10
= 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */
208 t11
= -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */
209 t12
= 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */
210 t13
= -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */
211 t14
= 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */
212 u0
= -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
213 u1
= 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */
214 u2
= 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */
215 u3
= 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */
216 u4
= 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */
217 u5
= 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */
218 v1
= 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */
219 v2
= 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */
220 v3
= 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */
221 v4
= 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */
222 v5
= 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */
223 s0
= -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
224 s1
= 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */
225 s2
= 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */
226 s3
= 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */
227 s4
= 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */
228 s5
= 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */
229 s6
= 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */
230 r1
= 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */
231 r2
= 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */
232 r3
= 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */
233 r4
= 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */
234 r5
= 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */
235 r6
= 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */
236 w0
= 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */
237 w1
= 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */
238 w2
= -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */
239 w3
= 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */
240 w4
= -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */
241 w5
= 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */
242 w6
= -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */
245 static const double zero
= 0.00000000000000000000e+00;
247 static double zero
= 0.00000000000000000000e+00;
251 static double sin_pi(double x
)
253 static double sin_pi(x
)
263 if(ix
<0x3fd00000) return sin(pi
*x
);
264 y
= -x
; /* x is assume negative */
267 * argument reduction, make sure inexact flag not raised if input
271 if(z
!=y
) { /* inexact anyway */
273 y
= 2.0*(y
- floor(y
)); /* y = |x| mod 2.0 */
274 n
= (__int32_t
) (y
*4.0);
277 y
= zero
; n
= 0; /* y must be even */
279 if(ix
<0x43300000) z
= y
+two52
; /* exact */
287 case 0: y
= sin(pi
*y
); break;
289 case 2: y
= cos(pi
*(0.5-y
)); break;
291 case 4: y
= sin(pi
*(one
-y
)); break;
293 case 6: y
= -cos(pi
*(y
-1.5)); break;
294 default: y
= sin(pi
*(y
-2.0)); break;
301 double lgamma_r(double x
, int *signgamp
)
303 double lgamma_r(x
,signgamp
)
304 double x
; int *signgamp
;
307 double t
,y
,z
,nadj
,p
,p1
,p2
,p3
,q
,r
,w
;
308 __int32_t i
,hx
,lx
,ix
;
312 EXTRACT_WORDS(hx
,lx
,x
);
314 /* purge off +-inf, NaN, +-0, and negative arguments */
317 if(ix
>=0x7ff00000) return x
*x
;
318 if((ix
|lx
)==0) return one
/zero
;
319 if(ix
<0x3b900000) { /* |x|<2**-70, return -log(|x|) */
323 } else return -log(x
);
326 if(ix
>=0x43300000) /* |x|>=2**52, must be -integer */
329 if(t
==zero
) return one
/zero
; /* -integer */
330 nadj
= log(pi
/fabs(t
*x
));
331 if(t
<zero
) *signgamp
= -1;
335 /* purge off 1 and 2 */
336 if((((ix
-0x3ff00000)|lx
)==0)||(((ix
-0x40000000)|lx
)==0)) r
= 0;
338 else if(ix
<0x40000000) {
339 if(ix
<=0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */
341 if(ix
>=0x3FE76944) {y
= one
-x
; i
= 0;}
342 else if(ix
>=0x3FCDA661) {y
= x
-(tc
-one
); i
=1;}
346 if(ix
>=0x3FFBB4C3) {y
=2.0-x
;i
=0;} /* [1.7316,2] */
347 else if(ix
>=0x3FF3B4C4) {y
=x
-tc
;i
=1;} /* [1.23,1.73] */
353 p1
= a0
+z
*(a2
+z
*(a4
+z
*(a6
+z
*(a8
+z
*a10
))));
354 p2
= z
*(a1
+z
*(a3
+z
*(a5
+z
*(a7
+z
*(a9
+z
*a11
)))));
356 r
+= (p
-0.5*y
); break;
360 p1
= t0
+w
*(t3
+w
*(t6
+w
*(t9
+w
*t12
))); /* parallel comp */
361 p2
= t1
+w
*(t4
+w
*(t7
+w
*(t10
+w
*t13
)));
362 p3
= t2
+w
*(t5
+w
*(t8
+w
*(t11
+w
*t14
)));
363 p
= z
*p1
-(tt
-w
*(p2
+y
*p3
));
364 r
+= (tf
+ p
); break;
366 p1
= y
*(u0
+y
*(u1
+y
*(u2
+y
*(u3
+y
*(u4
+y
*u5
)))));
367 p2
= one
+y
*(v1
+y
*(v2
+y
*(v3
+y
*(v4
+y
*v5
))));
368 r
+= (-0.5*y
+ p1
/p2
);
371 else if(ix
<0x40200000) { /* x < 8.0 */
375 p
= y
*(s0
+y
*(s1
+y
*(s2
+y
*(s3
+y
*(s4
+y
*(s5
+y
*s6
))))));
376 q
= one
+y
*(r1
+y
*(r2
+y
*(r3
+y
*(r4
+y
*(r5
+y
*r6
)))));
378 z
= one
; /* lgamma(1+s) = log(s) + lgamma(s) */
380 case 7: z
*= (y
+6.0); /* FALLTHRU */
381 case 6: z
*= (y
+5.0); /* FALLTHRU */
382 case 5: z
*= (y
+4.0); /* FALLTHRU */
383 case 4: z
*= (y
+3.0); /* FALLTHRU */
384 case 3: z
*= (y
+2.0); /* FALLTHRU */
387 /* 8.0 <= x < 2**58 */
388 } else if (ix
< 0x43900000) {
392 w
= w0
+z
*(w1
+y
*(w2
+y
*(w3
+y
*(w4
+y
*(w5
+y
*w6
)))));
393 r
= (x
-half
)*(t
-one
)+w
;
395 /* 2**58 <= x <= inf */
397 if(hx
<0) r
= nadj
- r
;
404 return lgamma_r(x
, &(_REENT_SIGNGAM(_REENT
)));