math: rewrite remainder functions (remainder, remquo, fmod, modf)
authorSzabolcs Nagy <nsz@port70.net>
Tue, 3 Sep 2013 04:09:12 +0000 (04:09 +0000)
committerSzabolcs Nagy <nsz@port70.net>
Thu, 5 Sep 2013 11:30:07 +0000 (11:30 +0000)
* results are exact
* modfl follows truncl (raises inexact flag spuriously now)
* modf and modff only had cosmetic cleanup
* remainder is just a wrapper around remquo now
* using iterative shift+subtract for remquo and fmod
* ld80 and ld128 are supported as well

src/math/fmod.c
src/math/fmodf.c
src/math/fmodl.c
src/math/modf.c
src/math/modff.c
src/math/modfl.c
src/math/remainder.c
src/math/remainderf.c
src/math/remquo.c
src/math/remquof.c
src/math/remquol.c

index 84a1b4a..6849722 100644 (file)
-/* origin: FreeBSD /usr/src/lib/msun/src/e_fmod.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/*
- * fmod(x,y)
- * Return x mod y in exact arithmetic
- * Method: shift and subtract
- */
-
-#include "libm.h"
-
-static const double Zero[] = {0.0, -0.0,};
+#include <math.h>
+#include <stdint.h>
 
 double fmod(double x, double y)
 {
-       int32_t n,hx,hy,hz,ix,iy,sx,i;
-       uint32_t lx,ly,lz;
+       union {double f; uint64_t i;} ux = {x}, uy = {y};
+       int ex = ux.i>>52 & 0x7ff;
+       int ey = uy.i>>52 & 0x7ff;
+       int sx = ux.i>>63;
+       uint64_t i;
 
-       EXTRACT_WORDS(hx, lx, x);
-       EXTRACT_WORDS(hy, ly, y);
-       sx = hx & 0x80000000;  /* sign of x */
-       hx ^= sx;              /* |x| */
-       hy &= 0x7fffffff;      /* |y| */
+       /* in the followings uxi should be ux.i, but then gcc wrongly adds */
+       /* float load/store to inner loops ruining performance and code size */
+       uint64_t uxi = ux.i;
 
-       /* purge off exception values */
-       if ((hy|ly) == 0 || hx >= 0x7ff00000 ||  /* y=0,or x not finite */
-           (hy|((ly|-ly)>>31)) > 0x7ff00000)    /* or y is NaN */
+       if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff)
                return (x*y)/(x*y);
-       if (hx <= hy) {
-               if (hx < hy || lx < ly)  /* |x| < |y| */
-                       return x;
-               if (lx == ly)            /* |x| = |y|, return x*0 */
-                       return Zero[(uint32_t)sx>>31];
+       if (uxi<<1 <= uy.i<<1) {
+               if (uxi<<1 == uy.i<<1)
+                       return 0*x;
+               return x;
        }
 
-       /* determine ix = ilogb(x) */
-       if (hx < 0x00100000) {  /* subnormal x */
-               if (hx == 0) {
-                       for (ix = -1043, i = lx; i > 0; i <<= 1)
-                               ix -= 1;
-               } else {
-                       for (ix = -1022, i = hx<<11; i > 0; i <<= 1)
-                               ix -= 1;
-               }
-       } else
-               ix = (hx>>20) - 1023;
-
-       /* determine iy = ilogb(y) */
-       if (hy < 0x00100000) {  /* subnormal y */
-               if (hy == 0) {
-                       for (iy = -1043, i = ly; i > 0; i <<= 1)
-                               iy -= 1;
-               } else {
-                       for (iy = -1022, i = hy<<11; i > 0; i <<= 1)
-                               iy -= 1;
-               }
-       } else
-               iy = (hy>>20) - 1023;
-
-       /* set up {hx,lx}, {hy,ly} and align y to x */
-       if (ix >= -1022)
-               hx = 0x00100000|(0x000fffff&hx);
-       else {       /* subnormal x, shift x to normal */
-               n = -1022-ix;
-               if (n <= 31) {
-                       hx = (hx<<n)|(lx>>(32-n));
-                       lx <<= n;
-               } else {
-                       hx = lx<<(n-32);
-                       lx = 0;
-               }
+       /* normalize x and y */
+       if (!ex) {
+               for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1);
+               uxi <<= -ex + 1;
+       } else {
+               uxi &= -1ULL >> 12;
+               uxi |= 1ULL << 52;
        }
-       if(iy >= -1022)
-               hy = 0x00100000|(0x000fffff&hy);
-       else {       /* subnormal y, shift y to normal */
-               n = -1022-iy;
-               if (n <= 31) {
-                       hy = (hy<<n)|(ly>>(32-n));
-                       ly <<= n;
-               } else {
-                       hy = ly<<(n-32);
-                       ly = 0;
-               }
+       if (!ey) {
+               for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1);
+               uy.i <<= -ey + 1;
+       } else {
+               uy.i &= -1ULL >> 12;
+               uy.i |= 1ULL << 52;
        }
 
-       /* fix point fmod */
-       n = ix - iy;
-       while (n--) {
-               hz = hx-hy;
-               lz = lx-ly;
-               if (lx < ly)
-                       hz -= 1;
-               if (hz < 0) {
-                       hx = hx+hx+(lx>>31);
-                       lx = lx+lx;
-               } else {
-                       if ((hz|lz) == 0)   /* return sign(x)*0 */
-                               return Zero[(uint32_t)sx>>31];
-                       hx = hz+hz+(lz>>31);
-                       lx = lz+lz;
+       /* x mod y */
+       for (; ex > ey; ex--) {
+               i = uxi - uy.i;
+               if (i >> 63 == 0) {
+                       if (i == 0)
+                               return 0*x;
+                       uxi = i;
                }
+               uxi <<= 1;
        }
-       hz = hx-hy;
-       lz = lx-ly;
-       if (lx < ly)
-               hz -= 1;
-       if (hz >= 0) {
-               hx = hz;
-               lx = lz;
+       i = uxi - uy.i;
+       if (i >> 63 == 0) {
+               if (i == 0)
+                       return 0*x;
+               uxi = i;
        }
+       for (; uxi>>52 == 0; uxi <<= 1, ex--);
 
-       /* convert back to floating value and restore the sign */
-       if ((hx|lx) == 0)          /* return sign(x)*0 */
-               return Zero[(uint32_t)sx>>31];
-       while (hx < 0x00100000) {  /* normalize x */
-               hx = hx+hx+(lx>>31);
-               lx = lx+lx;
-               iy -= 1;
-       }
-       if (iy >= -1022) {         /* normalize output */
-               hx = ((hx-0x00100000)|((iy+1023)<<20));
-               INSERT_WORDS(x, hx|sx, lx);
-       } else {                   /* subnormal output */
-               n = -1022 - iy;
-               if (n <= 20) {
-                       lx = (lx>>n)|((uint32_t)hx<<(32-n));
-                       hx >>= n;
-               } else if (n <= 31) {
-                       lx = (hx<<(32-n))|(lx>>n);
-                       hx = sx;
-               } else {
-                       lx = hx>>(n-32); hx = sx;
-               }
-               INSERT_WORDS(x, hx|sx, lx);
+       /* scale result */
+       if (ex > 0) {
+               uxi -= 1ULL << 52;
+               uxi |= (uint64_t)ex << 52;
+       } else {
+               uxi >>= -ex + 1;
        }
-       return x;  /* exact output */
+       uxi |= (uint64_t)sx << 63;
+       ux.i = uxi;
+       return ux.f;
 }
index 837e937..ff58f93 100644 (file)
-/* origin: FreeBSD /usr/src/lib/msun/src/e_fmodf.c */
-/*
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/*
- * fmodf(x,y)
- * Return x mod y in exact arithmetic
- * Method: shift and subtract
- */
-
-#include "libm.h"
-
-static const float Zero[] = {0.0, -0.0,};
+#include <math.h>
+#include <stdint.h>
 
 float fmodf(float x, float y)
 {
-       int32_t n,hx,hy,hz,ix,iy,sx,i;
+       union {float f; uint32_t i;} ux = {x}, uy = {y};
+       int ex = ux.i>>23 & 0xff;
+       int ey = uy.i>>23 & 0xff;
+       uint32_t sx = ux.i & 0x80000000;
+       uint32_t i;
+       uint32_t uxi = ux.i;
 
-       GET_FLOAT_WORD(hx, x);
-       GET_FLOAT_WORD(hy, y);
-       sx = hx & 0x80000000;  /* sign of x */
-       hx ^= sx;              /* |x| */
-       hy &= 0x7fffffff;      /* |y| */
-
-       /* purge off exception values */
-       if (hy == 0 || hx >= 0x7f800000 ||  /* y=0,or x not finite */
-           hy > 0x7f800000)                /* or y is NaN */
+       if (uy.i<<1 == 0 || isnan(y) || ex == 0xff)
                return (x*y)/(x*y);
-       if (hx < hy)                        /* |x| < |y| */
+       if (uxi<<1 <= uy.i<<1) {
+               if (uxi<<1 == uy.i<<1)
+                       return 0*x;
                return x;
-       if (hx == hy)                       /* |x| = |y|, return x*0 */
-               return Zero[(uint32_t)sx>>31];
-
-       /* determine ix = ilogb(x) */
-       if (hx < 0x00800000) {     /* subnormal x */
-               for (ix = -126, i = hx<<8; i > 0; i <<= 1)
-                       ix -= 1;
-       } else
-               ix = (hx>>23) - 127;
-
-       /* determine iy = ilogb(y) */
-       if (hy < 0x00800000) {     /* subnormal y */
-               for (iy = -126, i = hy<<8; i >= 0; i <<= 1)
-                       iy -= 1;
-       } else
-               iy = (hy>>23) - 127;
+       }
 
-       /* set up {hx,lx}, {hy,ly} and align y to x */
-       if (ix >= -126)
-               hx = 0x00800000|(0x007fffff&hx);
-       else {          /* subnormal x, shift x to normal */
-               n = -126-ix;
-               hx = hx<<n;
+       /* normalize x and y */
+       if (!ex) {
+               for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1);
+               uxi <<= -ex + 1;
+       } else {
+               uxi &= -1U >> 9;
+               uxi |= 1U << 23;
        }
-       if (iy >= -126)
-               hy = 0x00800000|(0x007fffff&hy);
-       else {          /* subnormal y, shift y to normal */
-               n = -126-iy;
-               hy = hy<<n;
+       if (!ey) {
+               for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1);
+               uy.i <<= -ey + 1;
+       } else {
+               uy.i &= -1U >> 9;
+               uy.i |= 1U << 23;
        }
 
-       /* fix point fmod */
-       n = ix - iy;
-       while (n--) {
-               hz = hx-hy;
-               if (hz<0)
-                       hx = hx+hx;
-               else {
-                       if(hz == 0)   /* return sign(x)*0 */
-                               return Zero[(uint32_t)sx>>31];
-                       hx = hz+hz;
+       /* x mod y */
+       for (; ex > ey; ex--) {
+               i = uxi - uy.i;
+               if (i >> 31 == 0) {
+                       if (i == 0)
+                               return 0*x;
+                       uxi = i;
                }
+               uxi <<= 1;
        }
-       hz = hx-hy;
-       if (hz >= 0)
-               hx = hz;
-
-       /* convert back to floating value and restore the sign */
-       if (hx == 0)               /* return sign(x)*0 */
-               return Zero[(uint32_t)sx>>31];
-       while (hx < 0x00800000) {  /* normalize x */
-               hx = hx+hx;
-               iy -= 1;
+       i = uxi - uy.i;
+       if (i >> 31 == 0) {
+               if (i == 0)
+                       return 0*x;
+               uxi = i;
        }
-       if (iy >= -126) {          /* normalize output */
-               hx = ((hx-0x00800000)|((iy+127)<<23));
-               SET_FLOAT_WORD(x, hx|sx);
-       } else {                   /* subnormal output */
-               n = -126 - iy;
-               hx >>= n;
-               SET_FLOAT_WORD(x, hx|sx);
+       for (; uxi>>23 == 0; uxi <<= 1, ex--);
+
+       /* scale result up */
+       if (ex > 0) {
+               uxi -= 1U << 23;
+               uxi |= (uint32_t)ex << 23;
+       } else {
+               uxi >>= -ex + 1;
        }
-       return x;  /* exact output */
+       uxi |= sx;
+       ux.i = uxi;
+       return ux.f;
 }
index b930c49..54af6a3 100644 (file)
@@ -1,15 +1,3 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_fmodl.c */
-/*-
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
 #include "libm.h"
 
 #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
@@ -18,141 +6,100 @@ long double fmodl(long double x, long double y)
        return fmod(x, y);
 }
 #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
-
-#define BIAS (LDBL_MAX_EXP - 1)
-
-#if LDBL_MANL_SIZE > 32
-typedef uint64_t manl_t;
-#else
-typedef uint32_t manl_t;
-#endif
-
-#if LDBL_MANH_SIZE > 32
-typedef uint64_t manh_t;
-#else
-typedef uint32_t manh_t;
-#endif
-
-/*
- * These macros add and remove an explicit integer bit in front of the
- * fractional mantissa, if the architecture doesn't have such a bit by
- * default already.
- */
-#ifdef LDBL_IMPLICIT_NBIT
-#define SET_NBIT(hx)    ((hx) | (1ULL << LDBL_MANH_SIZE))
-#define HFRAC_BITS      LDBL_MANH_SIZE
-#else
-#define SET_NBIT(hx)    (hx)
-#define HFRAC_BITS      (LDBL_MANH_SIZE - 1)
-#endif
-
-#define MANL_SHIFT      (LDBL_MANL_SIZE - 1)
-
-static const long double Zero[] = {0.0, -0.0,};
-
-/*
- * fmodl(x,y)
- * Return x mod y in exact arithmetic
- * Method: shift and subtract
- *
- * Assumptions:
- * - The low part of the mantissa fits in a manl_t exactly.
- * - The high part of the mantissa fits in an int64_t with enough room
- *   for an explicit integer bit in front of the fractional bits.
- */
 long double fmodl(long double x, long double y)
 {
-       union IEEEl2bits ux, uy;
-       int64_t hx,hz;  /* We need a carry bit even if LDBL_MANH_SIZE is 32. */
-       manh_t hy;
-       manl_t lx,ly,lz;
-       int ix,iy,n,sx;
-
-       ux.e = x;
-       uy.e = y;
-       sx = ux.bits.sign;
+       union ldshape ux = {x}, uy = {y};
+       int ex = ux.i.se & 0x7fff;
+       int ey = uy.i.se & 0x7fff;
+       int sx = ux.i.se & 0x8000;
 
-       /* purge off exception values */
-       if ((uy.bits.exp|uy.bits.manh|uy.bits.manl) == 0 || /* y=0 */
-           ux.bits.exp == BIAS + LDBL_MAX_EXP ||           /* or x not finite */
-           (uy.bits.exp == BIAS + LDBL_MAX_EXP &&
-            ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl) != 0)) /* or y is NaN */
+       if (y == 0 || isnan(y) || ex == 0x7fff)
                return (x*y)/(x*y);
-       if (ux.bits.exp <= uy.bits.exp) {
-               if (ux.bits.exp < uy.bits.exp ||
-                   (ux.bits.manh<=uy.bits.manh &&
-                    (ux.bits.manh<uy.bits.manh ||
-                     ux.bits.manl<uy.bits.manl)))  /* |x|<|y| return x or x-y */
-                       return x;
-               if (ux.bits.manh==uy.bits.manh && ux.bits.manl==uy.bits.manl)
-                       return Zero[sx];  /* |x| = |y| return x*0 */
+       ux.i.se = ex;
+       uy.i.se = ey;
+       if (ux.f <= uy.f) {
+               if (ux.f == uy.f)
+                       return 0*x;
+               return x;
        }
 
-       /* determine ix = ilogb(x) */
-       if (ux.bits.exp == 0) {  /* subnormal x */
-               ux.e *= 0x1.0p512;
-               ix = ux.bits.exp - (BIAS + 512);
-       } else {
-               ix = ux.bits.exp - BIAS;
+       /* normalize x and y */
+       if (!ex) {
+               ux.f *= 0x1p120f;
+               ex = ux.i.se - 120;
        }
-
-       /* determine iy = ilogb(y) */
-       if (uy.bits.exp == 0) {  /* subnormal y */
-               uy.e *= 0x1.0p512;
-               iy = uy.bits.exp - (BIAS + 512);
-       } else {
-               iy = uy.bits.exp - BIAS;
+       if (!ey) {
+               uy.f *= 0x1p120f;
+               ey = uy.i.se - 120;
        }
 
-       /* set up {hx,lx}, {hy,ly} and align y to x */
-       hx = SET_NBIT(ux.bits.manh);
-       hy = SET_NBIT(uy.bits.manh);
-       lx = ux.bits.manl;
-       ly = uy.bits.manl;
-
-       /* fix point fmod */
-       n = ix - iy;
-
-       while (n--) {
-               hz = hx-hy;
-               lz = lx-ly;
-               if (lx < ly)
-                       hz -= 1;
-               if (hz < 0) {
-                       hx = hx+hx+(lx>>MANL_SHIFT);
-                       lx = lx+lx;
+       /* x mod y */
+#if LDBL_MANT_DIG == 64
+       uint64_t i, mx, my;
+       mx = ux.i.m;
+       my = uy.i.m;
+       for (; ex > ey; ex--) {
+               i = mx - my;
+               if (mx >= my) {
+                       if (i == 0)
+                               return 0*x;
+                       mx = 2*i;
+               } else if (2*mx < mx) {
+                       mx = 2*mx - my;
                } else {
-                       if ((hz|lz)==0)   /* return sign(x)*0 */
-                               return Zero[sx];
-                       hx = hz+hz+(lz>>MANL_SHIFT);
-                       lx = lz+lz;
+                       mx = 2*mx;
                }
        }
-       hz = hx-hy;
-       lz = lx-ly;
-       if (lx < ly)
-               hz -= 1;
-       if (hz >= 0) {
-               hx = hz;
-               lx = lz;
+       i = mx - my;
+       if (mx >= my) {
+               if (i == 0)
+                       return 0*x;
+               mx = i;
        }
-
-       /* convert back to floating value and restore the sign */
-       if ((hx|lx) == 0)   /* return sign(x)*0 */
-               return Zero[sx];
-       while (hx < (1ULL<<HFRAC_BITS)) {  /* normalize x */
-               hx = hx+hx+(lx>>MANL_SHIFT);
-               lx = lx+lx;
-               iy -= 1;
+       for (; mx >> 63 == 0; mx *= 2, ex--);
+       ux.i.m = mx;
+#elif LDBL_MANT_DIG == 113
+       uint64_t hi, lo, xhi, xlo, yhi, ylo;
+       xhi = (ux.i2.hi & -1ULL>>16) | 1ULL<<48;
+       yhi = (uy.i2.hi & -1ULL>>16) | 1ULL<<48;
+       xlo = ux.i2.lo;
+       ylo = ux.i2.lo;
+       for (; ex > ey; ex--) {
+               hi = xhi - yhi;
+               lo = xlo - ylo;
+               if (xlo < ylo)
+                       hi -= 1;
+               if (hi >> 63 == 0) {
+                       if ((hi|lo) == 0)
+                               return 0*x;
+                       xhi = 2*hi + (lo>>63);
+                       xlo = 2*lo;
+               } else {
+                       xhi = 2*xhi + (xlo>>63);
+                       xlo = 2*xlo;
+               }
        }
-       ux.bits.manh = hx; /* The mantissa is truncated here if needed. */
-       ux.bits.manl = lx;
-       if (iy < LDBL_MIN_EXP) {
-               ux.bits.exp = iy + (BIAS + 512);
-               ux.e *= 0x1p-512;
-       } else {
-               ux.bits.exp = iy + BIAS;
+       hi = xhi - yhi;
+       lo = xlo - ylo;
+       if (xlo < ylo)
+               hi -= 1;
+       if (hi >> 63 == 0) {
+               if ((hi|lo) == 0)
+                       return 0*x;
+               xhi = hi;
+               xlo = lo;
        }
-       return ux.e;       /* exact output */
+       for (; xhi >> 48 == 0; xhi = 2*xhi + (xlo>>63), xlo = 2*xlo, ex--);
+       ux.i2.hi = xhi;
+       ux.i2.lo = xlo;
+#endif
+
+       /* scale result */
+       if (ex <= 0) {
+               ux.i.se = (ex+120)|sx;
+               ux.f *= 0x1p-120f;
+       } else
+               ux.i.se = ex|sx;
+       return ux.f;
 }
 #endif
index 8f337ef..1c8a1db 100644 (file)
@@ -2,36 +2,33 @@
 
 double modf(double x, double *iptr)
 {
-       union {double x; uint64_t n;} u = {x};
+       union {double f; uint64_t i;} u = {x};
        uint64_t mask;
-       int e;
-
-       e = (int)(u.n>>52 & 0x7ff) - 0x3ff;
+       int e = (int)(u.i>>52 & 0x7ff) - 0x3ff;
 
        /* no fractional part */
        if (e >= 52) {
                *iptr = x;
-               if (e == 0x400 && u.n<<12 != 0) /* nan */
+               if (e == 0x400 && u.i<<12 != 0) /* nan */
                        return x;
-               u.n &= (uint64_t)1<<63;
-               return u.x;
+               u.i &= 1ULL<<63;
+               return u.f;
        }
 
        /* no integral part*/
        if (e < 0) {
-               u.n &= (uint64_t)1<<63;
-               *iptr = u.x;
+               u.i &= 1ULL<<63;
+               *iptr = u.f;
                return x;
        }
 
-       mask = (uint64_t)-1>>12 >> e;
-       if ((u.n & mask) == 0) {
+       mask = -1ULL>>12>>e;
+       if ((u.i & mask) == 0) {
                *iptr = x;
-               u.n &= (uint64_t)1<<63;
-               return u.x;
+               u.i &= 1ULL<<63;
+               return u.f;
        }
-       u.n &= ~mask;
-       *iptr = u.x;
-       STRICT_ASSIGN(double, x, x - *iptr);
-       return x;
+       u.i &= ~mask;
+       *iptr = u.f;
+       return x - u.f;
 }
index 90caf31..639514e 100644 (file)
@@ -2,36 +2,33 @@
 
 float modff(float x, float *iptr)
 {
-       union {float x; uint32_t n;} u = {x};
+       union {float f; uint32_t i;} u = {x};
        uint32_t mask;
-       int e;
-
-       e = (int)(u.n>>23 & 0xff) - 0x7f;
+       int e = (int)(u.i>>23 & 0xff) - 0x7f;
 
        /* no fractional part */
        if (e >= 23) {
                *iptr = x;
-               if (e == 0x80 && u.n<<9 != 0) { /* nan */
+               if (e == 0x80 && u.i<<9 != 0) { /* nan */
                        return x;
                }
-               u.n &= 0x80000000;
-               return u.x;
+               u.i &= 0x80000000;
+               return u.f;
        }
        /* no integral part */
        if (e < 0) {
-               u.n &= 0x80000000;
-               *iptr = u.x;
+               u.i &= 0x80000000;
+               *iptr = u.f;
                return x;
        }
 
        mask = 0x007fffff>>e;
-       if ((u.n & mask) == 0) {
+       if ((u.i & mask) == 0) {
                *iptr = x;
-               u.n &= 0x80000000;
-               return u.x;
+               u.i &= 0x80000000;
+               return u.f;
        }
-       u.n &= ~mask;
-       *iptr = u.x;
-       STRICT_ASSIGN(float, x, x - *iptr);
-       return x;
+       u.i &= ~mask;
+       *iptr = u.f;
+       return x - u.f;
 }
index bbfcdb8..fc85bb5 100644 (file)
@@ -1,40 +1,3 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/s_modfl.c */
-/*-
- * Copyright (c) 2007 David Schultz <das@FreeBSD.ORG>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Derived from s_modf.c, which has the following Copyright:
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
 #include "libm.h"
 
 #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
@@ -43,58 +6,46 @@ long double modfl(long double x, long double *iptr)
        return modf(x, (double *)iptr);
 }
 #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
-
-#if LDBL_MANL_SIZE > 32
-#define MASK    ((uint64_t)-1)
-#else
-#define MASK    ((uint32_t)-1)
+#if LDBL_MANT_DIG == 64
+#define TOINT 0x1p63
+#elif LDBL_MANT_DIG == 113
+#define TOINT 0x1p112
 #endif
-/* Return the last n bits of a word, representing the fractional part. */
-#define GETFRAC(bits, n)        ((bits) & ~(MASK << (n)))
-/* The number of fraction bits in manh, not counting the integer bit */
-#define HIBITS  (LDBL_MANT_DIG - LDBL_MANL_SIZE)
-
-static const long double zero[] = { 0.0, -0.0 };
-
 long double modfl(long double x, long double *iptr)
 {
-       union IEEEl2bits ux;
-       int e;
+       union ldshape u = {x};
+       uint64_t mask;
+       int e = (u.i.se & 0x7fff) - 0x3fff;
+       int s = u.i.se >> 15;
+       long double absx;
+       long double y;
 
-       ux.e = x;
-       e = ux.bits.exp - LDBL_MAX_EXP + 1;
-       if (e < HIBITS) {                       /* Integer part is in manh. */
-               if (e < 0) {                    /* |x|<1 */
-                       *iptr = zero[ux.bits.sign];
-                       return x;
-               }
-               if ((GETFRAC(ux.bits.manh, HIBITS - 1 - e)|ux.bits.manl) == 0) {
-                       /* x is an integer. */
-                       *iptr = x;
-                       return zero[ux.bits.sign];
-               }
-               /* Clear all but the top e+1 bits. */
-               ux.bits.manh >>= HIBITS - 1 - e;
-               ux.bits.manh <<= HIBITS - 1 - e;
-               ux.bits.manl = 0;
-               *iptr = ux.e;
-               return x - ux.e;
-       } else if (e >= LDBL_MANT_DIG - 1) {    /* x has no fraction part. */
+       /* no fractional part */
+       if (e >= LDBL_MANT_DIG-1) {
                *iptr = x;
-               if (e == LDBL_MAX_EXP && ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl)) /* nan */
+               if (isnan(x))
                        return x;
-               return zero[ux.bits.sign];
-       } else {                                /* Fraction part is in manl. */
-               if (GETFRAC(ux.bits.manl, LDBL_MANT_DIG - 1 - e) == 0) {
-                       /* x is integral. */
-                       *iptr = x;
-                       return zero[ux.bits.sign];
-               }
-               /* Clear all but the top e+1 bits. */
-               ux.bits.manl >>= LDBL_MANT_DIG - 1 - e;
-               ux.bits.manl <<= LDBL_MANT_DIG - 1 - e;
-               *iptr = ux.e;
-               return x - ux.e;
+               return s ? -0.0 : 0.0;
+       }
+
+       /* no integral part*/
+       if (e < 0) {
+               *iptr = s ? -0.0 : 0.0;
+               return x;
+       }
+
+       /* raises spurious inexact */
+       absx = s ? -x : x;
+       y = absx + TOINT - TOINT - absx;
+       if (y == 0) {
+               *iptr = x;
+               return s ? -0.0 : 0.0;
        }
+       if (y > 0)
+               y -= 1;
+       if (s)
+               y = -y;
+       *iptr = x + y;
+       return -y;
 }
 #endif
index 2dede3a..ed5c477 100644 (file)
@@ -1,66 +1,7 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_remainder.c */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/* remainder(x,p)
- * Return :
- *      returns  x REM p  =  x - [x/p]*p as if in infinite
- *      precise arithmetic, where [x/p] is the (infinite bit)
- *      integer nearest x/p (in half way case choose the even one).
- * Method :
- *      Based on fmod() return x-[x/p]chopped*p exactlp.
- */
+#include <math.h>
 
-#include "libm.h"
-
-double remainder(double x, double p)
+double remainder(double x, double y)
 {
-       int32_t hx,hp;
-       uint32_t sx,lx,lp;
-       double p_half;
-
-       EXTRACT_WORDS(hx, lx, x);
-       EXTRACT_WORDS(hp, lp, p);
-       sx = hx & 0x80000000;
-       hp &= 0x7fffffff;
-       hx &= 0x7fffffff;
-
-       /* purge off exception values */
-       if ((hp|lp) == 0 ||                                  /* p = 0 */
-           hx >= 0x7ff00000 ||                              /* x not finite */
-           (hp >= 0x7ff00000 && (hp-0x7ff00000 | lp) != 0)) /* p is NaN */
-               return (x*p)/(x*p);
-
-       if (hp <= 0x7fdfffff)
-               x = fmod(x, p+p);  /* now x < 2p */
-       if (((hx-hp)|(lx-lp)) == 0)
-               return 0.0*x;
-       x = fabs(x);
-       p = fabs(p);
-       if (hp < 0x00200000) {
-               if (x + x > p) {
-                       x -= p;
-                       if (x + x >= p)
-                               x -= p;
-               }
-       } else {
-               p_half = 0.5*p;
-               if (x > p_half) {
-                       x -= p;
-                       if (x >= p_half)
-                               x -= p;
-               }
-       }
-       GET_HIGH_WORD(hx, x);
-       if ((hx&0x7fffffff) == 0)
-               hx = 0;
-       SET_HIGH_WORD(x, hx^sx);
-       return x;
+       int q;
+       return remquo(x, y, &q);
 }
index 7767103..b418bbf 100644 (file)
@@ -1,59 +1,7 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/e_remainderf.c */
-/*
- * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
- */
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
+#include <math.h>
 
-#include "libm.h"
-
-float remainderf(float x, float p)
+float remainderf(float x, float y)
 {
-       int32_t hx,hp;
-       uint32_t sx;
-       float p_half;
-
-       GET_FLOAT_WORD(hx, x);
-       GET_FLOAT_WORD(hp, p);
-       sx = hx & 0x80000000;
-       hp &= 0x7fffffff;
-       hx &= 0x7fffffff;
-
-       /* purge off exception values */
-       if (hp == 0 || hx >= 0x7f800000 || hp > 0x7f800000)  /* p = 0, x not finite, p is NaN */
-               return (x*p)/(x*p);
-
-       if (hp <= 0x7effffff)
-               x = fmodf(x, p + p);  /* now x < 2p */
-       if (hx - hp == 0)
-               return 0.0f*x;
-       x = fabsf(x);
-       p = fabsf(p);
-       if (hp < 0x01000000) {
-               if (x + x > p) {
-                       x -= p;
-                       if (x + x >= p)
-                               x -= p;
-               }
-       } else {
-               p_half = 0.5f*p;
-               if (x > p_half) {
-                       x -= p;
-                       if (x >= p_half)
-                               x -= p;
-               }
-       }
-       GET_FLOAT_WORD(hx, x);
-       if ((hx & 0x7fffffff) == 0)
-               hx = 0;
-       SET_FLOAT_WORD(x, hx ^ sx);
-       return x;
+       int q;
+       return remquof(x, y, &q);
 }
index 085466e..59d5ad5 100644 (file)
-/* origin: FreeBSD /usr/src/lib/msun/src/s_remquo.c */
-/*-
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/*
- * Return the IEEE remainder and set *quo to the last n bits of the
- * quotient, rounded to the nearest integer.  We choose n=31 because
- * we wind up computing all the integer bits of the quotient anyway as
- * a side-effect of computing the remainder by the shift and subtract
- * method.  In practice, this is far more bits than are needed to use
- * remquo in reduction algorithms.
- */
-
-#include "libm.h"
-
-static const double Zero[] = {0.0, -0.0,};
+#include <math.h>
+#include <stdint.h>
 
 double remquo(double x, double y, int *quo)
 {
-       int32_t n,hx,hy,hz,ix,iy,sx,i;
-       uint32_t lx,ly,lz,q,sxy;
-
-       EXTRACT_WORDS(hx, lx, x);
-       EXTRACT_WORDS(hy, ly, y);
-       sxy = (hx ^ hy) & 0x80000000;
-       sx = hx & 0x80000000;   /* sign of x */
-       hx ^= sx;               /* |x| */
-       hy &= 0x7fffffff;       /* |y| */
+       union {double f; uint64_t i;} ux = {x}, uy = {y};
+       int ex = ux.i>>52 & 0x7ff;
+       int ey = uy.i>>52 & 0x7ff;
+       int sx = ux.i>>63;
+       int sy = uy.i>>63;
+       uint32_t q;
+       uint64_t i;
+       uint64_t uxi = ux.i;
 
-       /* purge off exception values */
-       if ((hy|ly) == 0 || hx >= 0x7ff00000 ||  /* y = 0, or x not finite */
-           (hy|((ly|-ly)>>31)) > 0x7ff00000)    /* or y is NaN */
+       *quo = 0;
+       if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff)
                return (x*y)/(x*y);
-       if (hx <= hy) {
-               if (hx < hy || lx < ly) {  /* |x| < |y| return x or x-y */
-                       q = 0;
-                       goto fixup;
-               }
-               if (lx == ly) {            /* |x| = |y| return x*0 */
-                       *quo = sxy ? -1 : 1;
-                       return Zero[(uint32_t)sx>>31];
-               }
-       }
+       if (ux.i<<1 == 0)
+               return x;
 
-       // FIXME: use ilogb?
-
-       /* determine ix = ilogb(x) */
-       if (hx < 0x00100000) {  /* subnormal x */
-               if (hx == 0) {
-                       for (ix = -1043, i=lx; i>0; i<<=1) ix--;
-               } else {
-                       for (ix = -1022, i=hx<<11; i>0; i<<=1) ix--;
-               }
-       } else
-               ix = (hx>>20) - 1023;
-
-       /* determine iy = ilogb(y) */
-       if (hy < 0x00100000) {  /* subnormal y */
-               if (hy == 0) {
-                       for (iy = -1043, i=ly; i>0; i<<=1) iy--;
-               } else {
-                       for (iy = -1022, i=hy<<11; i>0; i<<=1) iy--;
-               }
-       } else
-               iy = (hy>>20) - 1023;
-
-       /* set up {hx,lx}, {hy,ly} and align y to x */
-       if (ix >= -1022)
-               hx = 0x00100000|(0x000fffff&hx);
-       else {  /* subnormal x, shift x to normal */
-               n = -1022 - ix;
-               if (n <= 31) {
-                       hx = (hx<<n)|(lx>>(32-n));
-                       lx <<= n;
-               } else {
-                       hx = lx<<(n-32);
-                       lx = 0;
-               }
+       /* normalize x and y */
+       if (!ex) {
+               for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1);
+               uxi <<= -ex + 1;
+       } else {
+               uxi &= -1ULL >> 12;
+               uxi |= 1ULL << 52;
        }
-       if (iy >= -1022)
-               hy = 0x00100000|(0x000fffff&hy);
-       else {  /* subnormal y, shift y to normal */
-               n = -1022 - iy;
-               if (n <= 31) {
-                       hy = (hy<<n)|(ly>>(32-n));
-                       ly <<= n;
-               } else {
-                       hy = ly<<(n-32);
-                       ly = 0;
-               }
+       if (!ey) {
+               for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1);
+               uy.i <<= -ey + 1;
+       } else {
+               uy.i &= -1ULL >> 12;
+               uy.i |= 1ULL << 52;
        }
 
-       /* fix point fmod */
-       n = ix - iy;
        q = 0;
-       while (n--) {
-               hz = hx - hy;
-               lz = lx - ly;
-               if (lx < ly)
-                       hz--;
-               if (hz < 0) {
-                       hx = hx + hx + (lx>>31);
-                       lx = lx + lx;
-               } else {
-                       hx = hz + hz + (lz>>31);
-                       lx = lz + lz;
+       if (ex < ey) {
+               if (ex+1 == ey)
+                       goto end;
+               return x;
+       }
+
+       /* x mod y */
+       for (; ex > ey; ex--) {
+               i = uxi - uy.i;
+               if (i >> 63 == 0) {
+                       uxi = i;
                        q++;
                }
+               uxi <<= 1;
                q <<= 1;
        }
-       hz = hx - hy;
-       lz = lx - ly;
-       if (lx < ly)
-               hz--;
-       if (hz >= 0) {
-               hx = hz;
-               lx = lz;
+       i = uxi - uy.i;
+       if (i >> 63 == 0) {
+               uxi = i;
                q++;
        }
-
-       /* convert back to floating value and restore the sign */
-       if ((hx|lx) == 0) {  /* return sign(x)*0 */
-               q &= 0x7fffffff;
-               *quo = sxy ? -q : q;
-               return Zero[(uint32_t)sx>>31];
-       }
-       while (hx < 0x00100000) {  /* normalize x */
-               hx = hx + hx + (lx>>31);
-               lx = lx + lx;
-               iy--;
+       if (uxi == 0)
+               ex = -60;
+       else
+               for (; uxi>>52 == 0; uxi <<= 1, ex--);
+end:
+       /* scale result and decide between |x| and |x|-|y| */
+       if (ex > 0) {
+               uxi -= 1ULL << 52;
+               uxi |= (uint64_t)ex << 52;
+       } else {
+               uxi >>= -ex + 1;
        }
-       if (iy >= -1022) {         /* normalize output */
-               hx = (hx-0x00100000)|((iy+1023)<<20);
-       } else {                   /* subnormal output */
-               n = -1022 - iy;
-               if (n <= 20) {
-                       lx = (lx>>n)|((uint32_t)hx<<(32-n));
-                       hx >>= n;
-               } else if (n <= 31) {
-                       lx = (hx<<(32-n))|(lx>>n);
-                       hx = 0;
-               } else {
-                       lx = hx>>(n-32);
-                       hx = 0;
-               }
-       }
-fixup:
-       INSERT_WORDS(x, hx, lx);
-       y = fabs(y);
-       if (y < 0x1p-1021) {
-               if (x + x > y || (x + x == y && (q & 1))) {
-                       q++;
-                       x -= y;
-               }
-       } else if (x > 0.5*y || (x == 0.5*y && (q & 1))) {
-               q++;
+       ux.i = uxi;
+       x = ux.f;
+       if (sy)
+               y = -y;
+       if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) {
                x -= y;
+               q++;
        }
-       GET_HIGH_WORD(hx, x);
-       SET_HIGH_WORD(x, hx ^ sx);
        q &= 0x7fffffff;
-       *quo = sxy ? -q : q;
-       return x;
+       *quo = sx^sy ? -(int)q : (int)q;
+       return sx ? -x : x;
 }
index 536a050..2f41ff7 100644 (file)
-/* origin: FreeBSD /usr/src/lib/msun/src/s_remquof.c */
-/*-
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-/*
- * Return the IEEE remainder and set *quo to the last n bits of the
- * quotient, rounded to the nearest integer.  We choose n=31 because
- * we wind up computing all the integer bits of the quotient anyway as
- * a side-effect of computing the remainder by the shift and subtract
- * method.  In practice, this is far more bits than are needed to use
- * remquo in reduction algorithms.
- */
-
-#include "libm.h"
-
-static const float Zero[] = {0.0, -0.0,};
+#include <math.h>
+#include <stdint.h>
 
 float remquof(float x, float y, int *quo)
 {
-       int32_t n,hx,hy,hz,ix,iy,sx,i;
-       uint32_t q,sxy;
+       union {float f; uint32_t i;} ux = {x}, uy = {y};
+       int ex = ux.i>>23 & 0xff;
+       int ey = uy.i>>23 & 0xff;
+       int sx = ux.i>>31;
+       int sy = uy.i>>31;
+       uint32_t q;
+       uint32_t i;
+       uint32_t uxi = ux.i;
 
-       GET_FLOAT_WORD(hx, x);
-       GET_FLOAT_WORD(hy, y);
-       sxy = (hx ^ hy) & 0x80000000;
-       sx = hx & 0x80000000;   /* sign of x */
-       hx ^= sx;               /* |x| */
-       hy &= 0x7fffffff;       /* |y| */
-
-       /* purge off exception values */
-       if (hy == 0 || hx >= 0x7f800000 || hy > 0x7f800000) /* y=0,NaN;or x not finite */
+       *quo = 0;
+       if (uy.i<<1 == 0 || isnan(y) || ex == 0xff)
                return (x*y)/(x*y);
-       if (hx < hy) {       /* |x| < |y| return x or x-y */
-               q = 0;
-               goto fixup;
-       } else if(hx==hy) {  /* |x| = |y| return x*0*/
-               *quo = sxy ? -1 : 1;
-               return Zero[(uint32_t)sx>>31];
-       }
+       if (ux.i<<1 == 0)
+               return x;
 
-       /* determine ix = ilogb(x) */
-       if (hx < 0x00800000) {  /* subnormal x */
-               for (ix = -126, i=hx<<8; i>0; i<<=1) ix--;
-       } else
-               ix = (hx>>23) - 127;
-
-       /* determine iy = ilogb(y) */
-       if (hy < 0x00800000) {  /* subnormal y */
-               for (iy = -126, i=hy<<8; i>0; i<<=1) iy--;
-       } else
-               iy = (hy>>23) - 127;
-
-       /* set up {hx,lx}, {hy,ly} and align y to x */
-       if (ix >= -126)
-               hx = 0x00800000|(0x007fffff&hx);
-       else {  /* subnormal x, shift x to normal */
-               n = -126 - ix;
-               hx <<= n;
+       /* normalize x and y */
+       if (!ex) {
+               for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1);
+               uxi <<= -ex + 1;
+       } else {
+               uxi &= -1U >> 9;
+               uxi |= 1U << 23;
        }
-       if (iy >= -126)
-               hy = 0x00800000|(0x007fffff&hy);
-       else {  /* subnormal y, shift y to normal */
-               n = -126 - iy;
-               hy <<= n;
+       if (!ey) {
+               for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1);
+               uy.i <<= -ey + 1;
+       } else {
+               uy.i &= -1U >> 9;
+               uy.i |= 1U << 23;
        }
 
-       /* fix point fmod */
-       n = ix - iy;
        q = 0;
-       while (n--) {
-               hz = hx - hy;
-               if (hz < 0)
-                       hx = hx << 1;
-               else {
-                       hx = hz << 1;
+       if (ex < ey) {
+               if (ex+1 == ey)
+                       goto end;
+               return x;
+       }
+
+       /* x mod y */
+       for (; ex > ey; ex--) {
+               i = uxi - uy.i;
+               if (i >> 31 == 0) {
+                       uxi = i;
                        q++;
                }
+               uxi <<= 1;
                q <<= 1;
        }
-       hz = hx - hy;
-       if (hz >= 0) {
-               hx = hz;
+       i = uxi - uy.i;
+       if (i >> 31 == 0) {
+               uxi = i;
                q++;
        }
-
-       /* convert back to floating value and restore the sign */
-       if (hx == 0) {                             /* return sign(x)*0 */
-               q &= 0x7fffffff;
-               *quo = sxy ? -q : q;
-               return Zero[(uint32_t)sx>>31];
-       }
-       while (hx < 0x00800000) {  /* normalize x */
-               hx <<= 1;
-               iy--;
+       if (uxi == 0)
+               ex = -30;
+       else
+               for (; uxi>>23 == 0; uxi <<= 1, ex--);
+end:
+       /* scale result and decide between |x| and |x|-|y| */
+       if (ex > 0) {
+               uxi -= 1U << 23;
+               uxi |= (uint32_t)ex << 23;
+       } else {
+               uxi >>= -ex + 1;
        }
-       if (iy >= -126) {          /* normalize output */
-               hx = (hx-0x00800000)|((iy+127)<<23);
-       } else {                   /* subnormal output */
-               n = -126 - iy;
-               hx >>= n;
-       }
-fixup:
-       SET_FLOAT_WORD(x,hx);
-       y = fabsf(y);
-       if (y < 0x1p-125f) {
-               if (x + x > y || (x + x == y && (q & 1))) {
-                       q++;
-                       x -= y;
-               }
-       } else if (x > 0.5f*y || (x == 0.5f*y && (q & 1))) {
-               q++;
+       ux.i = uxi;
+       x = ux.f;
+       if (sy)
+               y = -y;
+       if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) {
                x -= y;
+               q++;
        }
-       GET_FLOAT_WORD(hx, x);
-       SET_FLOAT_WORD(x, hx ^ sx);
        q &= 0x7fffffff;
-       *quo = sxy ? -q : q;
-       return x;
+       *quo = sx^sy ? -(int)q : (int)q;
+       return sx ? -x : x;
 }
index a2e1172..9b065c0 100644 (file)
@@ -1,15 +1,3 @@
-/* origin: FreeBSD /usr/src/lib/msun/src/s_remquol.c */
-/*-
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunSoft, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
 #include "libm.h"
 
 #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
@@ -18,177 +6,119 @@ long double remquol(long double x, long double y, int *quo)
        return remquo(x, y, quo);
 }
 #elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
-
-#define BIAS (LDBL_MAX_EXP - 1)
-
-#if LDBL_MANL_SIZE > 32
-typedef uint64_t manl_t;
-#else
-typedef uint32_t manl_t;
-#endif
-
-#if LDBL_MANH_SIZE > 32
-typedef uint64_t manh_t;
-#else
-typedef uint32_t manh_t;
-#endif
-
-/*
- * These macros add and remove an explicit integer bit in front of the
- * fractional mantissa, if the architecture doesn't have such a bit by
- * default already.
- */
-#ifdef LDBL_IMPLICIT_NBIT
-#define SET_NBIT(hx)    ((hx) | (1ULL << LDBL_MANH_SIZE))
-#define HFRAC_BITS      LDBL_MANH_SIZE
-#else
-#define SET_NBIT(hx)    (hx)
-#define HFRAC_BITS      (LDBL_MANH_SIZE - 1)
-#endif
-
-#define MANL_SHIFT      (LDBL_MANL_SIZE - 1)
-
-static const long double Zero[] = {0.0, -0.0};
-
-/*
- * Return the IEEE remainder and set *quo to the last n bits of the
- * quotient, rounded to the nearest integer.  We choose n=31 because
- * we wind up computing all the integer bits of the quotient anyway as
- * a side-effect of computing the remainder by the shift and subtract
- * method.  In practice, this is far more bits than are needed to use
- * remquo in reduction algorithms.
- *
- * Assumptions:
- * - The low part of the mantissa fits in a manl_t exactly.
- * - The high part of the mantissa fits in an int64_t with enough room
- *   for an explicit integer bit in front of the fractional bits.
- */
 long double remquol(long double x, long double y, int *quo)
 {
-       union IEEEl2bits ux, uy;
-       int64_t hx,hz;  /* We need a carry bit even if LDBL_MANH_SIZE is 32. */
-       manh_t hy;
-       manl_t lx,ly,lz;
-       int ix,iy,n,q,sx,sxy;
-
-       ux.e = x;
-       uy.e = y;
-       sx = ux.bits.sign;
-       sxy = sx ^ uy.bits.sign;
-       ux.bits.sign = 0;       /* |x| */
-       uy.bits.sign = 0;       /* |y| */
-       x = ux.e;
-
-       /* purge off exception values */
-       if ((uy.bits.exp|uy.bits.manh|uy.bits.manl)==0 || /* y=0 */
-           (ux.bits.exp == BIAS + LDBL_MAX_EXP) ||       /* or x not finite */
-           (uy.bits.exp == BIAS + LDBL_MAX_EXP &&
-               ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)!=0)) /* or y is NaN */
+       union ldshape ux = {x}, uy = {y};
+       int ex = ux.i.se & 0x7fff;
+       int ey = uy.i.se & 0x7fff;
+       int sx = ux.i.se >> 15;
+       int sy = uy.i.se >> 15;
+       uint32_t q;
+
+       *quo = 0;
+       if (y == 0 || isnan(y) || ex == 0x7fff)
                return (x*y)/(x*y);
-       if (ux.bits.exp <= uy.bits.exp) {
-               if ((ux.bits.exp < uy.bits.exp) ||
-                   (ux.bits.manh <= uy.bits.manh &&
-                    (ux.bits.manh < uy.bits.manh ||
-                     ux.bits.manl < uy.bits.manl))) {
-                       q = 0;
-                       goto fixup;       /* |x|<|y| return x or x-y */
-               }
-               if (ux.bits.manh == uy.bits.manh && ux.bits.manl == uy.bits.manl) {
-                       *quo = sxy ? -1 : 1;
-                       return Zero[sx];  /* |x|=|y| return x*0*/
-               }
-       }
-
-       /* determine ix = ilogb(x) */
-       if (ux.bits.exp == 0) {  /* subnormal x */
-               ux.e *= 0x1.0p512;
-               ix = ux.bits.exp - (BIAS + 512);
-       } else {
-               ix = ux.bits.exp - BIAS;
+       if (x == 0)
+               return x;
+
+       /* normalize x and y */
+       if (!ex) {
+               ux.i.se = ex;
+               ux.f *= 0x1p120f;
+               ex = ux.i.se - 120;
        }
-
-       /* determine iy = ilogb(y) */
-       if (uy.bits.exp == 0) {  /* subnormal y */
-               uy.e *= 0x1.0p512;
-               iy = uy.bits.exp - (BIAS + 512);
-       } else {
-               iy = uy.bits.exp - BIAS;
+       if (!ey) {
+               uy.i.se = ey;
+               uy.f *= 0x1p120f;
+               ey = uy.i.se - 120;
        }
 
-       /* set up {hx,lx}, {hy,ly} and align y to x */
-       hx = SET_NBIT(ux.bits.manh);
-       hy = SET_NBIT(uy.bits.manh);
-       lx = ux.bits.manl;
-       ly = uy.bits.manl;
-
-       /* fix point fmod */
-       n = ix - iy;
        q = 0;
-
-       while (n--) {
-               hz = hx - hy;
-               lz = lx - ly;
-               if (lx < ly)
-                       hz -= 1;
-               if (hz < 0) {
-                       hx = hx + hx + (lx>>MANL_SHIFT);
-                       lx = lx + lx;
-               } else {
-                       hx = hz + hz + (lz>>MANL_SHIFT);
-                       lx = lz + lz;
+       if (ex >= ey) {
+               /* x mod y */
+#if LDBL_MANT_DIG == 64
+               uint64_t i, mx, my;
+               mx = ux.i.m;
+               my = uy.i.m;
+               for (; ex > ey; ex--) {
+                       i = mx - my;
+                       if (mx >= my) {
+                               mx = 2*i;
+                               q++;
+                               q <<= 1;
+                       } else if (2*mx < mx) {
+                               mx = 2*mx - my;
+                               q <<= 1;
+                               q++;
+                       } else {
+                               mx = 2*mx;
+                               q <<= 1;
+                       }
+               }
+               i = mx - my;
+               if (mx >= my) {
+                       mx = i;
                        q++;
                }
-               q <<= 1;
-       }
-       hz = hx - hy;
-       lz = lx - ly;
-       if (lx < ly)
-               hz -= 1;
-       if (hz >= 0) {
-               hx = hz;
-               lx = lz;
-               q++;
-       }
-
-       /* convert back to floating value and restore the sign */
-       if ((hx|lx) == 0) {  /* return sign(x)*0 */
-               q &= 0x7fffffff;
-               *quo = sxy ? -q : q;
-               return Zero[sx];
-       }
-       while (hx < (1ULL<<HFRAC_BITS)) {  /* normalize x */
-               hx = hx + hx + (lx>>MANL_SHIFT);
-               lx = lx + lx;
-               iy -= 1;
-       }
-       ux.bits.manh = hx; /* The integer bit is truncated here if needed. */
-       ux.bits.manl = lx;
-       if (iy < LDBL_MIN_EXP) {
-               ux.bits.exp = iy + (BIAS + 512);
-               ux.e *= 0x1p-512;
-       } else {
-               ux.bits.exp = iy + BIAS;
-       }
-       ux.bits.sign = 0;
-       x = ux.e;
-fixup:
-       y = fabsl(y);
-       if (y < LDBL_MIN * 2) {
-               if (x + x > y || (x + x == y && (q & 1))) {
+               if (mx == 0)
+                       ex = -120;
+               else
+                       for (; mx >> 63 == 0; mx *= 2, ex--);
+               ux.i.m = mx;
+#elif LDBL_MANT_DIG == 113
+               uint64_t hi, lo, xhi, xlo, yhi, ylo;
+               xhi = (ux.i2.hi & -1ULL>>16) | 1ULL<<48;
+               yhi = (uy.i2.hi & -1ULL>>16) | 1ULL<<48;
+               xlo = ux.i2.lo;
+               ylo = ux.i2.lo;
+               for (; ex > ey; ex--) {
+                       hi = xhi - yhi;
+                       lo = xlo - ylo;
+                       if (xlo < ylo)
+                               hi -= 1;
+                       if (hi >> 63 == 0) {
+                               xhi = 2*hi + (lo>>63);
+                               xlo = 2*lo;
+                               q++;
+                       } else {
+                               xhi = 2*xhi + (xlo>>63);
+                               xlo = 2*xlo;
+                       }
+                       q <<= 1;
+               }
+               hi = xhi - yhi;
+               lo = xlo - ylo;
+               if (xlo < ylo)
+                       hi -= 1;
+               if (hi >> 63 == 0) {
+                       xhi = hi;
+                       xlo = lo;
                        q++;
-                       x-=y;
                }
-       } else if (x > 0.5*y || (x == 0.5*y && (q & 1))) {
-               q++;
-               x-=y;
+               if ((xhi|xlo) == 0)
+                       ex = -120;
+               else
+                       for (; xhi >> 48 == 0; xhi = 2*xhi + (xlo>>63), xlo = 2*xlo, ex--);
+               ux.i2.hi = xhi;
+               ux.i2.lo = xlo;
+#endif
        }
 
-       ux.e = x;
-       ux.bits.sign ^= sx;
-       x = ux.e;
-
+       /* scale result and decide between |x| and |x|-|y| */
+       if (ex <= 0) {
+               ux.i.se = ex + 120;
+               ux.f *= 0x1p-120f;
+       } else
+               ux.i.se = ex;
+       x = ux.f;
+       if (sy)
+               y = -y;
+       if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) {
+               x -= y;
+               q++;
+       }
        q &= 0x7fffffff;
-       *quo = sxy ? -q : q;
-       return x;
+       *quo = sx^sy ? -(int)q : (int)q;
+       return sx ? -x : x;
 }
 #endif