216 lines
5.3 KiB
C
216 lines
5.3 KiB
C
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <math.h>
|
|
|
|
/*
|
|
* Split x into an integral part stored in *iptr and a fractional part
|
|
* returned, both carrying x's sign (C23 7.12.6.5): modf(-1.5, &i) puts
|
|
* -1.0 in i and returns -0.5. The integral part is x truncated toward
|
|
* zero. modf(±0, &i) stores ±0 and returns ±0; modf(±Inf, &i) stores
|
|
* ±Inf and returns ±0 with x's sign; modf(NaN, &i) stores the NaN and
|
|
* returns it; a subnormal |x| < 1 stores ±0 (x's sign) and returns x.
|
|
*
|
|
* The implementation is a bit-level truncation (the same "clear the
|
|
* fractional mantissa bits" shape as trunc.c): a value with |x| < 1 has
|
|
* integral part ±0; a value too large to carry a fraction (|x| >= 2^52,
|
|
* >= 2^23, >= 2^63 for the three formats) is its own integral part; the
|
|
* values in between have their low (fraction) bits masked off. The
|
|
* fractional part is then x - i, an exact subtraction — x and i share the
|
|
* significand's leading bits, so the difference is a representable
|
|
* multiple of the common unit in the last place. When the subtraction is
|
|
* an exact zero the fraction is ±0 with x's sign, which the hardware
|
|
* would otherwise always report as +0.
|
|
*/
|
|
|
|
/*
|
|
* The double format: bit 63 the sign, bits 62..52 the exponent biased by
|
|
* 1023, bits 51..0 the fraction. A normal with exponent field e in
|
|
* [1023, 1074] has its low (1075 - e) fraction bits below the binary
|
|
* point; e >= 1075 means |x| >= 2^52, an integer already.
|
|
*/
|
|
double
|
|
modf(double x, double *iptr)
|
|
{
|
|
unsigned long long bits;
|
|
unsigned long long sign;
|
|
unsigned long long ef;
|
|
unsigned long long frac;
|
|
unsigned long long ibits;
|
|
double i;
|
|
double f;
|
|
int shift;
|
|
|
|
__builtin_memcpy(&bits, &x, sizeof bits);
|
|
sign = bits & (1ULL << 63);
|
|
ef = (bits >> 52) & 0x7ff;
|
|
frac = bits & 0xFFFFFFFFFFFFFULL;
|
|
|
|
if (ef == 0x7ff)
|
|
{
|
|
*iptr = x;
|
|
if (frac != 0)
|
|
{
|
|
return x; /* NaN: both parts are the NaN */
|
|
}
|
|
return sign != 0 ? -0.0 : 0.0; /* ±Inf: fraction ±0 of x's sign */
|
|
}
|
|
if (ef == 0)
|
|
{
|
|
if (frac == 0)
|
|
{
|
|
*iptr = x; /* ±0 */
|
|
return x;
|
|
}
|
|
*iptr = sign != 0 ? -0.0 : 0.0; /* subnormal: |x| < 1 */
|
|
return x;
|
|
}
|
|
if (ef >= 1075)
|
|
{
|
|
*iptr = x; /* |x| >= 2^52: already integral */
|
|
return sign != 0 ? -0.0 : 0.0;
|
|
}
|
|
if (ef < 1023)
|
|
{
|
|
*iptr = sign != 0 ? -0.0 : 0.0; /* 0 < |x| < 1 */
|
|
return x;
|
|
}
|
|
|
|
shift = 1075 - (int)ef;
|
|
ibits = bits & ~((1ULL << shift) - 1ULL);
|
|
__builtin_memcpy(&i, &ibits, sizeof i);
|
|
*iptr = i;
|
|
f = x - i;
|
|
if (f == 0.0)
|
|
{
|
|
return sign != 0 ? -0.0 : 0.0;
|
|
}
|
|
return f;
|
|
}
|
|
|
|
/*
|
|
* The float format: bit 31 the sign, bits 30..23 the exponent biased by
|
|
* 127, bits 22..0 the fraction. For e in [127, 149] the low (150 - e)
|
|
* fraction bits are fractional; e >= 150 means |x| >= 2^23, integral.
|
|
*/
|
|
float
|
|
modff(float x, float *iptr)
|
|
{
|
|
unsigned int bits;
|
|
unsigned int sign;
|
|
unsigned int ef;
|
|
unsigned int frac;
|
|
unsigned int ibits;
|
|
float i;
|
|
float f;
|
|
int shift;
|
|
|
|
__builtin_memcpy(&bits, &x, sizeof bits);
|
|
sign = bits & (1U << 31);
|
|
ef = (bits >> 23) & 0xff;
|
|
frac = bits & 0x7FFFFFU;
|
|
|
|
if (ef == 0xff)
|
|
{
|
|
*iptr = x;
|
|
if (frac != 0)
|
|
{
|
|
return x;
|
|
}
|
|
return sign != 0 ? -0.0f : 0.0f;
|
|
}
|
|
if (ef == 0)
|
|
{
|
|
if (frac == 0)
|
|
{
|
|
*iptr = x;
|
|
return x;
|
|
}
|
|
*iptr = sign != 0 ? -0.0f : 0.0f;
|
|
return x;
|
|
}
|
|
if (ef >= 150)
|
|
{
|
|
*iptr = x;
|
|
return sign != 0 ? -0.0f : 0.0f;
|
|
}
|
|
if (ef < 127)
|
|
{
|
|
*iptr = sign != 0 ? -0.0f : 0.0f;
|
|
return x;
|
|
}
|
|
|
|
shift = 150 - (int)ef;
|
|
ibits = bits & ~((1U << shift) - 1U);
|
|
__builtin_memcpy(&i, &ibits, sizeof i);
|
|
*iptr = i;
|
|
f = x - i;
|
|
if (f == 0.0f)
|
|
{
|
|
return sign != 0 ? -0.0f : 0.0f;
|
|
}
|
|
return f;
|
|
}
|
|
|
|
/*
|
|
* The x86 80-bit extended format: 64 significand bits m with an explicit
|
|
* integer bit and a sign/exponent word se biased by 16383. For e in
|
|
* [16383, 16445] the low (16446 - e) bits of m are fractional; e >= 16446
|
|
* means |x| >= 2^63, integral.
|
|
*/
|
|
long double
|
|
modfl(long double x, long double *iptr)
|
|
{
|
|
struct
|
|
{
|
|
unsigned long long m;
|
|
unsigned short se;
|
|
} p;
|
|
unsigned long long ibits;
|
|
long double i;
|
|
long double f;
|
|
int ef;
|
|
int shift;
|
|
|
|
__builtin_memcpy(&p, &x, sizeof p);
|
|
ef = p.se & 0x7fff;
|
|
|
|
if (ef == 0x7fff)
|
|
{
|
|
*iptr = x;
|
|
if (p.m != 0x8000000000000000ULL)
|
|
{
|
|
return x; /* NaN */
|
|
}
|
|
return (p.se & 0x8000) != 0 ? -0.0L : 0.0L; /* ±Inf */
|
|
}
|
|
if (p.m == 0)
|
|
{
|
|
*iptr = x; /* ±0 */
|
|
return x;
|
|
}
|
|
if (ef >= 16446)
|
|
{
|
|
*iptr = x;
|
|
return (p.se & 0x8000) != 0 ? -0.0L : 0.0L;
|
|
}
|
|
if (ef < 16383)
|
|
{
|
|
*iptr = (p.se & 0x8000) != 0 ? -0.0L : 0.0L; /* subnormal: |x| < 1 */
|
|
return x;
|
|
}
|
|
|
|
shift = 16446 - ef;
|
|
ibits = p.m & ~((1ULL << shift) - 1ULL);
|
|
p.m = ibits;
|
|
__builtin_memcpy(&i, &p, sizeof i);
|
|
*iptr = i;
|
|
f = x - i;
|
|
if (f == 0.0L)
|
|
{
|
|
return (p.se & 0x8000) != 0 ? -0.0L : 0.0L;
|
|
}
|
|
return f;
|
|
}
|