blob: 7067a611da716b9c79ffbc2a07f1d8fd1328d9ff [file] [log] [blame]
/* 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));
}