X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fmath%2Flgammaf_r.c;h=c5b43db558c2a8ae1fca30847c882157d2e076e9;hb=b72cd07f176b876aa51864d93aa8101477b1d732;hp=c6280f5be41d509202f34a8d9a19243ed55e6f89;hpb=93a50a26cd0f9efc59cc83daae7b2d916b327ab1;p=musl diff --git a/src/math/lgammaf_r.c b/src/math/lgammaf_r.c index c6280f5b..c5b43db5 100644 --- a/src/math/lgammaf_r.c +++ b/src/math/lgammaf_r.c @@ -14,11 +14,9 @@ */ #include "libm.h" +#include "libc.h" static const float -two23= 8.3886080000e+06, /* 0x4b000000 */ -half= 5.0000000000e-01, /* 0x3f000000 */ -one = 1.0000000000e+00, /* 0x3f800000 */ pi = 3.1415927410e+00, /* 0x40490fdb */ a0 = 7.7215664089e-02, /* 0x3d9e233f */ a1 = 3.2246702909e-01, /* 0x3ea51a66 */ @@ -83,89 +81,58 @@ w4 = -5.9518753551e-04, /* 0xba1c065c */ w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */ w6 = -1.6309292987e-03; /* 0xbad5c4e8 */ -static const float zero = 0.0000000000e+00; - -static float sin_pif(float x) +/* sin(pi*x) assuming x > 2^-100, if sin(pi*x)==0 the sign is arbitrary */ +static float sin_pi(float x) { - float y,z; - int n,ix; - - GET_FLOAT_WORD(ix, x); - ix &= 0x7fffffff; - - if(ix < 0x3e800000) - return __sindf(pi*x); + double_t y; + int n; - y = -x; /* negative x is assumed */ + /* spurious inexact if odd int */ + x = 2*(x*0.5f - floorf(x*0.5f)); /* x mod 2.0 */ - /* - * argument reduction, make sure inexact flag not raised if input - * is an integer - */ - z = floorf(y); - if (z != y) { /* inexact anyway */ - y *= 0.5f; - y = 2.0f*(y - floorf(y)); /* y = |x| mod 2.0 */ - n = (int)(y*4.0f); - } else { - if (ix >= 0x4b800000) { - y = zero; /* y must be even */ - n = 0; - } else { - if (ix < 0x4b000000) - z = y + two23; /* exact */ - GET_FLOAT_WORD(n, z); - n &= 1; - y = n; - n <<= 2; - } - } + n = (int)(x*4); + n = (n+1)/2; + y = x - n*0.5f; + y *= 3.14159265358979323846; switch (n) { - case 0: y = __sindf(pi*y); break; - case 1: - case 2: y = __cosdf(pi*(0.5f - y)); break; - case 3: - case 4: y = __sindf(pi*(one - y)); break; - case 5: - case 6: y = -__cosdf(pi*(y - 1.5f)); break; - default: y = __sindf(pi*(y - 2.0f)); break; + default: /* case 4: */ + case 0: return __sindf(y); + case 1: return __cosdf(y); + case 2: return __sindf(-y); + case 3: return -__cosdf(y); } - return -y; } - -float lgammaf_r(float x, int *signgamp) +float __lgammaf_r(float x, int *signgamp) { + union {float f; uint32_t i;} u = {x}; float t,y,z,nadj,p,p1,p2,p3,q,r,w; - int32_t hx; - int i,ix; - - GET_FLOAT_WORD(hx, x); + uint32_t ix; + int i,sign; /* purge off +-inf, NaN, +-0, tiny and negative arguments */ *signgamp = 1; - ix = hx & 0x7fffffff; + sign = u.i>>31; + ix = u.i & 0x7fffffff; if (ix >= 0x7f800000) return x*x; - if (ix == 0) - return one/zero; if (ix < 0x35000000) { /* |x| < 2**-21, return -log(|x|) */ - if (hx < 0) { + if (sign) { *signgamp = -1; - return -logf(-x); + x = -x; } return -logf(x); } - if (hx < 0) { - if (ix >= 0x4b000000) /* |x| >= 2**23, must be -integer */ - return one/zero; - t = sin_pif(x); - if (t == zero) /* -integer */ - return one/zero; - nadj = logf(pi/fabsf(t*x)); - if (t < zero) - *signgamp = -1; + if (sign) { x = -x; + t = sin_pi(x); + if (t == 0.0f) /* -integer */ + return 1.0f/(x-x); + if (t > 0.0f) + *signgamp = -1; + else + t = -t; + nadj = logf(pi/(t*x)); } /* purge off 1 and 2 */ @@ -176,17 +143,17 @@ float lgammaf_r(float x, int *signgamp) if (ix <= 0x3f666666) { /* lgamma(x) = lgamma(x+1)-log(x) */ r = -logf(x); if (ix >= 0x3f3b4a20) { - y = one - x; + y = 1.0f - x; i = 0; } else if (ix >= 0x3e6d3308) { - y = x - (tc-one); + y = x - (tc-1.0f); i = 1; } else { y = x; i = 2; } } else { - r = zero; + r = 0.0f; if (ix >= 0x3fdda618) { /* [1.7316,2] */ y = 2.0f - x; i = 0; @@ -194,7 +161,7 @@ float lgammaf_r(float x, int *signgamp) y = x - tc; i = 1; } else { - y = x - one; + y = x - 1.0f; i = 2; } } @@ -217,16 +184,16 @@ float lgammaf_r(float x, int *signgamp) break; case 2: p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); - p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + p2 = 1.0f+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); r += -0.5f*y + p1/p2; } } else if (ix < 0x41000000) { /* x < 8.0 */ i = (int)x; y = x - (float)i; p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); - q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); - r = half*y+p/q; - z = one; /* lgamma(1+s) = log(s) + lgamma(s) */ + q = 1.0f+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = 0.5f*y+p/q; + z = 1.0f; /* lgamma(1+s) = log(s) + lgamma(s) */ switch (i) { case 7: z *= y + 6.0f; /* FALLTHRU */ case 6: z *= y + 5.0f; /* FALLTHRU */ @@ -238,13 +205,15 @@ float lgammaf_r(float x, int *signgamp) } } else if (ix < 0x5c800000) { /* 8.0 <= x < 2**58 */ t = logf(x); - z = one/x; + z = 1.0f/x; y = z*z; w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); - r = (x-half)*(t-one)+w; + r = (x-0.5f)*(t-1.0f)+w; } else /* 2**58 <= x <= inf */ - r = x*(logf(x)-one); - if (hx < 0) + r = x*(logf(x)-1.0f); + if (sign) r = nadj - r; return r; } + +weak_alias(__lgammaf_r, lgammaf_r);