mirror of
https://github.com/fluencelabs/musl
synced 2025-06-15 16:01:41 +00:00
math: rewrite remainder functions (remainder, remquo, fmod, modf)
* 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
This commit is contained in:
179
src/math/fmod.c
179
src/math/fmod.c
@ -1,145 +1,68 @@
|
|||||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_fmod.c */
|
#include <math.h>
|
||||||
/*
|
#include <stdint.h>
|
||||||
* ====================================================
|
|
||||||
* 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,};
|
|
||||||
|
|
||||||
double fmod(double x, double y)
|
double fmod(double x, double y)
|
||||||
{
|
{
|
||||||
int32_t n,hx,hy,hz,ix,iy,sx,i;
|
union {double f; uint64_t i;} ux = {x}, uy = {y};
|
||||||
uint32_t lx,ly,lz;
|
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);
|
/* in the followings uxi should be ux.i, but then gcc wrongly adds */
|
||||||
EXTRACT_WORDS(hy, ly, y);
|
/* float load/store to inner loops ruining performance and code size */
|
||||||
sx = hx & 0x80000000; /* sign of x */
|
uint64_t uxi = ux.i;
|
||||||
hx ^= sx; /* |x| */
|
|
||||||
hy &= 0x7fffffff; /* |y| */
|
|
||||||
|
|
||||||
/* purge off exception values */
|
if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff)
|
||||||
if ((hy|ly) == 0 || hx >= 0x7ff00000 || /* y=0,or x not finite */
|
|
||||||
(hy|((ly|-ly)>>31)) > 0x7ff00000) /* or y is NaN */
|
|
||||||
return (x*y)/(x*y);
|
return (x*y)/(x*y);
|
||||||
if (hx <= hy) {
|
if (uxi<<1 <= uy.i<<1) {
|
||||||
if (hx < hy || lx < ly) /* |x| < |y| */
|
if (uxi<<1 == uy.i<<1)
|
||||||
return x;
|
return 0*x;
|
||||||
if (lx == ly) /* |x| = |y|, return x*0 */
|
return x;
|
||||||
return Zero[(uint32_t)sx>>31];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* determine ix = ilogb(x) */
|
/* normalize x and y */
|
||||||
if (hx < 0x00100000) { /* subnormal x */
|
if (!ex) {
|
||||||
if (hx == 0) {
|
for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1);
|
||||||
for (ix = -1043, i = lx; i > 0; i <<= 1)
|
uxi <<= -ex + 1;
|
||||||
ix -= 1;
|
} else {
|
||||||
} else {
|
uxi &= -1ULL >> 12;
|
||||||
for (ix = -1022, i = hx<<11; i > 0; i <<= 1)
|
uxi |= 1ULL << 52;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(iy >= -1022)
|
if (!ey) {
|
||||||
hy = 0x00100000|(0x000fffff&hy);
|
for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1);
|
||||||
else { /* subnormal y, shift y to normal */
|
uy.i <<= -ey + 1;
|
||||||
n = -1022-iy;
|
} else {
|
||||||
if (n <= 31) {
|
uy.i &= -1ULL >> 12;
|
||||||
hy = (hy<<n)|(ly>>(32-n));
|
uy.i |= 1ULL << 52;
|
||||||
ly <<= n;
|
|
||||||
} else {
|
|
||||||
hy = ly<<(n-32);
|
|
||||||
ly = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fix point fmod */
|
/* x mod y */
|
||||||
n = ix - iy;
|
for (; ex > ey; ex--) {
|
||||||
while (n--) {
|
i = uxi - uy.i;
|
||||||
hz = hx-hy;
|
if (i >> 63 == 0) {
|
||||||
lz = lx-ly;
|
if (i == 0)
|
||||||
if (lx < ly)
|
return 0*x;
|
||||||
hz -= 1;
|
uxi = i;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
uxi <<= 1;
|
||||||
}
|
}
|
||||||
hz = hx-hy;
|
i = uxi - uy.i;
|
||||||
lz = lx-ly;
|
if (i >> 63 == 0) {
|
||||||
if (lx < ly)
|
if (i == 0)
|
||||||
hz -= 1;
|
return 0*x;
|
||||||
if (hz >= 0) {
|
uxi = i;
|
||||||
hx = hz;
|
|
||||||
lx = lz;
|
|
||||||
}
|
}
|
||||||
|
for (; uxi>>52 == 0; uxi <<= 1, ex--);
|
||||||
|
|
||||||
/* convert back to floating value and restore the sign */
|
/* scale result */
|
||||||
if ((hx|lx) == 0) /* return sign(x)*0 */
|
if (ex > 0) {
|
||||||
return Zero[(uint32_t)sx>>31];
|
uxi -= 1ULL << 52;
|
||||||
while (hx < 0x00100000) { /* normalize x */
|
uxi |= (uint64_t)ex << 52;
|
||||||
hx = hx+hx+(lx>>31);
|
} else {
|
||||||
lx = lx+lx;
|
uxi >>= -ex + 1;
|
||||||
iy -= 1;
|
|
||||||
}
|
}
|
||||||
if (iy >= -1022) { /* normalize output */
|
uxi |= (uint64_t)sx << 63;
|
||||||
hx = ((hx-0x00100000)|((iy+1023)<<20));
|
ux.i = uxi;
|
||||||
INSERT_WORDS(x, hx|sx, lx);
|
return ux.f;
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
return x; /* exact output */
|
|
||||||
}
|
}
|
||||||
|
143
src/math/fmodf.c
143
src/math/fmodf.c
@ -1,104 +1,65 @@
|
|||||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_fmodf.c */
|
#include <math.h>
|
||||||
/*
|
#include <stdint.h>
|
||||||
* 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,};
|
|
||||||
|
|
||||||
float fmodf(float x, float y)
|
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);
|
if (uy.i<<1 == 0 || isnan(y) || ex == 0xff)
|
||||||
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 */
|
|
||||||
return (x*y)/(x*y);
|
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;
|
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;
|
|
||||||
}
|
|
||||||
if (iy >= -126)
|
|
||||||
hy = 0x00800000|(0x007fffff&hy);
|
|
||||||
else { /* subnormal y, shift y to normal */
|
|
||||||
n = -126-iy;
|
|
||||||
hy = hy<<n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fix point fmod */
|
/* normalize x and y */
|
||||||
n = ix - iy;
|
if (!ex) {
|
||||||
while (n--) {
|
for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1);
|
||||||
hz = hx-hy;
|
uxi <<= -ex + 1;
|
||||||
if (hz<0)
|
} else {
|
||||||
hx = hx+hx;
|
uxi &= -1U >> 9;
|
||||||
else {
|
uxi |= 1U << 23;
|
||||||
if(hz == 0) /* return sign(x)*0 */
|
}
|
||||||
return Zero[(uint32_t)sx>>31];
|
if (!ey) {
|
||||||
hx = hz+hz;
|
for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1);
|
||||||
|
uy.i <<= -ey + 1;
|
||||||
|
} else {
|
||||||
|
uy.i &= -1U >> 9;
|
||||||
|
uy.i |= 1U << 23;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
i = uxi - uy.i;
|
||||||
if (hz >= 0)
|
if (i >> 31 == 0) {
|
||||||
hx = hz;
|
if (i == 0)
|
||||||
|
return 0*x;
|
||||||
|
uxi = i;
|
||||||
|
}
|
||||||
|
for (; uxi>>23 == 0; uxi <<= 1, ex--);
|
||||||
|
|
||||||
/* convert back to floating value and restore the sign */
|
/* scale result up */
|
||||||
if (hx == 0) /* return sign(x)*0 */
|
if (ex > 0) {
|
||||||
return Zero[(uint32_t)sx>>31];
|
uxi -= 1U << 23;
|
||||||
while (hx < 0x00800000) { /* normalize x */
|
uxi |= (uint32_t)ex << 23;
|
||||||
hx = hx+hx;
|
} else {
|
||||||
iy -= 1;
|
uxi >>= -ex + 1;
|
||||||
}
|
}
|
||||||
if (iy >= -126) { /* normalize output */
|
uxi |= sx;
|
||||||
hx = ((hx-0x00800000)|((iy+127)<<23));
|
ux.i = uxi;
|
||||||
SET_FLOAT_WORD(x, hx|sx);
|
return ux.f;
|
||||||
} else { /* subnormal output */
|
|
||||||
n = -126 - iy;
|
|
||||||
hx >>= n;
|
|
||||||
SET_FLOAT_WORD(x, hx|sx);
|
|
||||||
}
|
|
||||||
return x; /* exact output */
|
|
||||||
}
|
}
|
||||||
|
217
src/math/fmodl.c
217
src/math/fmodl.c
@ -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"
|
#include "libm.h"
|
||||||
|
|
||||||
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
|
#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);
|
return fmod(x, y);
|
||||||
}
|
}
|
||||||
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
|
#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)
|
long double fmodl(long double x, long double y)
|
||||||
{
|
{
|
||||||
union IEEEl2bits ux, uy;
|
union ldshape ux = {x}, uy = {y};
|
||||||
int64_t hx,hz; /* We need a carry bit even if LDBL_MANH_SIZE is 32. */
|
int ex = ux.i.se & 0x7fff;
|
||||||
manh_t hy;
|
int ey = uy.i.se & 0x7fff;
|
||||||
manl_t lx,ly,lz;
|
int sx = ux.i.se & 0x8000;
|
||||||
int ix,iy,n,sx;
|
|
||||||
|
|
||||||
ux.e = x;
|
if (y == 0 || isnan(y) || ex == 0x7fff)
|
||||||
uy.e = y;
|
|
||||||
sx = ux.bits.sign;
|
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
return (x*y)/(x*y);
|
return (x*y)/(x*y);
|
||||||
if (ux.bits.exp <= uy.bits.exp) {
|
ux.i.se = ex;
|
||||||
if (ux.bits.exp < uy.bits.exp ||
|
uy.i.se = ey;
|
||||||
(ux.bits.manh<=uy.bits.manh &&
|
if (ux.f <= uy.f) {
|
||||||
(ux.bits.manh<uy.bits.manh ||
|
if (ux.f == uy.f)
|
||||||
ux.bits.manl<uy.bits.manl))) /* |x|<|y| return x or x-y */
|
return 0*x;
|
||||||
return x;
|
return x;
|
||||||
if (ux.bits.manh==uy.bits.manh && ux.bits.manl==uy.bits.manl)
|
|
||||||
return Zero[sx]; /* |x| = |y| return x*0 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* determine ix = ilogb(x) */
|
/* normalize x and y */
|
||||||
if (ux.bits.exp == 0) { /* subnormal x */
|
if (!ex) {
|
||||||
ux.e *= 0x1.0p512;
|
ux.f *= 0x1p120f;
|
||||||
ix = ux.bits.exp - (BIAS + 512);
|
ex = ux.i.se - 120;
|
||||||
} else {
|
}
|
||||||
ix = ux.bits.exp - BIAS;
|
if (!ey) {
|
||||||
|
uy.f *= 0x1p120f;
|
||||||
|
ey = uy.i.se - 120;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* determine iy = ilogb(y) */
|
/* x mod y */
|
||||||
if (uy.bits.exp == 0) { /* subnormal y */
|
#if LDBL_MANT_DIG == 64
|
||||||
uy.e *= 0x1.0p512;
|
uint64_t i, mx, my;
|
||||||
iy = uy.bits.exp - (BIAS + 512);
|
mx = ux.i.m;
|
||||||
} else {
|
my = uy.i.m;
|
||||||
iy = uy.bits.exp - BIAS;
|
for (; ex > ey; ex--) {
|
||||||
}
|
i = mx - my;
|
||||||
|
if (mx >= my) {
|
||||||
/* set up {hx,lx}, {hy,ly} and align y to x */
|
if (i == 0)
|
||||||
hx = SET_NBIT(ux.bits.manh);
|
return 0*x;
|
||||||
hy = SET_NBIT(uy.bits.manh);
|
mx = 2*i;
|
||||||
lx = ux.bits.manl;
|
} else if (2*mx < mx) {
|
||||||
ly = uy.bits.manl;
|
mx = 2*mx - my;
|
||||||
|
|
||||||
/* 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;
|
|
||||||
} else {
|
} else {
|
||||||
if ((hz|lz)==0) /* return sign(x)*0 */
|
mx = 2*mx;
|
||||||
return Zero[sx];
|
|
||||||
hx = hz+hz+(lz>>MANL_SHIFT);
|
|
||||||
lx = lz+lz;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hz = hx-hy;
|
i = mx - my;
|
||||||
lz = lx-ly;
|
if (mx >= my) {
|
||||||
if (lx < ly)
|
if (i == 0)
|
||||||
hz -= 1;
|
return 0*x;
|
||||||
if (hz >= 0) {
|
mx = i;
|
||||||
hx = hz;
|
|
||||||
lx = lz;
|
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
for (; xhi >> 48 == 0; xhi = 2*xhi + (xlo>>63), xlo = 2*xlo, ex--);
|
||||||
|
ux.i2.hi = xhi;
|
||||||
|
ux.i2.lo = xlo;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* convert back to floating value and restore the sign */
|
/* scale result */
|
||||||
if ((hx|lx) == 0) /* return sign(x)*0 */
|
if (ex <= 0) {
|
||||||
return Zero[sx];
|
ux.i.se = (ex+120)|sx;
|
||||||
while (hx < (1ULL<<HFRAC_BITS)) { /* normalize x */
|
ux.f *= 0x1p-120f;
|
||||||
hx = hx+hx+(lx>>MANL_SHIFT);
|
} else
|
||||||
lx = lx+lx;
|
ux.i.se = ex|sx;
|
||||||
iy -= 1;
|
return ux.f;
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
return ux.e; /* exact output */
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,36 +2,33 @@
|
|||||||
|
|
||||||
double modf(double x, double *iptr)
|
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;
|
uint64_t mask;
|
||||||
int e;
|
int e = (int)(u.i>>52 & 0x7ff) - 0x3ff;
|
||||||
|
|
||||||
e = (int)(u.n>>52 & 0x7ff) - 0x3ff;
|
|
||||||
|
|
||||||
/* no fractional part */
|
/* no fractional part */
|
||||||
if (e >= 52) {
|
if (e >= 52) {
|
||||||
*iptr = x;
|
*iptr = x;
|
||||||
if (e == 0x400 && u.n<<12 != 0) /* nan */
|
if (e == 0x400 && u.i<<12 != 0) /* nan */
|
||||||
return x;
|
return x;
|
||||||
u.n &= (uint64_t)1<<63;
|
u.i &= 1ULL<<63;
|
||||||
return u.x;
|
return u.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no integral part*/
|
/* no integral part*/
|
||||||
if (e < 0) {
|
if (e < 0) {
|
||||||
u.n &= (uint64_t)1<<63;
|
u.i &= 1ULL<<63;
|
||||||
*iptr = u.x;
|
*iptr = u.f;
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
mask = (uint64_t)-1>>12 >> e;
|
mask = -1ULL>>12>>e;
|
||||||
if ((u.n & mask) == 0) {
|
if ((u.i & mask) == 0) {
|
||||||
*iptr = x;
|
*iptr = x;
|
||||||
u.n &= (uint64_t)1<<63;
|
u.i &= 1ULL<<63;
|
||||||
return u.x;
|
return u.f;
|
||||||
}
|
}
|
||||||
u.n &= ~mask;
|
u.i &= ~mask;
|
||||||
*iptr = u.x;
|
*iptr = u.f;
|
||||||
STRICT_ASSIGN(double, x, x - *iptr);
|
return x - u.f;
|
||||||
return x;
|
|
||||||
}
|
}
|
||||||
|
@ -2,36 +2,33 @@
|
|||||||
|
|
||||||
float modff(float x, float *iptr)
|
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;
|
uint32_t mask;
|
||||||
int e;
|
int e = (int)(u.i>>23 & 0xff) - 0x7f;
|
||||||
|
|
||||||
e = (int)(u.n>>23 & 0xff) - 0x7f;
|
|
||||||
|
|
||||||
/* no fractional part */
|
/* no fractional part */
|
||||||
if (e >= 23) {
|
if (e >= 23) {
|
||||||
*iptr = x;
|
*iptr = x;
|
||||||
if (e == 0x80 && u.n<<9 != 0) { /* nan */
|
if (e == 0x80 && u.i<<9 != 0) { /* nan */
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
u.n &= 0x80000000;
|
u.i &= 0x80000000;
|
||||||
return u.x;
|
return u.f;
|
||||||
}
|
}
|
||||||
/* no integral part */
|
/* no integral part */
|
||||||
if (e < 0) {
|
if (e < 0) {
|
||||||
u.n &= 0x80000000;
|
u.i &= 0x80000000;
|
||||||
*iptr = u.x;
|
*iptr = u.f;
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
mask = 0x007fffff>>e;
|
mask = 0x007fffff>>e;
|
||||||
if ((u.n & mask) == 0) {
|
if ((u.i & mask) == 0) {
|
||||||
*iptr = x;
|
*iptr = x;
|
||||||
u.n &= 0x80000000;
|
u.i &= 0x80000000;
|
||||||
return u.x;
|
return u.f;
|
||||||
}
|
}
|
||||||
u.n &= ~mask;
|
u.i &= ~mask;
|
||||||
*iptr = u.x;
|
*iptr = u.f;
|
||||||
STRICT_ASSIGN(float, x, x - *iptr);
|
return x - u.f;
|
||||||
return x;
|
|
||||||
}
|
}
|
||||||
|
117
src/math/modfl.c
117
src/math/modfl.c
@ -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"
|
#include "libm.h"
|
||||||
|
|
||||||
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
|
#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);
|
return modf(x, (double *)iptr);
|
||||||
}
|
}
|
||||||
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
|
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
|
||||||
|
#if LDBL_MANT_DIG == 64
|
||||||
#if LDBL_MANL_SIZE > 32
|
#define TOINT 0x1p63
|
||||||
#define MASK ((uint64_t)-1)
|
#elif LDBL_MANT_DIG == 113
|
||||||
#else
|
#define TOINT 0x1p112
|
||||||
#define MASK ((uint32_t)-1)
|
|
||||||
#endif
|
#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)
|
long double modfl(long double x, long double *iptr)
|
||||||
{
|
{
|
||||||
union IEEEl2bits ux;
|
union ldshape u = {x};
|
||||||
int e;
|
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;
|
/* no fractional part */
|
||||||
e = ux.bits.exp - LDBL_MAX_EXP + 1;
|
if (e >= LDBL_MANT_DIG-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. */
|
|
||||||
*iptr = x;
|
*iptr = x;
|
||||||
if (e == LDBL_MAX_EXP && ((ux.bits.manh&~LDBL_NBIT)|ux.bits.manl)) /* nan */
|
if (isnan(x))
|
||||||
return x;
|
return x;
|
||||||
return zero[ux.bits.sign];
|
return s ? -0.0 : 0.0;
|
||||||
} 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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
|
#endif
|
||||||
|
@ -1,66 +1,7 @@
|
|||||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_remainder.c */
|
#include <math.h>
|
||||||
/*
|
|
||||||
* ====================================================
|
|
||||||
* 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 "libm.h"
|
double remainder(double x, double y)
|
||||||
|
|
||||||
double remainder(double x, double p)
|
|
||||||
{
|
{
|
||||||
int32_t hx,hp;
|
int q;
|
||||||
uint32_t sx,lx,lp;
|
return remquo(x, y, &q);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
@ -1,59 +1,7 @@
|
|||||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_remainderf.c */
|
#include <math.h>
|
||||||
/*
|
|
||||||
* 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 "libm.h"
|
float remainderf(float x, float y)
|
||||||
|
|
||||||
float remainderf(float x, float p)
|
|
||||||
{
|
{
|
||||||
int32_t hx,hp;
|
int q;
|
||||||
uint32_t sx;
|
return remquof(x, y, &q);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
@ -1,171 +1,82 @@
|
|||||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_remquo.c */
|
#include <math.h>
|
||||||
/*-
|
#include <stdint.h>
|
||||||
* ====================================================
|
|
||||||
* 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,};
|
|
||||||
|
|
||||||
double remquo(double x, double y, int *quo)
|
double remquo(double x, double y, int *quo)
|
||||||
{
|
{
|
||||||
int32_t n,hx,hy,hz,ix,iy,sx,i;
|
union {double f; uint64_t i;} ux = {x}, uy = {y};
|
||||||
uint32_t lx,ly,lz,q,sxy;
|
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;
|
||||||
|
|
||||||
EXTRACT_WORDS(hx, lx, x);
|
*quo = 0;
|
||||||
EXTRACT_WORDS(hy, ly, y);
|
if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff)
|
||||||
sxy = (hx ^ hy) & 0x80000000;
|
|
||||||
sx = hx & 0x80000000; /* sign of x */
|
|
||||||
hx ^= sx; /* |x| */
|
|
||||||
hy &= 0x7fffffff; /* |y| */
|
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
return (x*y)/(x*y);
|
return (x*y)/(x*y);
|
||||||
if (hx <= hy) {
|
if (ux.i<<1 == 0)
|
||||||
if (hx < hy || lx < ly) { /* |x| < |y| return x or x-y */
|
return x;
|
||||||
q = 0;
|
|
||||||
goto fixup;
|
/* normalize x and y */
|
||||||
}
|
if (!ex) {
|
||||||
if (lx == ly) { /* |x| = |y| return x*0 */
|
for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1);
|
||||||
*quo = sxy ? -1 : 1;
|
uxi <<= -ex + 1;
|
||||||
return Zero[(uint32_t)sx>>31];
|
} else {
|
||||||
}
|
uxi &= -1ULL >> 12;
|
||||||
|
uxi |= 1ULL << 52;
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fix point fmod */
|
|
||||||
n = ix - iy;
|
|
||||||
q = 0;
|
q = 0;
|
||||||
while (n--) {
|
if (ex < ey) {
|
||||||
hz = hx - hy;
|
if (ex+1 == ey)
|
||||||
lz = lx - ly;
|
goto end;
|
||||||
if (lx < ly)
|
return x;
|
||||||
hz--;
|
}
|
||||||
if (hz < 0) {
|
|
||||||
hx = hx + hx + (lx>>31);
|
/* x mod y */
|
||||||
lx = lx + lx;
|
for (; ex > ey; ex--) {
|
||||||
} else {
|
i = uxi - uy.i;
|
||||||
hx = hz + hz + (lz>>31);
|
if (i >> 63 == 0) {
|
||||||
lx = lz + lz;
|
uxi = i;
|
||||||
q++;
|
q++;
|
||||||
}
|
}
|
||||||
|
uxi <<= 1;
|
||||||
q <<= 1;
|
q <<= 1;
|
||||||
}
|
}
|
||||||
hz = hx - hy;
|
i = uxi - uy.i;
|
||||||
lz = lx - ly;
|
if (i >> 63 == 0) {
|
||||||
if (lx < ly)
|
uxi = i;
|
||||||
hz--;
|
|
||||||
if (hz >= 0) {
|
|
||||||
hx = hz;
|
|
||||||
lx = lz;
|
|
||||||
q++;
|
q++;
|
||||||
}
|
}
|
||||||
|
if (uxi == 0)
|
||||||
/* convert back to floating value and restore the sign */
|
ex = -60;
|
||||||
if ((hx|lx) == 0) { /* return sign(x)*0 */
|
else
|
||||||
q &= 0x7fffffff;
|
for (; uxi>>52 == 0; uxi <<= 1, ex--);
|
||||||
*quo = sxy ? -q : q;
|
end:
|
||||||
return Zero[(uint32_t)sx>>31];
|
/* scale result and decide between |x| and |x|-|y| */
|
||||||
|
if (ex > 0) {
|
||||||
|
uxi -= 1ULL << 52;
|
||||||
|
uxi |= (uint64_t)ex << 52;
|
||||||
|
} else {
|
||||||
|
uxi >>= -ex + 1;
|
||||||
}
|
}
|
||||||
while (hx < 0x00100000) { /* normalize x */
|
ux.i = uxi;
|
||||||
hx = hx + hx + (lx>>31);
|
x = ux.f;
|
||||||
lx = lx + lx;
|
if (sy)
|
||||||
iy--;
|
y = -y;
|
||||||
}
|
if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) {
|
||||||
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++;
|
|
||||||
x -= y;
|
x -= y;
|
||||||
|
q++;
|
||||||
}
|
}
|
||||||
GET_HIGH_WORD(hx, x);
|
|
||||||
SET_HIGH_WORD(x, hx ^ sx);
|
|
||||||
q &= 0x7fffffff;
|
q &= 0x7fffffff;
|
||||||
*quo = sxy ? -q : q;
|
*quo = sx^sy ? -(int)q : (int)q;
|
||||||
return x;
|
return sx ? -x : x;
|
||||||
}
|
}
|
||||||
|
@ -1,126 +1,82 @@
|
|||||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_remquof.c */
|
#include <math.h>
|
||||||
/*-
|
#include <stdint.h>
|
||||||
* ====================================================
|
|
||||||
* 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,};
|
|
||||||
|
|
||||||
float remquof(float x, float y, int *quo)
|
float remquof(float x, float y, int *quo)
|
||||||
{
|
{
|
||||||
int32_t n,hx,hy,hz,ix,iy,sx,i;
|
union {float f; uint32_t i;} ux = {x}, uy = {y};
|
||||||
uint32_t q,sxy;
|
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);
|
*quo = 0;
|
||||||
GET_FLOAT_WORD(hy, y);
|
if (uy.i<<1 == 0 || isnan(y) || ex == 0xff)
|
||||||
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 */
|
|
||||||
return (x*y)/(x*y);
|
return (x*y)/(x*y);
|
||||||
if (hx < hy) { /* |x| < |y| return x or x-y */
|
if (ux.i<<1 == 0)
|
||||||
q = 0;
|
return x;
|
||||||
goto fixup;
|
|
||||||
} else if(hx==hy) { /* |x| = |y| return x*0*/
|
/* normalize x and y */
|
||||||
*quo = sxy ? -1 : 1;
|
if (!ex) {
|
||||||
return Zero[(uint32_t)sx>>31];
|
for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1);
|
||||||
|
uxi <<= -ex + 1;
|
||||||
|
} else {
|
||||||
|
uxi &= -1U >> 9;
|
||||||
|
uxi |= 1U << 23;
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
if (iy >= -126)
|
|
||||||
hy = 0x00800000|(0x007fffff&hy);
|
|
||||||
else { /* subnormal y, shift y to normal */
|
|
||||||
n = -126 - iy;
|
|
||||||
hy <<= n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fix point fmod */
|
|
||||||
n = ix - iy;
|
|
||||||
q = 0;
|
q = 0;
|
||||||
while (n--) {
|
if (ex < ey) {
|
||||||
hz = hx - hy;
|
if (ex+1 == ey)
|
||||||
if (hz < 0)
|
goto end;
|
||||||
hx = hx << 1;
|
return x;
|
||||||
else {
|
}
|
||||||
hx = hz << 1;
|
|
||||||
|
/* x mod y */
|
||||||
|
for (; ex > ey; ex--) {
|
||||||
|
i = uxi - uy.i;
|
||||||
|
if (i >> 31 == 0) {
|
||||||
|
uxi = i;
|
||||||
q++;
|
q++;
|
||||||
}
|
}
|
||||||
|
uxi <<= 1;
|
||||||
q <<= 1;
|
q <<= 1;
|
||||||
}
|
}
|
||||||
hz = hx - hy;
|
i = uxi - uy.i;
|
||||||
if (hz >= 0) {
|
if (i >> 31 == 0) {
|
||||||
hx = hz;
|
uxi = i;
|
||||||
q++;
|
q++;
|
||||||
}
|
}
|
||||||
|
if (uxi == 0)
|
||||||
/* convert back to floating value and restore the sign */
|
ex = -30;
|
||||||
if (hx == 0) { /* return sign(x)*0 */
|
else
|
||||||
q &= 0x7fffffff;
|
for (; uxi>>23 == 0; uxi <<= 1, ex--);
|
||||||
*quo = sxy ? -q : q;
|
end:
|
||||||
return Zero[(uint32_t)sx>>31];
|
/* scale result and decide between |x| and |x|-|y| */
|
||||||
|
if (ex > 0) {
|
||||||
|
uxi -= 1U << 23;
|
||||||
|
uxi |= (uint32_t)ex << 23;
|
||||||
|
} else {
|
||||||
|
uxi >>= -ex + 1;
|
||||||
}
|
}
|
||||||
while (hx < 0x00800000) { /* normalize x */
|
ux.i = uxi;
|
||||||
hx <<= 1;
|
x = ux.f;
|
||||||
iy--;
|
if (sy)
|
||||||
}
|
y = -y;
|
||||||
if (iy >= -126) { /* normalize output */
|
if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) {
|
||||||
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++;
|
|
||||||
x -= y;
|
x -= y;
|
||||||
|
q++;
|
||||||
}
|
}
|
||||||
GET_FLOAT_WORD(hx, x);
|
|
||||||
SET_FLOAT_WORD(x, hx ^ sx);
|
|
||||||
q &= 0x7fffffff;
|
q &= 0x7fffffff;
|
||||||
*quo = sxy ? -q : q;
|
*quo = sx^sy ? -(int)q : (int)q;
|
||||||
return x;
|
return sx ? -x : x;
|
||||||
}
|
}
|
||||||
|
@ -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"
|
#include "libm.h"
|
||||||
|
|
||||||
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
|
#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);
|
return remquo(x, y, quo);
|
||||||
}
|
}
|
||||||
#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384
|
#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)
|
long double remquol(long double x, long double y, int *quo)
|
||||||
{
|
{
|
||||||
union IEEEl2bits ux, uy;
|
union ldshape ux = {x}, uy = {y};
|
||||||
int64_t hx,hz; /* We need a carry bit even if LDBL_MANH_SIZE is 32. */
|
int ex = ux.i.se & 0x7fff;
|
||||||
manh_t hy;
|
int ey = uy.i.se & 0x7fff;
|
||||||
manl_t lx,ly,lz;
|
int sx = ux.i.se >> 15;
|
||||||
int ix,iy,n,q,sx,sxy;
|
int sy = uy.i.se >> 15;
|
||||||
|
uint32_t q;
|
||||||
|
|
||||||
ux.e = x;
|
*quo = 0;
|
||||||
uy.e = y;
|
if (y == 0 || isnan(y) || ex == 0x7fff)
|
||||||
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 */
|
|
||||||
return (x*y)/(x*y);
|
return (x*y)/(x*y);
|
||||||
if (ux.bits.exp <= uy.bits.exp) {
|
if (x == 0)
|
||||||
if ((ux.bits.exp < uy.bits.exp) ||
|
return x;
|
||||||
(ux.bits.manh <= uy.bits.manh &&
|
|
||||||
(ux.bits.manh < uy.bits.manh ||
|
/* normalize x and y */
|
||||||
ux.bits.manl < uy.bits.manl))) {
|
if (!ex) {
|
||||||
q = 0;
|
ux.i.se = ex;
|
||||||
goto fixup; /* |x|<|y| return x or x-y */
|
ux.f *= 0x1p120f;
|
||||||
}
|
ex = ux.i.se - 120;
|
||||||
if (ux.bits.manh == uy.bits.manh && ux.bits.manl == uy.bits.manl) {
|
}
|
||||||
*quo = sxy ? -1 : 1;
|
if (!ey) {
|
||||||
return Zero[sx]; /* |x|=|y| return x*0*/
|
uy.i.se = ey;
|
||||||
}
|
uy.f *= 0x1p120f;
|
||||||
|
ey = uy.i.se - 120;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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;
|
q = 0;
|
||||||
|
if (ex >= ey) {
|
||||||
while (n--) {
|
/* x mod y */
|
||||||
hz = hx - hy;
|
#if LDBL_MANT_DIG == 64
|
||||||
lz = lx - ly;
|
uint64_t i, mx, my;
|
||||||
if (lx < ly)
|
mx = ux.i.m;
|
||||||
hz -= 1;
|
my = uy.i.m;
|
||||||
if (hz < 0) {
|
for (; ex > ey; ex--) {
|
||||||
hx = hx + hx + (lx>>MANL_SHIFT);
|
i = mx - my;
|
||||||
lx = lx + lx;
|
if (mx >= my) {
|
||||||
} else {
|
mx = 2*i;
|
||||||
hx = hz + hz + (lz>>MANL_SHIFT);
|
q++;
|
||||||
lx = lz + lz;
|
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++;
|
||||||
}
|
}
|
||||||
q <<= 1;
|
if (mx == 0)
|
||||||
}
|
ex = -120;
|
||||||
hz = hx - hy;
|
else
|
||||||
lz = lx - ly;
|
for (; mx >> 63 == 0; mx *= 2, ex--);
|
||||||
if (lx < ly)
|
ux.i.m = mx;
|
||||||
hz -= 1;
|
#elif LDBL_MANT_DIG == 113
|
||||||
if (hz >= 0) {
|
uint64_t hi, lo, xhi, xlo, yhi, ylo;
|
||||||
hx = hz;
|
xhi = (ux.i2.hi & -1ULL>>16) | 1ULL<<48;
|
||||||
lx = lz;
|
yhi = (uy.i2.hi & -1ULL>>16) | 1ULL<<48;
|
||||||
q++;
|
xlo = ux.i2.lo;
|
||||||
}
|
ylo = ux.i2.lo;
|
||||||
|
for (; ex > ey; ex--) {
|
||||||
/* convert back to floating value and restore the sign */
|
hi = xhi - yhi;
|
||||||
if ((hx|lx) == 0) { /* return sign(x)*0 */
|
lo = xlo - ylo;
|
||||||
q &= 0x7fffffff;
|
if (xlo < ylo)
|
||||||
*quo = sxy ? -q : q;
|
hi -= 1;
|
||||||
return Zero[sx];
|
if (hi >> 63 == 0) {
|
||||||
}
|
xhi = 2*hi + (lo>>63);
|
||||||
while (hx < (1ULL<<HFRAC_BITS)) { /* normalize x */
|
xlo = 2*lo;
|
||||||
hx = hx + hx + (lx>>MANL_SHIFT);
|
q++;
|
||||||
lx = lx + lx;
|
} else {
|
||||||
iy -= 1;
|
xhi = 2*xhi + (xlo>>63);
|
||||||
}
|
xlo = 2*xlo;
|
||||||
ux.bits.manh = hx; /* The integer bit is truncated here if needed. */
|
}
|
||||||
ux.bits.manl = lx;
|
q <<= 1;
|
||||||
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))) {
|
|
||||||
q++;
|
|
||||||
x-=y;
|
|
||||||
}
|
}
|
||||||
} else if (x > 0.5*y || (x == 0.5*y && (q & 1))) {
|
hi = xhi - yhi;
|
||||||
q++;
|
lo = xlo - ylo;
|
||||||
x-=y;
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
ux.e = x;
|
/* scale result and decide between |x| and |x|-|y| */
|
||||||
ux.bits.sign ^= sx;
|
if (ex <= 0) {
|
||||||
x = ux.e;
|
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;
|
q &= 0x7fffffff;
|
||||||
*quo = sxy ? -q : q;
|
*quo = sx^sy ? -(int)q : (int)q;
|
||||||
return x;
|
return sx ? -x : x;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user