#include <float.h>
#include <math.h>
#include <complex.h>
+#include <endian.h>
#include "longdbl.h"
uint64_t bits;
};
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
+#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
+union ldshape {
+ long double f;
+ struct {
+ uint64_t m;
+ uint16_t se;
+ } i;
+};
+#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
+union ldshape {
+ long double f;
+ struct {
+ uint64_t lo;
+ uint32_t mid;
+ uint16_t top;
+ uint16_t se;
+ } i;
+ struct {
+ uint64_t lo;
+ uint64_t hi;
+ } i2;
+};
+#else
+#error Unsupported long double representation
+#endif
+
#define FORCE_EVAL(x) do { \
if (sizeof(x) == sizeof(float)) { \
volatile float __x; \
#include <float.h>
#include <stdint.h>
-#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
-#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
-union ldshape {
- long double value;
- struct {
- uint64_t m;
- uint16_t exp:15;
- uint16_t sign:1;
- uint16_t pad;
- } bits;
-};
-#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
-union ldshape {
- long double value;
- struct {
- uint64_t mlo;
- uint64_t mhi:48;
- uint16_t exp:15;
- uint16_t sign:1;
- } bits;
-};
-#else
-#error Unsupported long double representation
-#endif
-
-
// FIXME: hacks to make freebsd+openbsd long double code happy
// union and macros for freebsd
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
+/* invalid representations (top bit of u.i.m is wrong) are not handled */
int __fpclassifyl(long double x)
{
- union ldshape u = { x };
- int e = u.bits.exp;
- if (!e) {
- if (u.bits.m >> 63) return FP_NAN;
- else if (u.bits.m) return FP_SUBNORMAL;
- else return FP_ZERO;
- }
+ union ldshape u = {x};
+ int e = u.i.se & 0x7fff;
+ if (!e)
+ return u.i.m ? FP_SUBNORMAL : FP_ZERO;
if (e == 0x7fff)
- return u.bits.m & (uint64_t)-1>>1 ? FP_NAN : FP_INFINITE;
- return u.bits.m & (uint64_t)1<<63 ? FP_NORMAL : FP_NAN;
+ return u.i.m << 1 ? FP_NAN : FP_INFINITE;
+ return FP_NORMAL;
}
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
int __fpclassifyl(long double x)
{
- union ldshape u = { x };
- int e = u.bits.exp;
+ union ldshape u = {x};
+ int e = u.i.se & 0x7fff;
if (!e)
- return u.bits.mlo | u.bits.mhi ? FP_SUBNORMAL : FP_ZERO;
- if (e == 0x7fff)
- return u.bits.mlo | u.bits.mhi ? FP_NAN : FP_INFINITE;
+ return u.i2.lo | u.i2.hi ? FP_SUBNORMAL : FP_ZERO;
+ if (e == 0x7fff) {
+ u.i.se = 0;
+ return u.i2.lo | u.i2.hi ? FP_NAN : FP_INFINITE;
+ }
return FP_NORMAL;
}
#endif
#include "libm.h"
-// FIXME: should be a macro
#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
int __signbitl(long double x)
{
union ldshape u = {x};
-
- return u.bits.sign;
+ return u.i.se >> 15;
}
#endif
long double copysignl(long double x, long double y)
{
union ldshape ux = {x}, uy = {y};
-
- ux.bits.sign = uy.bits.sign;
- return ux.value;
+ ux.i.se &= 0x7fff;
+ ux.i.se |= uy.i.se & 0x8000;
+ return ux.f;
}
#endif
{
union ldshape u = {x};
- u.bits.sign = 0;
- return u.value;
+ u.i.se &= 0x7fff;
+ return u.f;
}
#endif
int ilogbl(long double x)
{
union ldshape u = {x};
- uint64_t m = u.bits.m;
- int e = u.bits.exp;
+ uint64_t m = u.i.m;
+ int e = u.i.se & 0x7fff;
if (!e) {
if (m == 0) {
- FORCE_EVAL(0/0.0f);
+ FORCE_EVAL(x/x);
return FP_ILOGB0;
}
/* subnormal x */
if (e == 0x7fff) {
FORCE_EVAL(0/0.0f);
/* in ld80 msb is set in inf */
- return m & (uint64_t)-1>>1 ? FP_ILOGBNAN : INT_MAX;
+ return m << 1 ? FP_ILOGBNAN : INT_MAX;
}
return e - 0x3fff;
}
return nextafter(x, y);
}
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
-#define MSB ((uint64_t)1<<63)
long double nextafterl(long double x, long double y)
{
union ldshape ux, uy;
return x + y;
if (x == y)
return y;
- ux.value = x;
+ ux.f = x;
if (x == 0) {
- uy.value = y;
- ux.bits.m = 1;
- ux.bits.sign = uy.bits.sign;
- } else if (x < y ^ ux.bits.sign) {
- ux.bits.m++;
- if ((ux.bits.m & ~MSB) == 0) {
- ux.bits.m = MSB;
- ux.bits.exp++;
+ 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.bits.m & ~MSB) == 0) {
- ux.bits.exp--;
- if (ux.bits.exp)
- ux.bits.m = 0;
+ if (ux.i.m << 1 == 0) {
+ ux.i.se--;
+ if (ux.i.se)
+ ux.i.m = 0;
}
- ux.bits.m--;
+ ux.i.m--;
}
- /* raise overflow if ux.value is infinite and x is finite */
- if (ux.bits.exp == 0x7fff)
+ /* raise overflow if ux is infinite and x is finite */
+ if ((ux.i.se & 0x7fff) == 0x7fff)
return x + x;
- /* raise underflow if ux.value is subnormal or zero */
- if (ux.bits.exp == 0)
- FORCE_EVAL(x*x + ux.value*ux.value);
- return ux.value;
+ /* 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;
}
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
long double nextafterl(long double x, long double y)
return x + y;
if (x == y)
return y;
- ux.value = x;
+ ux.f = x;
if (x == 0) {
- uy.value = y;
- ux.bits.mlo = 1;
- ux.bits.sign = uy.bits.sign;
- } else if (x < y ^ ux.bits.sign) {
- ux.bits.mlo++;
- if (ux.bits.mlo == 0) {
- ux.bits.mhi++;
- if (ux.bits.mhi == 0)
- ux.bits.exp++;
- }
+ uy.f = y;
+ ux.i.lo = 1;
+ ux.i.se = uy.i.se & 0x8000;
+ } else if ((x < y) == !(ux.i.se & 0x8000)) {
+ ux.i2.lo++;
+ if (ux.i2.lo == 0)
+ ux.i2.hi++;
} else {
- if (ux.bits.mlo == 0) {
- if (ux.bits.mhi == 0)
- ux.bits.exp--;
- ux.bits.mhi--;
- }
- ux.bits.mlo--;
+ if (ux.i2.lo == 0)
+ ux.i2.hi--;
+ ux.i2.lo--;
}
- /* raise overflow if ux.value is infinite and x is finite */
- if (ux.bits.exp == 0x7fff)
+ /* raise overflow if ux is infinite and x is finite */
+ if ((ux.i.se & 0x7fff) == 0x7fff)
return x + x;
- /* raise underflow if ux.value is subnormal or zero */
- if (ux.bits.exp == 0)
- FORCE_EVAL(x*x + ux.value*ux.value);
- return ux.value;
+ /* 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;
}
#endif