float __ieee754_atanhf (float x) { float xa = fabsf (x); float t; if (isless (xa, 0.5f)) { if (__glibc_unlikely (xa < 0x1.0p-28f)) { math_force_eval (huge + x); if (fabsf (x) < FLT_MIN) { float force_underflow = x * x; math_force_eval (force_underflow); } return x; } t = xa + xa; t = 0.5f * __log1pf (t + t * xa / (1.0f - xa)); } else if (__glibc_likely (isless (xa, 1.0f))) t = 0.5f * __log1pf ((xa + xa) / (1.0f - xa)); else { if (isgreater (xa, 1.0f)) return (x - x) / (x - x); return x / 0.0f; } return __copysignf (t, x); }
float __ieee754_atanhf (float x) { float xa = fabsf (x); float t; if (isless (xa, 0.5f)) { if (__builtin_expect (xa < 0x1.0p-28f, 0)) { math_force_eval (huge + x); return x; } t = xa + xa; t = 0.5f * __log1pf (t + t * xa / (1.0f - xa)); } else if (__builtin_expect (isless (xa, 1.0f), 1)) t = 0.5f * __log1pf ((xa + xa) / (1.0f - xa)); else { if (isgreater (xa, 1.0f)) return (x - x) / (x - x); return x / 0.0f; } return __copysignf (t, x); }
float __asinhf(float x) { float w; int32_t hx,ix; GET_FLOAT_WORD(hx,x); ix = hx&0x7fffffff; if(__builtin_expect(ix< 0x38000000, 0)) { /* |x|<2**-14 */ math_check_force_underflow (x); if(huge+x>one) return x; /* return x inexact except 0 */ } if(__builtin_expect(ix>0x47000000, 0)) { /* |x| > 2**14 */ if(ix>=0x7f800000) return x+x; /* x is inf or NaN */ w = __ieee754_logf(fabsf(x))+ln2; } else { float xa = fabsf(x); if (ix>0x40000000) { /* 2**14 > |x| > 2.0 */ w = __ieee754_logf(2.0f*xa+one/(__ieee754_sqrtf(xa*xa+one)+xa)); } else { /* 2.0 > |x| > 2**-14 */ float t = xa*xa; w =__log1pf(xa+t/(one+__ieee754_sqrtf(one+t))); } } return __copysignf(w, x); }
float log10f(float x) { float f,hfsq,hi,lo,r,y; int32_t i,k,hx; GET_FLOAT_WORD(hx, x); k = 0; if (hx < 0x00800000) { /* x < 2**-126 */ if ((hx&0x7fffffff) == 0) return -two25/0.0f; /* log(+-0)=-inf */ if (hx < 0) return (x-x)/0.0f; /* log(-#) = NaN */ /* subnormal number, scale up x */ k -= 25; x *= two25; GET_FLOAT_WORD(hx, x); } if (hx >= 0x7f800000) return x+x; if (hx == 0x3f800000) return 0.0f; /* log(1) = +0 */ k += (hx>>23) - 127; hx &= 0x007fffff; i = (hx+(0x4afb0d))&0x800000; SET_FLOAT_WORD(x, hx|(i^0x3f800000)); /* normalize x or x/2 */ k += i>>23; y = (float)k; f = x - 1.0f; hfsq = 0.5f * f * f; r = __log1pf(f); // FIXME // /* See log2f.c and log2.c for details. */ // if (sizeof(float_t) > sizeof(float)) // return (r - hfsq + f) * ((float_t)ivln10lo + ivln10hi) + // y * ((float_t)log10_2lo + log10_2hi); hi = f - hfsq; GET_FLOAT_WORD(hx, hi); SET_FLOAT_WORD(hi, hx&0xfffff000); lo = (f - hi) - hfsq + r; return y*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi + hi*ivln10hi + y*log10_2hi; }
__complex__ float __clog10f (__complex__ float x) { __complex__ float result; int rcls = fpclassify (__real__ x); int icls = fpclassify (__imag__ x); if (__glibc_unlikely (rcls == FP_ZERO && icls == FP_ZERO)) { /* Real and imaginary part are 0.0. */ __imag__ result = signbit (__real__ x) ? M_PI_LOG10Ef : 0.0; __imag__ result = __copysignf (__imag__ result, __imag__ x); /* Yes, the following line raises an exception. */ __real__ result = -1.0 / fabsf (__real__ x); } else if (__glibc_likely (rcls != FP_NAN && icls != FP_NAN)) { /* Neither real nor imaginary part is NaN. */ float absx = fabsf (__real__ x), absy = fabsf (__imag__ x); int scale = 0; if (absx < absy) { float t = absx; absx = absy; absy = t; } if (absx > FLT_MAX / 2.0f) { scale = -1; absx = __scalbnf (absx, scale); absy = (absy >= FLT_MIN * 2.0f ? __scalbnf (absy, scale) : 0.0f); } else if (absx < FLT_MIN && absy < FLT_MIN) { scale = FLT_MANT_DIG; absx = __scalbnf (absx, scale); absy = __scalbnf (absy, scale); } if (absx == 1.0f && scale == 0) { float absy2 = absy * absy; if (absy2 <= FLT_MIN * 2.0f * (float) M_LN10) { float force_underflow = absy2 * absy2; __real__ result = absy2 * ((float) M_LOG10E / 2.0f); math_force_eval (force_underflow); } else __real__ result = __log1pf (absy2) * ((float) M_LOG10E / 2.0f); } else if (absx > 1.0f && absx < 2.0f && absy < 1.0f && scale == 0) { float d2m1 = (absx - 1.0f) * (absx + 1.0f); if (absy >= FLT_EPSILON) d2m1 += absy * absy; __real__ result = __log1pf (d2m1) * ((float) M_LOG10E / 2.0f); } else if (absx < 1.0f && absx >= 0.75f && absy < FLT_EPSILON / 2.0f && scale == 0) { float d2m1 = (absx - 1.0f) * (absx + 1.0f); __real__ result = __log1pf (d2m1) * ((float) M_LOG10E / 2.0f); } else if (absx < 1.0f && (absx >= 0.75f || absy >= 0.5f) && scale == 0) { float d2m1 = __x2y2m1f (absx, absy); __real__ result = __log1pf (d2m1) * ((float) M_LOG10E / 2.0f); } else { float d = __ieee754_hypotf (absx, absy); __real__ result = __ieee754_log10f (d) - scale * M_LOG10_2f; } __imag__ result = M_LOG10E * __ieee754_atan2f (__imag__ x, __real__ x); } else { __imag__ result = __nanf (""); if (rcls == FP_INFINITE || icls == FP_INFINITE) /* Real or imaginary part is infinite. */ __real__ result = HUGE_VALF; else __real__ result = __nanf (""); } return result; }
__complex__ float __clogf (__complex__ float x) { __complex__ float result; int rcls = fpclassify (__real__ x); int icls = fpclassify (__imag__ x); if (__builtin_expect (rcls == FP_ZERO && icls == FP_ZERO, 0)) { /* Real and imaginary part are 0.0. */ __imag__ result = signbit (__real__ x) ? M_PI : 0.0; __imag__ result = __copysignf (__imag__ result, __imag__ x); /* Yes, the following line raises an exception. */ __real__ result = -1.0 / fabsf (__real__ x); } else if (__builtin_expect (rcls != FP_NAN && icls != FP_NAN, 1)) { /* Neither real nor imaginary part is NaN. */ float absx = fabsf (__real__ x), absy = fabsf (__imag__ x); int scale = 0; if (absx < absy) { float t = absx; absx = absy; absy = t; } if (absx > FLT_MAX / 2.0f) { scale = -1; absx = __scalbnf (absx, scale); absy = (absy >= FLT_MIN * 2.0f ? __scalbnf (absy, scale) : 0.0f); } else if (absx < FLT_MIN && absy < FLT_MIN) { scale = FLT_MANT_DIG; absx = __scalbnf (absx, scale); absy = __scalbnf (absy, scale); } if (absx == 1.0f && scale == 0) { float absy2 = absy * absy; if (absy2 <= FLT_MIN * 2.0f) { #if __FLT_EVAL_METHOD__ == 0 __real__ result = absy2 / 2.0f - absy2 * absy2 / 4.0f; #else volatile float force_underflow = absy2 * absy2 / 4.0f; __real__ result = absy2 / 2.0f - force_underflow; #endif } else __real__ result = __log1pf (absy2) / 2.0f; } else if (absx > 1.0f && absx < 2.0f && absy < 1.0f && scale == 0) { float d2m1 = (absx - 1.0f) * (absx + 1.0f); if (absy >= FLT_EPSILON) d2m1 += absy * absy; __real__ result = __log1pf (d2m1) / 2.0f; } else if (absx < 1.0f && absx >= 0.75f && absy < FLT_EPSILON / 2.0f && scale == 0) { float d2m1 = (absx - 1.0f) * (absx + 1.0f); __real__ result = __log1pf (d2m1) / 2.0f; } else if (absx < 1.0f && (absx >= 0.75f || absy >= 0.5f) && scale == 0) { float d2m1 = __x2y2m1f (absx, absy); __real__ result = __log1pf (d2m1) / 2.0f; } else { float d = __ieee754_hypotf (absx, absy); __real__ result = __ieee754_logf (d) - scale * (float) M_LN2; } __imag__ result = __ieee754_atan2f (__imag__ x, __real__ x); } else { __imag__ result = __nanf (""); if (rcls == FP_INFINITE || icls == FP_INFINITE) /* Real or imaginary part is infinite. */ __real__ result = HUGE_VALF; else __real__ result = __nanf (""); } return result; }
__complex__ float __catanf (__complex__ float x) { __complex__ float res; int rcls = fpclassify (__real__ x); int icls = fpclassify (__imag__ x); if (__glibc_unlikely (rcls <= FP_INFINITE || icls <= FP_INFINITE)) { if (rcls == FP_INFINITE) { __real__ res = __copysignf (M_PI_2, __real__ x); __imag__ res = __copysignf (0.0, __imag__ x); } else if (icls == FP_INFINITE) { if (rcls >= FP_ZERO) __real__ res = __copysignf (M_PI_2, __real__ x); else __real__ res = __nanf (""); __imag__ res = __copysignf (0.0, __imag__ x); } else if (icls == FP_ZERO || icls == FP_INFINITE) { __real__ res = __nanf (""); __imag__ res = __copysignf (0.0, __imag__ x); } else { __real__ res = __nanf (""); __imag__ res = __nanf (""); } } else if (__glibc_unlikely (rcls == FP_ZERO && icls == FP_ZERO)) { res = x; } else { if (fabsf (__real__ x) >= 16.0f / FLT_EPSILON || fabsf (__imag__ x) >= 16.0f / FLT_EPSILON) { __real__ res = __copysignf ((float) M_PI_2, __real__ x); if (fabsf (__real__ x) <= 1.0f) __imag__ res = 1.0f / __imag__ x; else if (fabsf (__imag__ x) <= 1.0f) __imag__ res = __imag__ x / __real__ x / __real__ x; else { float h = __ieee754_hypotf (__real__ x / 2.0f, __imag__ x / 2.0f); __imag__ res = __imag__ x / h / h / 4.0f; } } else { float den, absx, absy; absx = fabsf (__real__ x); absy = fabsf (__imag__ x); if (absx < absy) { float t = absx; absx = absy; absy = t; } if (absy < FLT_EPSILON / 2.0f) { den = (1.0f - absx) * (1.0f + absx); if (den == -0.0f) den = 0.0f; } else if (absx >= 1.0f) den = (1.0f - absx) * (1.0f + absx) - absy * absy; else if (absx >= 0.75f || absy >= 0.5f) den = -__x2y2m1f (absx, absy); else den = (1.0f - absx) * (1.0f + absx) - absy * absy; __real__ res = 0.5f * __ieee754_atan2f (2.0f * __real__ x, den); if (fabsf (__imag__ x) == 1.0f && fabsf (__real__ x) < FLT_EPSILON * FLT_EPSILON) __imag__ res = (__copysignf (0.5f, __imag__ x) * ((float) M_LN2 - __ieee754_logf (fabsf (__real__ x)))); else { float r2 = 0.0f, num, f; if (fabsf (__real__ x) >= FLT_EPSILON * FLT_EPSILON) r2 = __real__ x * __real__ x; num = __imag__ x + 1.0f; num = r2 + num * num; den = __imag__ x - 1.0f; den = r2 + den * den; f = num / den; if (f < 0.5f) __imag__ res = 0.25f * __ieee754_logf (f); else { num = 4.0f * __imag__ x; __imag__ res = 0.25f * __log1pf (num / den); } } } if (fabsf (__real__ res) < FLT_MIN) { volatile float force_underflow = __real__ res * __real__ res; (void) force_underflow; } if (fabsf (__imag__ res) < FLT_MIN) { volatile float force_underflow = __imag__ res * __imag__ res; (void) force_underflow; } } return res; }
__complex__ float __kernel_casinhf (__complex__ float x, int adj) { __complex__ float res; float rx, ix; __complex__ float y; /* Avoid cancellation by reducing to the first quadrant. */ rx = fabsf (__real__ x); ix = fabsf (__imag__ x); if (rx >= 1.0f / FLT_EPSILON || ix >= 1.0f / FLT_EPSILON) { /* For large x in the first quadrant, x + csqrt (1 + x * x) is sufficiently close to 2 * x to make no significant difference to the result; avoid possible overflow from the squaring and addition. */ __real__ y = rx; __imag__ y = ix; if (adj) { float t = __real__ y; __real__ y = __copysignf (__imag__ y, __imag__ x); __imag__ y = t; } res = __clogf (y); __real__ res += (float) M_LN2; } else if (rx >= 0.5f && ix < FLT_EPSILON / 8.0f) { float s = __ieee754_hypotf (1.0f, rx); __real__ res = __ieee754_logf (rx + s); if (adj) __imag__ res = __ieee754_atan2f (s, __imag__ x); else __imag__ res = __ieee754_atan2f (ix, s); } else if (rx < FLT_EPSILON / 8.0f && ix >= 1.5f) { float s = __ieee754_sqrtf ((ix + 1.0f) * (ix - 1.0f)); __real__ res = __ieee754_logf (ix + s); if (adj) __imag__ res = __ieee754_atan2f (rx, __copysignf (s, __imag__ x)); else __imag__ res = __ieee754_atan2f (s, rx); } else if (ix > 1.0f && ix < 1.5f && rx < 0.5f) { if (rx < FLT_EPSILON * FLT_EPSILON) { float ix2m1 = (ix + 1.0f) * (ix - 1.0f); float s = __ieee754_sqrtf (ix2m1); __real__ res = __log1pf (2.0f * (ix2m1 + ix * s)) / 2.0f; if (adj) __imag__ res = __ieee754_atan2f (rx, __copysignf (s, __imag__ x)); else __imag__ res = __ieee754_atan2f (s, rx); } else { float ix2m1 = (ix + 1.0f) * (ix - 1.0f); float rx2 = rx * rx; float f = rx2 * (2.0f + rx2 + 2.0f * ix * ix); float d = __ieee754_sqrtf (ix2m1 * ix2m1 + f); float dp = d + ix2m1; float dm = f / dp; float r1 = __ieee754_sqrtf ((dm + rx2) / 2.0f); float r2 = rx * ix / r1; __real__ res = __log1pf (rx2 + dp + 2.0f * (rx * r1 + ix * r2)) / 2.0f; if (adj) __imag__ res = __ieee754_atan2f (rx + r1, __copysignf (ix + r2, __imag__ x)); else __imag__ res = __ieee754_atan2f (ix + r2, rx + r1); } } else if (ix == 1.0f && rx < 0.5f) { if (rx < FLT_EPSILON / 8.0f) { __real__ res = __log1pf (2.0f * (rx + __ieee754_sqrtf (rx))) / 2.0f; if (adj) __imag__ res = __ieee754_atan2f (__ieee754_sqrtf (rx), __copysignf (1.0f, __imag__ x)); else __imag__ res = __ieee754_atan2f (1.0f, __ieee754_sqrtf (rx)); } else { float d = rx * __ieee754_sqrtf (4.0f + rx * rx); float s1 = __ieee754_sqrtf ((d + rx * rx) / 2.0f); float s2 = __ieee754_sqrtf ((d - rx * rx) / 2.0f); __real__ res = __log1pf (rx * rx + d + 2.0f * (rx * s1 + s2)) / 2.0f; if (adj) __imag__ res = __ieee754_atan2f (rx + s1, __copysignf (1.0f + s2, __imag__ x)); else __imag__ res = __ieee754_atan2f (1.0f + s2, rx + s1); } } else if (ix < 1.0f && rx < 0.5f) { if (ix >= FLT_EPSILON) { if (rx < FLT_EPSILON * FLT_EPSILON) { float onemix2 = (1.0f + ix) * (1.0f - ix); float s = __ieee754_sqrtf (onemix2); __real__ res = __log1pf (2.0f * rx / s) / 2.0f; if (adj) __imag__ res = __ieee754_atan2f (s, __imag__ x); else __imag__ res = __ieee754_atan2f (ix, s); } else { float onemix2 = (1.0f + ix) * (1.0f - ix); float rx2 = rx * rx; float f = rx2 * (2.0f + rx2 + 2.0f * ix * ix); float d = __ieee754_sqrtf (onemix2 * onemix2 + f); float dp = d + onemix2; float dm = f / dp; float r1 = __ieee754_sqrtf ((dp + rx2) / 2.0f); float r2 = rx * ix / r1; __real__ res = __log1pf (rx2 + dm + 2.0f * (rx * r1 + ix * r2)) / 2.0f; if (adj) __imag__ res = __ieee754_atan2f (rx + r1, __copysignf (ix + r2, __imag__ x)); else __imag__ res = __ieee754_atan2f (ix + r2, rx + r1); } } else { float s = __ieee754_hypotf (1.0f, rx); __real__ res = __log1pf (2.0f * rx * (rx + s)) / 2.0f; if (adj) __imag__ res = __ieee754_atan2f (s, __imag__ x); else __imag__ res = __ieee754_atan2f (ix, s); } if (__real__ res < FLT_MIN) { volatile float force_underflow = __real__ res * __real__ res; (void) force_underflow; } } else { __real__ y = (rx - ix) * (rx + ix) + 1.0f; __imag__ y = 2.0f * rx * ix; y = __csqrtf (y); __real__ y += rx; __imag__ y += ix; if (adj) { float t = __real__ y; __real__ y = __copysignf (__imag__ y, __imag__ x); __imag__ y = t; } res = __clogf (y); } /* Give results the correct sign for the original argument. */ __real__ res = __copysignf (__real__ res, __real__ x); __imag__ res = __copysignf (__imag__ res, (adj ? 1.0f : __imag__ x)); return res; }
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; }