double nexttoward(double x, long double y) { union {double f; uint64_t i;} ux = {x}; int e; if (isnan(x) || isnan(y)) return x + y; if (x == y) return y; if (x == 0) { ux.i = 1; if (signbit(y)) ux.i |= 1ULL<<63; } else if (x < y) { if (signbit(x)) ux.i--; else ux.i++; } else { if (signbit(x)) ux.i++; else ux.i--; } e = ux.i>>52 & 0x7ff; /* raise overflow if ux.f is infinite and x is finite */ if (e == 0x7ff) FORCE_EVAL(x+x); /* raise underflow if ux.f is subnormal or zero */ if (e == 0) FORCE_EVAL(x*x + ux.f*ux.f); return ux.f; }
double exp(double x) { double_t hi, lo, c, xx, y; int k, sign; uint32_t hx; GET_HIGH_WORD(hx, x); sign = hx>>31; hx &= 0x7fffffff; /* high word of |x| */ /* special cases */ if (hx >= 0x4086232b) { /* if |x| >= 708.39... */ if (isnan(x)) return x; if (x > 709.782712893383973096) { /* overflow if x!=inf */ x *= 0x1p1023; return x; } if (x < -708.39641853226410622) { /* underflow if x!=-inf */ FORCE_EVAL((float)(-0x1p-149/x)); if (x < -745.13321910194110842) return 0; } } /* argument reduction */ if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ if (hx >= 0x3ff0a2b2) /* if |x| >= 1.5 ln2 */ k = (int)(invln2*x + half[sign]); else k = 1 - sign - sign; hi = x - k*ln2hi; /* k*ln2hi is exact here */ lo = k*ln2lo; x = hi - lo; } else if (hx > 0x3e300000) { /* if |x| > 2**-28 */ k = 0; hi = x; lo = 0; } else { /* inexact if x!=0 */ FORCE_EVAL(0x1p1023 + x); return 1 + x; } /* x is now in primary range */ xx = x*x; c = x - xx*(__EXP_P1+xx*(__EXP_P2+xx*(__EXP_P3+xx*(__EXP_P4+xx*__EXP_P5)))); y = 1 + (x*c/(2-c) - lo + hi); if (k == 0) return y; return scalbn(y, k); }
float expf(float x) { float_t hi, lo, c, xx, y; int k, sign; uint32_t hx; GET_FLOAT_WORD(hx, x); sign = hx >> 31; /* sign bit of x */ hx &= 0x7fffffff; /* high word of |x| */ /* special cases */ if (hx >= 0x42aeac50) { /* if |x| >= -87.33655f or NaN */ if (hx >= 0x42b17218 && !sign) { /* x >= 88.722839f */ /* overflow */ x *= 0x1p127f; return x; } if (sign) { /* underflow */ FORCE_EVAL(-0x1p-149f/x); if (hx >= 0x42cff1b5) /* x <= -103.972084f */ return 0; } } /* argument reduction */ if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */ k = invln2*x + half[sign]; else k = 1 - sign - sign; hi = x - k*ln2hi; /* k*ln2hi is exact here */ lo = k*ln2lo; x = hi - lo; } else if (hx > 0x39000000) { /* |x| > 2**-14 */ k = 0; hi = x; lo = 0; } else { /* raise inexact */ FORCE_EVAL(0x1p127f + x); return 1 + x; } /* x is now in primary range */ xx = x*x; c = x - xx*(P1+xx*P2); y = 1 + (x*c/(2-c) - lo + hi); if (k == 0) return y; return scalbnf(y, k); }
long double tanl(long double x) { union IEEEl2bits z; long double y[2]; unsigned n; z.e = x; z.bits.sign = 0; /* If x = NaN or Inf, then tan(x) = NaN. */ if (z.bits.exp == 0x7fff) return (x - x) / (x - x); /* |x| < (double)pi/4 */ if (z.e < M_PI_4) { /* |x| < 0x1p-64 */ if (z.bits.exp < 0x3fff - 64) { /* raise inexact if x!=0 and underflow if subnormal */ FORCE_EVAL(z.bits.exp == 0 ? x/0x1p120f : x+0x1p120f); return x; } return __tanl(x, 0, 0); } n = __rem_pio2l(x, y); return __tanl(y[0], y[1], n&1); }
/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ float asinhf(float x) { union { float f; uint32_t i; } u = {.f = x}; uint32_t i = u.i & 0x7fffffff; unsigned s = u.i >> 31; /* |x| */ u.i = i; x = u.f; if (i >= 0x3f800000 + (12 << 23)) { /* |x| >= 0x1p12 or inf or nan */ x = logf(x) + 0.693147180559945309417232121458176568f; } else if (i >= 0x3f800000 + (1 << 23)) { /* |x| >= 2 */ x = logf(2 * x + 1 / (sqrtf(x * x + 1) + x)); } else if (i >= 0x3f800000 - (12 << 23)) { /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ x = log1pf(x + x * x / (sqrtf(x * x + 1) + 1)); } else { /* |x| < 0x1p-12, raise inexact if x!=0 */ FORCE_EVAL(x + 0x1p120f); } return s ? -x : x; }
long double coshl(long double x) { union ldshape u = {x}; unsigned ex = u.i.se & 0x7fff; uint32_t w; long double t; /* |x| */ u.i.se = ex; x = u.f; w = u.i.m >> 32; /* |x| < log(2) */ if (ex < 0x3fff-1 || (ex == 0x3fff-1 && w < 0xb17217f7)) { if (ex < 0x3fff-32) { FORCE_EVAL(x + 0x1p120f); return 1; } t = expm1l(x); return 1 + t*t/(2*(1+t)); } /* |x| < log(LDBL_MAX) */ if (ex < 0x3fff+13 || (ex == 0x3fff+13 && w < 0xb17217f7)) { t = expl(x); return 0.5*(t + 1/t); } /* |x| > log(LDBL_MAX) or nan */ t = expl(0.5*x); return 0.5*t*t; }
double nexttoward(double x, long double y) { union dshape ux; int e; if (isnan(x) || isnan(y)) return x + y; if (x == y) return y; ux.value = x; if (x == 0) { ux.bits = 1; if (signbit(y)) ux.bits |= SIGN; } else if (x < y) { if (signbit(x)) ux.bits--; else ux.bits++; } else { if (signbit(x)) ux.bits++; else ux.bits--; } e = ux.bits>>52 & 0x7ff; /* raise overflow if ux.value is infinite and x is finite */ if (e == 0x7ff) return x + x; /* raise underflow if ux.value is subnormal or zero */ if (e == 0) FORCE_EVAL(x*x + ux.value*ux.value); return ux.value; }
float coshf(float x) { union {float f; uint32_t i;} u = {.f = x}; uint32_t w; float t; /* |x| */ u.i &= 0x7fffffff; x = u.f; w = u.i; /* |x| < log(2) */ if (w < 0x3f317217) { if (w < 0x3f800000 - (12<<23)) { FORCE_EVAL(x + 0x1p120f); return 1; } t = expm1f(x); return 1 + t*t/(2*(1+t)); } /* |x| < log(FLT_MAX) */ if (w < 0x42b17217) { t = expf(x); return 0.5f*(t + 1/t); } /* |x| > log(FLT_MAX) or nan */ t = __expo2f(x); return t; }
/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ long double asinhl(long double x) { union ldshape u = {x}; unsigned e = u.i.se & 0x7fff; unsigned s = u.i.se >> 15; /* |x| */ u.i.se = e; x = u.f; if (e >= 0x3fff + 32) { /* |x| >= 0x1p32 or inf or nan */ x = logl(x) + 0.693147180559945309417232121458176568L; } else if (e >= 0x3fff + 1) { /* |x| >= 2 */ x = logl(2*x + 1/(sqrtl(x*x+1)+x)); } else if (e >= 0x3fff - 32) { /* |x| >= 0x1p-32 */ x = log1pl(x + x*x/(sqrtl(x*x+1)+1)); } else { /* |x| < 0x1p-32, raise inexact if x!=0 */ FORCE_EVAL(x + 0x1p120f); } return s ? -x : x; }
double tan(double x) { double y[2]; uint32_t ix; unsigned n; GET_HIGH_WORD(ix, x); ix &= 0x7fffffff; /* |x| ~< pi/4 */ if (ix <= 0x3fe921fb) { if (ix < 0x3e400000) { /* |x| < 2**-27 */ /* raise inexact if x!=0 and underflow if subnormal */ FORCE_EVAL(ix < 0x00100000 ? x / 0x1p120f : x + 0x1p120f); return x; } return __tan(x, 0.0, 0); } /* tan(Inf or NaN) is NaN */ if (ix >= 0x7ff00000) return x - x; /* argument reduction */ n = __rem_pio2(x, y); return __tan(y[0], y[1], n & 1); }
double _mysin(double x) { double y[2]; uint32_t ix; unsigned n; /* High word of x. */ GET_HIGH_WORD(ix, x); ix &= 0x7fffffff; /* |x| ~< pi/4 */ if (ix <= 0x3fe921fb) { if (ix < 0x3e500000) { /* |x| < 2**-26 */ /* raise inexact if x != 0 and underflow if subnormal*/ FORCE_EVAL(ix < 0x00100000 ? x/get_0x1p120f() : x+get_0x1p120f()); return x; } return my__sin(x, 0.0, 0); } /* sin(Inf or NaN) is NaN */ if (ix >= 0x7ff00000) return x - x; /* argument reduction needed */ n = my__rem_pio2(x, y); switch (n&3) { case 0: return my__sin(y[0], y[1], 1); case 1: return my__cos(y[0], y[1]); case 2: return -my__sin(y[0], y[1], 1); default: return -my__cos(y[0], y[1]); } }
long double sinl(long double x) { union ldshape u = {x}; unsigned n; long double y[2], hi, lo; u.i.se &= 0x7fff; if (u.i.se == 0x7fff) return x - x; if (u.f < M_PI_4) { if (u.i.se < 0x3fff - LDBL_MANT_DIG/2) { /* raise inexact if x!=0 and underflow if subnormal */ FORCE_EVAL(u.i.se == 0 ? x*0x1p-120f : x+0x1p120f); return x; } return __sinl(x, 0.0, 0); } n = __rem_pio2l(x, y); hi = y[0]; lo = y[1]; switch (n & 3) { case 0: return __sinl(hi, lo, 1); case 1: return __cosl(hi, lo); case 2: return -__sinl(hi, lo, 1); case 3: default: return -__cosl(hi, lo); } }
/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ double atanh(double x) { union {double f; uint64_t i;} u = {.f = x}; unsigned e = u.i >> 52 & 0x7ff; unsigned s = u.i >> 63; double_t y; /* |x| */ u.i &= (uint64_t)-1/2; y = u.f; if (e < 0x3ff - 1) { if (e < 0x3ff - 32) { /* handle underflow */ if (e == 0) FORCE_EVAL((float)y); } else { /* |x| < 0.5, up to 1.7ulp error */ y = 0.5*log1p(2*y + 2*y*y/(1-y)); } } else { /* avoid overflow */ y = 0.5*log1p(2*(y/(1-y))); } return s ? -y : y; }
/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ float atanhf(float x) { union {float f; uint32_t i;} u = {.f = x}; unsigned s = u.i >> 31; float_t y; /* |x| */ u.i &= 0x7fffffff; y = u.f; if (u.i < 0x3f800000 - (1<<23)) { if (u.i < 0x3f800000 - (32<<23)) { /* handle underflow */ if (u.i < (1<<23)) FORCE_EVAL((float)(y*y)); } else { /* |x| < 0.5, up to 1.7ulp error */ y = 0.5f*log1pf(2*y + 2*y*y/(1-y)); } } else { /* avoid overflow */ y = 0.5f*log1pf(2*(y/(1-y))); } return s ? -y : y; }
long double nextafterl(long double x, long double y) { union ldshape ux, uy; if (isnan(x) || isnan(y)) return x + y; if (x == y) return y; ux.f = x; if (x == 0) { uy.f = y; ux.i.m = 1; ux.i.se = uy.i.se & 0x8000; } else if ((x < y) == !(ux.i.se & 0x8000)) { ux.i.m++; if (ux.i.m << 1 == 0) { ux.i.m = 1ULL << 63; ux.i.se++; } } else { if (ux.i.m << 1 == 0) { ux.i.se--; if (ux.i.se) ux.i.m = 0; } ux.i.m--; } /* raise overflow if ux is infinite and x is finite */ if ((ux.i.se & 0x7fff) == 0x7fff) return x + x; /* raise underflow if ux is subnormal or zero */ if ((ux.i.se & 0x7fff) == 0) FORCE_EVAL(x*x + ux.f*ux.f); return ux.f; }
/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ double asinh(double x) { union {double f; uint64_t i;} u = {.f = x}; unsigned e = u.i >> 52 & 0x7ff; unsigned s = u.i >> 63; /* |x| */ u.i &= (uint64_t)-1/2; x = u.f; if (e >= 0x3ff + 26) { /* |x| >= 0x1p26 or inf or nan */ x = log(x) + 0.693147180559945309417232121458176568; } else if (e >= 0x3ff + 1) { /* |x| >= 2 */ x = log(2*x + 1/(sqrt(x*x+1)+x)); } else if (e >= 0x3ff - 26) { /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ x = log1p(x + x*x/(sqrt(x*x+1)+1)); } else { /* |x| < 0x1p-26, raise inexact if x != 0 */ FORCE_EVAL(x + 0x1p120f); } return s ? -x : x; }
long double atanl(long double x) { union ldshape u = {x}; long double w, s1, s2, z; int id; unsigned e = u.i.se & 0x7fff; unsigned sign = u.i.se >> 15; unsigned expman; if (e >= 0x3fff + LDBL_MANT_DIG + 1) { /* if |x| is large, atan(x)~=pi/2 */ if (isnan(x)) return x; return sign ? -atanhi[3] : atanhi[3]; } /* Extract the exponent and the first few bits of the mantissa. */ expman = EXPMAN(u); if (expman < ((0x3fff - 2) << 8) + 0xc0) { /* |x| < 0.4375 */ if (e < 0x3fff - (LDBL_MANT_DIG+1)/2) { /* if |x| is small, atanl(x)~=x */ /* raise underflow if subnormal */ if (e == 0) FORCE_EVAL((float)x); return x; } id = -1; } else { x = fabsl(x); if (expman < (0x3fff << 8) + 0x30) { /* |x| < 1.1875 */ if (expman < ((0x3fff - 1) << 8) + 0x60) { /* 7/16 <= |x| < 11/16 */ id = 0; x = (2.0*x-1.0)/(2.0+x); } else { /* 11/16 <= |x| < 19/16 */ id = 1; x = (x-1.0)/(x+1.0); } } else { if (expman < ((0x3fff + 1) << 8) + 0x38) { /* |x| < 2.4375 */ id = 2; x = (x-1.5)/(1.0+1.5*x); } else { /* 2.4375 <= |x| */ id = 3; x = -1.0/x; } } } /* end of argument reduction */ z = x*x; w = z*z; /* break sum aT[i]z**(i+1) into odd and even poly */ s1 = z*T_even(w); s2 = w*T_odd(w); if (id < 0) return x - x*(s1+s2); z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); return sign ? -z : z; }
float cosf(float x) { double y; uint32_t ix; unsigned n, sign; GET_FLOAT_WORD(ix, x); sign = ix >> 31; ix &= 0x7fffffff; if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ if (ix < 0x39800000) { /* |x| < 2**-12 */ /* raise inexact if x != 0 */ FORCE_EVAL(x + 0x1p120f); return 1.0f; } return __cosdf(x); } if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ if (ix > 0x4016cbe3) /* |x| ~> 3*pi/4 */ return -__cosdf(sign ? x + c2pio2 : x - c2pio2); else { if (sign) return __sindf(x + c1pio2); else return __sindf(c1pio2 - x); } } if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ if (ix > 0x40afeddf) /* |x| ~> 7*pi/4 */ return __cosdf(sign ? x + c4pio2 : x - c4pio2); else { if (sign) return __sindf(-x - c3pio2); else return __sindf(x - c3pio2); } } /* cos(Inf or NaN) is NaN */ if (ix >= 0x7f800000) return x - x; /* general argument reduction needed */ n = __rem_pio2f(x, &y); switch (n & 3) { case 0: return __cosdf(y); case 1: return __sindf(-y); case 2: return -__cosdf(y); default: return __sindf(y); } }
void sincos(double x, double *sin, double *cos) { double y[2], s, c; uint32_t ix; unsigned n; GET_HIGH_WORD(ix, x); ix &= 0x7fffffff; /* |x| ~< pi/4 */ if (ix <= 0x3fe921fb) { /* if |x| < 2**-27 * sqrt(2) */ if (ix < 0x3e46a09e) { /* raise inexact if x!=0 and underflow if subnormal */ FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); *sin = x; *cos = 1.0; return; } *sin = __sin(x, 0.0, 0); *cos = __cos(x, 0.0); return; } /* sincos(Inf or NaN) is NaN */ if (ix >= 0x7ff00000) { *sin = *cos = x - x; return; } /* argument reduction needed */ n = __rem_pio2(x, y); s = __sin(y[0], y[1], 1); c = __cos(y[0], y[1]); switch (n&3) { case 0: *sin = s; *cos = c; break; case 1: *sin = c; *cos = -s; break; case 2: *sin = -s; *cos = -c; break; case 3: default: *sin = -c; *cos = s; break; } }
void sincosl(long double x, long double *sin, long double *cos) { union IEEEl2bits u; unsigned n; long double y[2], s, c; u.e = x; u.bits.sign = 0; /* x = nan or inf */ if (u.bits.exp == 0x7fff) { *sin = *cos = x - x; return; } /* |x| < (double)pi/4 */ if (u.e < M_PI_4) { /* |x| < 0x1p-64 */ if (u.bits.exp < 0x3fff - 64) { /* raise underflow if subnormal */ if (u.bits.exp == 0) FORCE_EVAL(x*0x1p-120f); *sin = x; /* raise inexact if x!=0 */ *cos = 1.0 + x; return; } *sin = __sinl(x, 0, 0); *cos = __cosl(x, 0); return; } n = __rem_pio2l(x, y); s = __sinl(y[0], y[1], 1); c = __cosl(y[0], y[1]); switch (n & 3) { case 0: *sin = s; *cos = c; break; case 1: *sin = c; *cos = -s; break; case 2: *sin = -s; *cos = -c; break; case 3: default: *sin = -c; *cos = s; break; } }
double atan(double x) { double_t w,s1,s2,z; uint32_t ix,sign; int id; GET_HIGH_WORD(ix, x); sign = ix >> 31; ix &= 0x7fffffff; if (ix >= 0x44100000) { /* if |x| >= 2^66 */ if (isnan(x)) return x; z = atanhi[3] + 0x1p-120f; return sign ? -z : z; } if (ix < 0x3fdc0000) { /* |x| < 0.4375 */ if (ix < 0x3e400000) { /* |x| < 2^-27 */ if (ix < 0x00100000) /* raise underflow for subnormal x */ FORCE_EVAL((float)x); return x; } id = -1; } else { x = fabs(x); if (ix < 0x3ff30000) { /* |x| < 1.1875 */ if (ix < 0x3fe60000) { /* 7/16 <= |x| < 11/16 */ id = 0; x = (2.0*x-1.0)/(2.0+x); } else { /* 11/16 <= |x| < 19/16 */ id = 1; x = (x-1.0)/(x+1.0); } } else { if (ix < 0x40038000) { /* |x| < 2.4375 */ id = 2; x = (x-1.5)/(1.0+1.5*x); } else { /* 2.4375 <= |x| < 2^66 */ id = 3; x = -1.0/x; } } } /* end of argument reduction */ z = x*x; w = z*z; /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10]))))); s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9])))); if (id < 0) return x - x*(s1+s2); z = atanhi[id] - (x*(s1+s2) - atanlo[id] - x); return sign ? -z : z; }
float atanf(float x) { float_t w,s1,s2,z; uint32_t ix,sign; int id; GET_FLOAT_WORD(ix, x); sign = ix>>31; ix &= 0x7fffffff; if (ix >= 0x4c800000) { /* if |x| >= 2**26 */ if (isnan(x)) return x; z = atanhi[3] + 0x1p-120f; return sign ? -z : z; } if (ix < 0x3ee00000) { /* |x| < 0.4375 */ if (ix < 0x39800000) { /* |x| < 2**-12 */ if (ix < 0x00800000) /* raise underflow for subnormal x */ FORCE_EVAL(x*x); return x; } id = -1; } else { x = fabsf(x); if (ix < 0x3f980000) { /* |x| < 1.1875 */ if (ix < 0x3f300000) { /* 7/16 <= |x| < 11/16 */ id = 0; x = (2.0f*x - 1.0f)/(2.0f + x); } else { /* 11/16 <= |x| < 19/16 */ id = 1; x = (x - 1.0f)/(x + 1.0f); } } else { if (ix < 0x401c0000) { /* |x| < 2.4375 */ id = 2; x = (x - 1.5f)/(1.0f + 1.5f*x); } else { /* 2.4375 <= |x| < 2**26 */ id = 3; x = -1.0f/x; } } } /* end of argument reduction */ z = x*x; w = z*z; /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */ s1 = z*(aT[0]+w*(aT[2]+w*aT[4])); s2 = w*(aT[1]+w*aT[3]); if (id < 0) return x - x*(s1+s2); z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x); return sign ? -z : z; }
int ilogb(double x) { union dshape u = {x}; int e = u.bits>>52 & 0x7ff; if (!e) { u.bits <<= 12; if (u.bits == 0) { FORCE_EVAL(0/0.0f); return FP_ILOGB0; } /* subnormal x */ for (e = -0x3ff; u.bits < (uint64_t)1<<63; e--, u.bits<<=1); return e; } if (e == 0x7ff) { FORCE_EVAL(0/0.0f); return u.bits<<12 ? FP_ILOGBNAN : INT_MAX; } return e - 0x3ff; }
int ilogbl(long double x) { PRAGMA_STDC_FENV_ACCESS_ON union ldshape u = {x}; int e = u.i.se & 0x7fff; if (!e) { if (x == 0) { FORCE_EVAL(0 / 0.0f); return FP_ILOGB0; } /* subnormal x */ x *= 0x1p120; return ilogbl(x) - 120; } if (e == 0x7fff) { FORCE_EVAL(0 / 0.0f); u.i.se = 0; return u.f ? FP_ILOGBNAN : INT_MAX; } return e - 0x3fff; }
int ilogbl(long double x) { PRAGMA_STDC_FENV_ACCESS_ON union ldshape u = {x}; uint64_t m = u.i.m; int e = u.i.se & 0x7fff; if (!e) { if (m == 0) { FORCE_EVAL(0 / 0.0f); return FP_ILOGB0; } /* subnormal x */ for (e = -0x3fff + 1; m >> 63 == 0; e--, m <<= 1) ; return e; } if (e == 0x7fff) { FORCE_EVAL(0 / 0.0f); return m << 1 ? FP_ILOGBNAN : INT_MAX; } return e - 0x3fff; }
float sinf(float x) { double y; uint32_t ix; int n, sign; GET_FLOAT_WORD(ix, x); sign = ix >> 31; ix &= 0x7fffffff; if (ix <= 0x3f490fda) { /* |x| ~<= pi/4 */ if (ix < 0x39800000) { /* |x| < 2**-12 */ /* raise inexact if x!=0 and underflow if subnormal */ FORCE_EVAL(ix < 0x00800000 ? x/0x1p120f : x+0x1p120f); return x; } return __sindf(x); } if (ix <= 0x407b53d1) { /* |x| ~<= 5*pi/4 */ if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ if (sign) return -__cosdf(x + s1pio2); else return __cosdf(x - s1pio2); } return __sindf(sign ? -(x + s2pio2) : -(x - s2pio2)); } if (ix <= 0x40e231d5) { /* |x| ~<= 9*pi/4 */ if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ if (sign) return __cosdf(x + s3pio2); else return -__cosdf(x - s3pio2); } return __sindf(sign ? x + s4pio2 : x - s4pio2); } /* sin(Inf or NaN) is NaN */ if (ix >= 0x7f800000) return x - x; /* general argument reduction needed */ n = __rem_pio2f(x, &y); switch (n&3) { case 0: return __sindf(y); case 1: return __cosdf(y); case 2: return __sindf(-y); default: return -__cosdf(y); } }
long double tanl(long double x) { union ldshape u = {x}; long double y[2]; unsigned n; u.i.se &= 0x7fff; if (u.i.se == 0x7fff) return x - x; if (u.f < M_PI_4) { if (u.i.se < 0x3fff - LDBL_MANT_DIG / 2) { /* raise inexact if x!=0 and underflow if subnormal */ FORCE_EVAL(u.i.se == 0 ? x * 0x1p-120f : x + 0x1p120f); return x; } return __tanl(x, 0, 0); } n = __rem_pio2l(x, y); return __tanl(y[0], y[1], n & 1); }
int ilogb(double x) { PRAGMA_STDC_FENV_ACCESS_ON union { double f; uint64_t i; } u = {x}; uint64_t i = u.i; int e = i>>52 & 0x7ff; if (!e) { i <<= 12; if (i == 0) { FORCE_EVAL(0/0.0f); return FP_ILOGB0; } /* subnormal x */ for (e = -0x3ff; i>>63 == 0; e--, i<<=1); return e; }
/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) */ double tanh(double x) { union { double f; uint64_t i; } u = {.f = x}; uint32_t w; int sign; double_t t; /* x = |x| */ sign = u.i >> 63; u.i &= (uint64_t)-1 / 2; x = u.f; w = u.i >> 32; if (w > 0x3fe193ea) { /* |x| > log(3)/2 ~= 0.5493 or nan */ if (w > 0x40340000) { /* |x| > 20 or nan */ /* note: this branch avoids raising overflow */ t = 1 - 0 / x; } else { t = expm1(2 * x); t = 1 - 2 / (t + 2); } } else if (w > 0x3fd058ae) { /* |x| > log(5/3)/2 ~= 0.2554 */ t = expm1(2 * x); t = t / (t + 2); } else if (w >= 0x00100000) { /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ t = expm1(-2 * x); t = -t / (t + 2); } else { /* |x| is subnormal */ /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ FORCE_EVAL((float)x); t = x; } return sign ? -t : t; }
/* * exp2f(x): compute the base 2 exponential of x * * Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. * * Method: (equally-spaced tables) * * Reduce x: * x = k + y, for integer k and |y| <= 1/2. * Thus we have exp2f(x) = 2**k * exp2(y). * * Reduce y: * y = i/TBLSIZE + z for integer i near y * TBLSIZE. * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), * with |z| <= 2**-(TBLSIZE+1). * * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a * degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. * Using double precision for everything except the reduction makes * roundoff error insignificant and simplifies the scaling step. * * This method is due to Tang, but I do not use his suggested parameters: * * Tang, P. Table-driven Implementation of the Exponential Function * in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). */ float exp2f(float x) { double_t t, r, z; union {float f; uint32_t i;} u = {x}; union {double f; uint64_t i;} uk; uint32_t ix, i0, k; /* Filter out exceptional cases. */ ix = u.i & 0x7fffffff; if (ix > 0x42fc0000) { /* |x| > 126 */ if (u.i >= 0x43000000 && u.i < 0x80000000) { /* x >= 128 */ x *= 0x1p127f; return x; } if (u.i >= 0x80000000) { /* x < -126 */ if (u.i >= 0xc3160000 || (u.i & 0x0000ffff)) FORCE_EVAL(-0x1p-149f/x); if (u.i >= 0xc3160000) /* x <= -150 */ return 0; } } else if (ix <= 0x33000000) { /* |x| <= 0x1p-25 */ return 1.0f + x; } /* Reduce x, computing z, i0, and k. */ u.f = x + redux; i0 = u.i; i0 += TBLSIZE / 2; k = i0 / TBLSIZE; uk.i = (uint64_t)(0x3ff + k)<<52; i0 &= TBLSIZE - 1; u.f -= redux; z = x - u.f; /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ r = exp2ft[i0]; t = r * z; r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4); /* Scale by 2**k */ return r * uk.f; }