#include <math.h>
#include <stdint.h>
#ifdef ARMLIBM_SET_FLAGS
#include "required_arithmetic.h"
#endif
static const double LogSqrt2pi = 0.9189385332046727417803297e+0;
static const double pi = 3.1415926535897932384626434e+0;
static const double eps = 0x1.0p-52;
static const double xbig = 171.624e+0;
static const double p[8] = { -1.71618513886549492533811e+0,
2.47656508055759199108314e+1,
-3.79804256470945635097577e+2,
6.29331155312818442661052e+2,
8.66966202790413211295064e+2,
-3.14512729688483675254357e+4,
-3.61444134186911729807069e+4,
6.64561438202405440627855e+4 };
static const double q[8] = { -3.08402300119738975254353e+1,
3.15350626979604161529144e+2,
-1.01515636749021914166146e+3,
-3.10777167157231109440444e+3,
2.25381184209801510330112e+4,
4.75584627752788110767815e+3,
-1.34659959864969306392456e+5,
-1.15132259675553483497211e+5 };
static const double c[7] = { 0xa.aaaaaaaaaaaaaabp-7,
-0xb.60b60b60b60b60bp-12,
0xd.00d00d00d00d00dp-14,
-0x9.c09c09c09c09c0ap-14,
0xd.ca8f158c7f91ab8p-14,
-0xf.b5586ccc9e3e41p-13,
0xd.20d20d20d20d20dp-11 };
double tgamma( double x )
{
union{ double d; uint64_t u; }u = {x};
if( (u.u & 0x7fffffffffffffffULL) -1ULL >= 0x7ff0000000000000ULL -1ULL )
{
if( x == 0.0 ) {
#ifdef ARMLIBM_SET_FLAGS
return required_divide_double( 1.0, x );
#else
return __builtin_copysign(__builtin_inf(), x);
#endif
}
if( x != x )
return x + x;
if( x < 0.0 ) {
#ifdef ARMLIBM_SET_FLAGS
return required_multiply_double( x, 0.0 ); #else
return __builtin_nan("");
#endif
}
return x; }
int n = 0;
int parity = 0;
double y = x;
double fact = 1.0;
if( x <= 0.0 )
{
y = -x;
if( y < 0x1.0p-1022 )
return 1.0 / x;
double iy = y;
int64_t ll = 0;
if( y < 0x1.0p54 )
{
ll = y;
iy = ll;
}
double fraction = y - iy;
if( fraction != 0.0 )
{
parity = (int) (ll & 1);
fact = -pi / sin( pi * fraction );
y += 1.0;
}
else {
#ifdef ARMLIBM_SET_FLAGS
return required_add_double( -__builtin_inf(), __builtin_inf() ); #else
return __builtin_nan("");
#endif
}
}
double result;
int i;
if( y < eps )
{
result = 1.0 / y;
}
else if( y < 12.0 )
{
double y1 = y;
double z;
if( y < 1.0)
{
z = y;
y += 1.0;
}
else
{
n = (int)y - 1;
y -= (double) n;
z = y - 1.0;
}
double numerator = 0.0;
double denomenator = 1.0;
for( i = 0; i < 8; i++ )
{
numerator = (numerator + p[i]) * z;
denomenator = denomenator * z + q[i];
}
result = numerator / denomenator + 1.0;
if( y1 < y )
result /= y1;
else if( y1 > y )
{
for( i = 0; i < n; i++ )
{
result *= y;
y += 1.0;
}
}
}
else
{ if( x < xbig )
{
double yy = y * y;
double sum = c[6];
for( i = 5; i >= 0; i-- )
sum = sum / yy + c[i];
sum = sum / y - y + LogSqrt2pi;
sum += (y - 0.5) * log( y );
result = exp( sum );
}
else
return x * 0x1.0p1023; }
if( parity )
result = -result;
if( fact != 1.0 )
result = fact / result;
return result;
}