static long double erfc2(uint32_t ix, long double x)
{
+ union ldshape u;
long double s,z,R,S;
- uint32_t i0,i1;
if (ix < 0x3fffa000) /* 0.84375 <= |x| < 1.25 */
return erfc1(x);
S = sc[0] + s * (sc[1] + s * (sc[2] + s * (sc[3] +
s * (sc[4] + s))));
}
- z = x;
- GET_LDOUBLE_WORDS(ix, i0, i1, z);
- i1 = 0;
- i0 &= 0xffffff00;
- SET_LDOUBLE_WORDS(z, ix, i0, i1);
+ u.f = x;
+ u.i.m &= -1ULL << 40;
+ z = u.f;
return expl(-z*z - 0.5625) * expl((z - x) * (z + x) + R / S) / x;
}
long double erfl(long double x)
{
long double r, s, z, y;
- uint32_t i0, i1, ix;
- int sign;
+ union ldshape u = {x};
+ uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48;
+ int sign = u.i.se >> 15;
- GET_LDOUBLE_WORDS(ix, i0, i1, x);
- sign = ix >> 15;
- ix &= 0x7fff;
- if (ix == 0x7fff) {
+ if (ix >= 0x7fff0000)
/* erf(nan)=nan, erf(+-inf)=+-1 */
return 1 - 2*sign + 1/x;
- }
- ix = (ix << 16) | (i0 >> 16);
if (ix < 0x3ffed800) { /* |x| < 0.84375 */
if (ix < 0x3fde8000) { /* |x| < 2**-33 */
return 0.125 * (8 * x + efx8 * x); /* avoid underflow */
long double erfcl(long double x)
{
long double r, s, z, y;
- uint32_t i0, i1, ix;
- int sign;
+ union ldshape u = {x};
+ uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48;
+ int sign = u.i.se >> 15;
- GET_LDOUBLE_WORDS(ix, i0, i1, x);
- sign = ix>>15;
- ix &= 0x7fff;
- if (ix == 0x7fff)
+ if (ix >= 0x7fff0000)
/* erfc(nan) = nan, erfc(+-inf) = 0,2 */
return 2*sign + 1/x;
-
- ix = (ix << 16) | (i0 >> 16);
if (ix < 0x3ffed800) { /* |x| < 0.84375 */
if (ix < 0x3fbe0000) /* |x| < 2**-65 */
return 1.0 - x;
}
if (ix < 0x4005d600) /* |x| < 107 */
return sign ? 2 - erfc2(ix,x) : erfc2(ix,x);
- return sign ? 2 - 0x1p-16382L : 0x1p-16382L*0x1p-16382L;
+ y = 0x1p-16382L;
+ return sign ? 2 - y : y*y;
}
#endif
#include "libm.h"
#if LDBL_MANT_DIG==64 && LDBL_MAX_EXP==16384
-union ld80 {
- long double x;
- struct {
- uint64_t m;
- uint16_t e : 15;
- uint16_t s : 1;
- uint16_t pad;
- } bits;
-};
-
/* exact add, assumes exponent_x >= exponent_y */
static void add(long double *hi, long double *lo, long double x, long double y)
{
*/
static long double adjust(long double hi, long double lo)
{
- union ld80 uhi, ulo;
+ union ldshape uhi, ulo;
if (lo == 0)
return hi;
- uhi.x = hi;
- if (uhi.bits.m & 0x3ff)
+ uhi.f = hi;
+ if (uhi.i.m & 0x3ff)
return hi;
- ulo.x = lo;
- if (uhi.bits.s == ulo.bits.s)
- uhi.bits.m++;
+ ulo.f = lo;
+ if ((uhi.i.se & 0x8000) == (ulo.i.se & 0x8000))
+ uhi.i.m++;
else {
- uhi.bits.m--;
/* handle underflow and take care of ld80 implicit msb */
- if (uhi.bits.m == (uint64_t)-1/2) {
- uhi.bits.m *= 2;
- uhi.bits.e--;
+ if (uhi.i.m << 1 == 0) {
+ uhi.i.m = 0;
+ uhi.i.se--;
}
+ uhi.i.m--;
}
- return uhi.x;
+ return uhi.f;
}
/* adjusted add so the result is correct when rounded to double (or less) precision */
static int getexp(long double x)
{
- union ld80 u;
- u.x = x;
- return u.bits.e;
+ union ldshape u;
+ u.f = x;
+ return u.i.se & 0x7fff;
}
double fma(double x, double y, double z)
}
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
#include <fenv.h>
+#if LDBL_MANT_DIG == 64
+#define LASTBIT(u) (u.i.m & 1)
+#define SPLIT (0x1p32L + 1)
+#elif LDBL_MANT_DIG == 113
+#define LASTBIT(u) (u.i.lo & 1)
+#define SPLIT (0x1p57L + 1)
+#endif
/*
* A struct dd represents a floating-point number with twice the precision
static inline long double add_adjusted(long double a, long double b)
{
struct dd sum;
- union IEEEl2bits u;
+ union ldshape u;
sum = dd_add(a, b);
if (sum.lo != 0) {
- u.e = sum.hi;
- if ((u.bits.manl & 1) == 0)
+ u.f = sum.hi;
+ if (!LASTBIT(u))
sum.hi = nextafterl(sum.hi, INFINITY * sum.lo);
}
return (sum.hi);
{
struct dd sum;
int bits_lost;
- union IEEEl2bits u;
+ union ldshape u;
sum = dd_add(a, b);
* break the ties manually.
*/
if (sum.lo != 0) {
- u.e = sum.hi;
- bits_lost = -u.bits.exp - scale + 1;
- if (bits_lost != 1 ^ (int)(u.bits.manl & 1))
+ u.f = sum.hi;
+ bits_lost = -u.i.se - scale + 1;
+ if ((bits_lost != 1) ^ LASTBIT(u))
sum.hi = nextafterl(sum.hi, INFINITY * sum.lo);
}
return scalbnl(sum.hi, scale);
*/
static inline struct dd dd_mul(long double a, long double b)
{
-#if LDBL_MANT_DIG == 64
- static const long double split = 0x1p32L + 1.0;
-#elif LDBL_MANT_DIG == 113
- static const long double split = 0x1p57L + 1.0;
-#endif
struct dd ret;
long double ha, hb, la, lb, p, q;
- p = a * split;
+ p = a * SPLIT;
ha = a - p;
ha += p;
la = a - ha;
- p = b * split;
+ p = b * SPLIT;
hb = b - p;
hb += p;
lb = b - hb;
static long double sin_pi(long double x)
{
+ union ldshape u = {x};
+ uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48;
long double y, z;
- int n, ix;
- uint32_t se, i0, i1;
+ int n;
- GET_LDOUBLE_WORDS(se, i0, i1, x);
- ix = se & 0x7fff;
- ix = (ix << 16) | (i0 >> 16);
if (ix < 0x3ffd8000) /* 0.25 */
return sinl(pi * x);
y = -x; /* x is assume negative */
} else {
if (ix < 0x403e8000) /* 2^63 */
z = y + two63; /* exact */
- GET_LDOUBLE_WORDS(se, i0, i1, z);
- n = i1 & 1;
+ u.f = z;
+ n = u.i.m & 1;
y = n;
n <<= 2;
}
long double __lgammal_r(long double x, int *sg) {
long double t, y, z, nadj, p, p1, p2, q, r, w;
- int i, ix;
- uint32_t se, i0, i1;
+ union ldshape u = {x};
+ uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48;
+ int sign = u.i.se >> 15;
+ int i;
*sg = 1;
- GET_LDOUBLE_WORDS(se, i0, i1, x);
- ix = se & 0x7fff;
-
- if ((ix | i0 | i1) == 0) {
- if (se & 0x8000)
- *sg = -1;
- return 1.0 / fabsl(x);
- }
-
- ix = (ix << 16) | (i0 >> 16);
/* purge off +-inf, NaN, +-0, and negative arguments */
if (ix >= 0x7fff0000)
return x * x;
-
+ if (x == 0) {
+ *sg -= 2*sign;
+ return 1.0 / fabsl(x);
+ }
if (ix < 0x3fc08000) { /* |x|<2**-63, return -log(|x|) */
- if (se & 0x8000) {
+ if (sign) {
*sg = -1;
return -logl(-x);
}
return -logl(x);
}
- if (se & 0x8000) {
+ if (sign) {
t = sin_pi (x);
if (t == 0.0)
return 1.0 / fabsl(t); /* -integer */
x = -x;
}
- /* purge off 1 and 2 */
- if ((((ix - 0x3fff8000) | i0 | i1) == 0) ||
- (((ix - 0x40008000) | i0 | i1) == 0))
- r = 0;
- else if (ix < 0x40008000) { /* x < 2.0 */
+ if (ix < 0x40008000) { /* x < 2.0 */
if (ix <= 0x3ffee666) { /* 8.99993896484375e-1 */
/* lgamma(x) = lgamma(x+1) - log(x) */
r = -logl(x);
r = (x - 0.5) * (t - 1.0) + w;
} else /* 2**66 <= x <= inf */
r = x * (logl(x) - 1.0);
- if (se & 0x8000)
+ if (sign)
r = nadj - r;
return r;
}
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
long double scalbnl(long double x, int n)
{
- union IEEEl2bits scale;
+ union ldshape u;
if (n > 16383) {
x *= 0x1p16383L;
n = -16382;
}
}
- scale.e = 1.0;
- scale.bits.exp = 0x3fff + n;
- return x * scale.e;
+ u.f = 1.0;
+ u.i.se = 0x3fff + n;
+ return x * u.f;
}
#endif