static float sin_pif(float x) { float y,z; int n,ix; GET_FLOAT_WORD(ix,x); ix &= 0x7fffffff; if(ix<0x3e800000) return __kernel_sinf(pi*x,zero,0); y = -x; /* x is assume negative */ /* * argument reduction, make sure inexact flag not raised if input * is an integer */ z = __floorf(y); if(z!=y) { /* inexact anyway */ y *= (float)0.5; y = (float)2.0*(y - __floorf(y)); /* y = |x| mod 2.0 */ n = (int) (y*(float)4.0); } else { if(ix>=0x4b800000) { y = zero; n = 0; /* y must be even */ } else { if(ix<0x4b000000) z = y+two23; /* exact */ GET_FLOAT_WORD(n,z); n &= 1; y = n; n<<= 2; } } switch (n) { case 0: y = __kernel_sinf(pi*y,zero,0); break; case 1: case 2: y = __kernel_cosf(pi*((float)0.5-y),zero); break; case 3: case 4: y = __kernel_sinf(pi*(one-y),zero,0); break; case 5: case 6: y = -__kernel_cosf(pi*(y-(float)1.5),zero); break; default: y = __kernel_sinf(pi*(y-(float)2.0),zero,0); break; } return -y; }
int32_t __fp_kernel_rem_pio2f (float *x, float *y, float e0, int32_t nx) { int32_t jz, jx, jv, jp, jk, carry, n, iq[20], i, j, k, m, q0, ih, exp; float z, fw, f[20], fq[20], q[20]; /* initialize jk */ jp = jk = 9; /* determine jx,jv,q0, note that 3>q0 */ jx = nx - 1; exp = __float_get_exp (e0) - 127; jv = (exp - 3) / 8; if (jv < 0) jv = 0; q0 = exp - 8 * (jv + 1); /* set up f[0] to f[jx+jk] where f[jx+jk] = two_over_pi[jv+jk] */ j = jv - jx; m = jx + jk; for (i = 0; i <= m; i++, j++) f[i] = (j < 0) ? zero : two_over_pi[j]; /* compute q[0],q[1],...q[jk] */ for (i = 0; i <= jk; i++) { for (j = 0, fw = 0.0; j <= jx; j++) fw += x[j] * f[jx + i - j]; q[i] = fw; } jz = jk; recompute: /* distill q[] into iq[] reversingly */ for (i = 0, j = jz, z = q[jz]; j > 0; i++, j--) { fw = __truncf (twon8 * z); iq[i] = (int32_t) (z - two8 * fw); z = q[j - 1] + fw; } /* compute n */ z = __scalbnf (z, q0); /* actual value of z */ z -= 8.0 * __floorf (z * 0.125); /* trim off integer >= 8 */ n = (int32_t) z; z -= __truncf (z); ih = 0; if (q0 > 0) { /* need iq[jz-1] to determine n */ i = (iq[jz - 1] >> (8 - q0)); n += i; iq[jz - 1] -= i << (8 - q0); ih = iq[jz - 1] >> (7 - q0); }
float LGFUNC (__lgammaf) (float x) { float y = CALL_LGAMMA (float, __ieee754_lgammaf_r, x); if(__builtin_expect(!isfinite(y), 0) && isfinite(x) && _LIB_VERSION != _IEEE_) return __kernel_standard_f(x, x, __floorf(x)==x&&x<=0.0f ? 115 /* lgamma pole */ : 114); /* lgamma overflow */ return y; }
float __lgammaf_r(float x, int *signgamp) { float y = __ieee754_lgammaf_r(x,signgamp); if(__builtin_expect(!__finitef(y), 0) && __finitef(x) && _LIB_VERSION != _IEEE_) return __kernel_standard_f(x, x, __floorf(x)==x&&x<=0.0f ? 115 /* lgamma pole */ : 114); /* lgamma overflow */ return y; }
int __kernel_rem_pio2f(float *x, float *y, int e0, int nx, int prec, const int32_t *ipio2) { int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih; float z,fw,f[20],fq[20],q[20]; /* initialize jk*/ jk = init_jk[prec]; jp = jk; /* determine jx,jv,q0, note that 3>q0 */ jx = nx-1; jv = (e0-3)/8; if(jv<0) jv=0; q0 = e0-8*(jv+1); /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */ j = jv-jx; m = jx+jk; for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (float) ipio2[j]; /* compute q[0],q[1],...q[jk] */ for (i=0;i<=jk;i++) { for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw; } jz = jk; recompute: /* distill q[] into iq[] reversingly */ for(i=0,j=jz,z=q[jz];j>0;i++,j--) { fw = (float)((int32_t)(twon8* z)); iq[i] = (int32_t)(z-two8*fw); z = q[j-1]+fw; } /* compute n */ z = __scalbnf(z,q0); /* actual value of z */ z -= (float)8.0*__floorf(z*(float)0.125); /* trim off integer >= 8 */ n = (int32_t) z; z -= (float)n; ih = 0; if(q0>0) { /* need iq[jz-1] to determine n */ i = (iq[jz-1]>>(8-q0)); n += i; iq[jz-1] -= i<<(8-q0); ih = iq[jz-1]>>(7-q0); }
int32_t __ieee754_rem_pio2f (float x, float *y) { float ax, z, n, r, w, t, e0; float tx[3]; int32_t i, nx; ax = __builtin_fabsf (x); if (ax <= pio4) { y[0] = x; y[1] = 0; return 0; } if (ax < pio3_4) { if (x > 0) { z = x - pio2_1; if (!__float_and_test28 (ax, pio2_24b)) { y[0] = z - pio2_1t; y[1] = (z - y[0]) - pio2_1t; } else { z -= pio2_2; y[0] = z - pio2_2t; y[1] = (z - y[0]) - pio2_2t; } return 1; } else { z = x + pio2_1; if (!__float_and_test28 (ax, pio2_24b)) { y[0] = z + pio2_1t; y[1] = (z - y[0]) + pio2_1t; } else { z += pio2_2; y[0] = z + pio2_2t; y[1] = (z - y[0]) + pio2_2t; } return -1; } } if (ax <= pio2_2e7) { n = __floorf (ax * invpio2 + half); i = (int32_t) n; r = ax - n * pio2_1; w = n * pio2_1t; /* 1st round good to 40 bit */ if (i < 32 && !__float_and_test24 (ax, npio2_hw[i - 1])) { y[0] = r - w; } else { float i, j; j = __float_and8 (ax); y[0] = r - w; i = __float_and8 (y[0]); if (j / i > 256.0 || j / i < 3.9062500e-3) { /* 2nd iterations needed, good to 57 */ t = r; w = n * pio2_2; r = t - w; w = n * pio2_2t - ((t - r) - w); y[0] = r - w; i = __float_and8 (y[0]); if (j / i > 33554432 || j / i < 2.9802322e-8) { /* 3rd iteration needed, 74 bits acc */ t = r; w = n * pio2_3; r = t - w; w = n * pio2_3t - ((t - r) - w); y[0] = r - w; } } } y[1] = (r - y[0]) - w; if (x < 0) { y[0] = -y[0]; y[1] = -y[1]; return -i; } else { return i; } } /* all other (large) arguments */ if (isnanf (x) || isinff (x)) { y[0] = y[1] = x - x; return 0; } /* set z = scalbn(|x|,ilogb(x)-7) */ e0 = __float_and8 (ax / 128.0); z = ax / e0; tx[0] = __floorf (z); z = (z - tx[0]) * two8; tx[1] = __floorf (z); z = (z - tx[1]) * two8; tx[2] = __floorf (z); nx = 3; while (tx[nx - 1] == zero) nx--; i = __fp_kernel_rem_pio2f (tx, y, e0, nx); if (x < 0) { y[0] = -y[0]; y[1] = -y[1]; return -i; } return i; }
float __lgamma_negf (float x, int *signgamp) { /* Determine the half-integer region X lies in, handle exact integers and determine the sign of the result. */ int i = __floorf (-2 * x); if ((i & 1) == 0 && i == -2 * x) return 1.0f / 0.0f; float xn = ((i & 1) == 0 ? -i / 2 : (-i - 1) / 2); i -= 4; *signgamp = ((i & 2) == 0 ? -1 : 1); SET_RESTORE_ROUNDF (FE_TONEAREST); /* Expand around the zero X0 = X0_HI + X0_LO. */ float x0_hi = lgamma_zeros[i][0], x0_lo = lgamma_zeros[i][1]; float xdiff = x - x0_hi - x0_lo; /* For arguments in the range -3 to -2, use polynomial approximations to an adjusted version of the gamma function. */ if (i < 2) { int j = __floorf (-8 * x) - 16; float xm = (-33 - 2 * j) * 0.0625f; float x_adj = x - xm; size_t deg = poly_deg[j]; size_t end = poly_end[j]; float g = poly_coeff[end]; for (size_t j = 1; j <= deg; j++) g = g * x_adj + poly_coeff[end - j]; return __log1pf (g * xdiff / (x - xn)); } /* The result we want is log (sinpi (X0) / sinpi (X)) + log (gamma (1 - X0) / gamma (1 - X)). */ float x_idiff = fabsf (xn - x), x0_idiff = fabsf (xn - x0_hi - x0_lo); float log_sinpi_ratio; if (x0_idiff < x_idiff * 0.5f) /* Use log not log1p to avoid inaccuracy from log1p of arguments close to -1. */ log_sinpi_ratio = __ieee754_logf (lg_sinpi (x0_idiff) / lg_sinpi (x_idiff)); else { /* Use log1p not log to avoid inaccuracy from log of arguments close to 1. X0DIFF2 has positive sign if X0 is further from XN than X is from XN, negative sign otherwise. */ float x0diff2 = ((i & 1) == 0 ? xdiff : -xdiff) * 0.5f; float sx0d2 = lg_sinpi (x0diff2); float cx0d2 = lg_cospi (x0diff2); log_sinpi_ratio = __log1pf (2 * sx0d2 * (-sx0d2 + cx0d2 * lg_cotpi (x_idiff))); } float log_gamma_ratio; float y0 = math_narrow_eval (1 - x0_hi); float y0_eps = -x0_hi + (1 - y0) - x0_lo; float y = math_narrow_eval (1 - x); float y_eps = -x + (1 - y); /* We now wish to compute LOG_GAMMA_RATIO = log (gamma (Y0 + Y0_EPS) / gamma (Y + Y_EPS)). XDIFF accurately approximates the difference Y0 + Y0_EPS - Y - Y_EPS. Use Stirling's approximation. */ float log_gamma_high = (xdiff * __log1pf ((y0 - e_hi - e_lo + y0_eps) / e_hi) + (y - 0.5f + y_eps) * __log1pf (xdiff / y)); /* Compute the sum of (B_2k / 2k(2k-1))(Y0^-(2k-1) - Y^-(2k-1)). */ float y0r = 1 / y0, yr = 1 / y; float y0r2 = y0r * y0r, yr2 = yr * yr; float rdiff = -xdiff / (y * y0); float bterm[NCOEFF]; float dlast = rdiff, elast = rdiff * yr * (yr + y0r); bterm[0] = dlast * lgamma_coeff[0]; for (size_t j = 1; j < NCOEFF; j++) { float dnext = dlast * y0r2 + elast; float enext = elast * yr2; bterm[j] = dnext * lgamma_coeff[j]; dlast = dnext; elast = enext; } float log_gamma_low = 0; for (size_t j = 0; j < NCOEFF; j++) log_gamma_low += bterm[NCOEFF - 1 - j]; log_gamma_ratio = log_gamma_high + log_gamma_low; return log_sinpi_ratio + log_gamma_ratio; }