/* log gamma(x+2), -.5 < x < .5 */ | |
static const float B[] = { | |
6.055172732649237E-004, | |
-1.311620815545743E-003, | |
2.863437556468661E-003, | |
-7.366775108654962E-003, | |
2.058355474821512E-002, | |
-6.735323259371034E-002, | |
3.224669577325661E-001, | |
4.227843421859038E-001 | |
}; | |
/* log gamma(x+1), -.25 < x < .25 */ | |
static const float C[] = { | |
1.369488127325832E-001, | |
-1.590086327657347E-001, | |
1.692415923504637E-001, | |
-2.067882815621965E-001, | |
2.705806208275915E-001, | |
-4.006931650563372E-001, | |
8.224670749082976E-001, | |
-5.772156501719101E-001 | |
}; | |
/* log( sqrt( 2*pi ) ) */ | |
static const float LS2PI = 0.91893853320467274178; | |
#define MAXLGM 2.035093e36 | |
static const float PIINV = 0.318309886183790671538; | |
#include "cephes_mconf.h" | |
/* Reentrant version */ | |
/* Logarithm of gamma function */ | |
float __lgammaf_r( float x, int* sgngamf ) | |
{ | |
float p, q, w, z; | |
float nx, tx; | |
int i, direction; | |
*sgngamf = 1; | |
#ifdef NANS | |
if( isnan(x) ) | |
return(x); | |
#endif | |
#ifdef INFINITIES | |
if( !isfinite(x) ) | |
return(x); | |
#endif | |
if( x < 0.0 ) | |
{ | |
q = -x; | |
w = __lgammaf_r(q, sgngamf); /* note this modifies sgngam! */ | |
p = floorf(q); | |
if( p == q ) | |
{ | |
lgsing: | |
_SET_ERRNO(EDOM); | |
mtherr( "lgamf", SING ); | |
#ifdef INFINITIES | |
return (INFINITYF); | |
#else | |
return( *sgngamf * MAXNUMF ); | |
#endif | |
} | |
i = p; | |
if( (i & 1) == 0 ) | |
*sgngamf = -1; | |
else | |
*sgngamf = 1; | |
z = q - p; | |
if( z > 0.5 ) | |
{ | |
p += 1.0; | |
z = p - q; | |
} | |
z = q * sinf( PIF * z ); | |
if( z == 0.0 ) | |
goto lgsing; | |
z = -logf( PIINV*z ) - w; | |
return( z ); | |
} | |
if( x < 6.5 ) | |
{ | |
direction = 0; | |
z = 1.0; | |
tx = x; | |
nx = 0.0; | |
if( x >= 1.5 ) | |
{ | |
while( tx > 2.5 ) | |
{ | |
nx -= 1.0; | |
tx = x + nx; | |
z *=tx; | |
} | |
x += nx - 2.0; | |
iv1r5: | |
p = x * polevlf( x, B, 7 ); | |
goto cont; | |
} | |
if( x >= 1.25 ) | |
{ | |
z *= x; | |
x -= 1.0; /* x + 1 - 2 */ | |
direction = 1; | |
goto iv1r5; | |
} | |
if( x >= 0.75 ) | |
{ | |
x -= 1.0; | |
p = x * polevlf( x, C, 7 ); | |
q = 0.0; | |
goto contz; | |
} | |
while( tx < 1.5 ) | |
{ | |
if( tx == 0.0 ) | |
goto lgsing; | |
z *=tx; | |
nx += 1.0; | |
tx = x + nx; | |
} | |
direction = 1; | |
x += nx - 2.0; | |
p = x * polevlf( x, B, 7 ); | |
cont: | |
if( z < 0.0 ) | |
{ | |
*sgngamf = -1; | |
z = -z; | |
} | |
else | |
{ | |
*sgngamf = 1; | |
} | |
q = logf(z); | |
if( direction ) | |
q = -q; | |
contz: | |
return( p + q ); | |
} | |
if( x > MAXLGM ) | |
{ | |
_SET_ERRNO(ERANGE); | |
mtherr( "lgamf", OVERFLOW ); | |
#ifdef INFINITIES | |
return( *sgngamf * INFINITYF ); | |
#else | |
return( *sgngamf * MAXNUMF ); | |
#endif | |
} | |
/* Note, though an asymptotic formula could be used for x >= 3, | |
* there is cancellation error in the following if x < 6.5. */ | |
q = LS2PI - x; | |
q += ( x - 0.5 ) * logf(x); | |
if( x <= 1.0e4 ) | |
{ | |
z = 1.0/x; | |
p = z * z; | |
q += (( 6.789774945028216E-004 * p | |
- 2.769887652139868E-003 ) * p | |
+ 8.333316229807355E-002 ) * z; | |
} | |
return( q ); | |
} | |
/* This is the C99 version */ | |
float lgammaf(float x) | |
{ | |
int local_sgngamf=0; | |
return (__lgammaf_r(x, &local_sgngamf)); | |
} |