Index: fusl/src/math/remquol.c |
diff --git a/fusl/src/math/remquol.c b/fusl/src/math/remquol.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9b065c007f56e573a9d2dbb5a91fadd919cf290c |
--- /dev/null |
+++ b/fusl/src/math/remquol.c |
@@ -0,0 +1,124 @@ |
+#include "libm.h" |
+ |
+#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 |
+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 |
+long double remquol(long double x, long double y, int *quo) |
+{ |
+ 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 (x == 0) |
+ return x; |
+ |
+ /* normalize x and y */ |
+ if (!ex) { |
+ ux.i.se = ex; |
+ ux.f *= 0x1p120f; |
+ ex = ux.i.se - 120; |
+ } |
+ if (!ey) { |
+ uy.i.se = ey; |
+ uy.f *= 0x1p120f; |
+ ey = uy.i.se - 120; |
+ } |
+ |
+ q = 0; |
+ 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++; |
+ } |
+ 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++; |
+ } |
+ 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 |
+ } |
+ |
+ /* 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 = sx^sy ? -(int)q : (int)q; |
+ return sx ? -x : x; |
+} |
+#endif |