zig/lib/libc/mingw/math/lgammaf.c

188 lines
3.1 KiB
C

/**
* This file has no copyright assigned and is placed in the Public Domain.
* This file is part of the mingw-w64 runtime package.
* No warranty is given; refer to the file DISCLAIMER.PD within this package.
*/
/* 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 __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)
{
return (__lgammaf_r(x, &signgam));
}