diff options
Diffstat (limited to 'src/math/remainderf.c')
-rw-r--r-- | src/math/remainderf.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/src/math/remainderf.c b/src/math/remainderf.c new file mode 100644 index 00000000..c17bb4f4 --- /dev/null +++ b/src/math/remainderf.c @@ -0,0 +1,64 @@ +/* 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 "libm.h" + +static const float zero = 0.0; + +float remainderf(float x, float p) +{ + 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) /* p = 0 */ + return (x*p)/(x*p); + if (hx >= 0x7f800000 || hp > 0x7f800000) /* x not finite, p is NaN */ + // FIXME: why long double? + return ((long double)x*p)/((long double)x*p); + + if (hp <= 0x7effffff) + x = fmodf(x, p + p); /* now x < 2p */ + if (hx - hp == 0) + return zero*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 = (float)0.5*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; +} |