#ifdef HAVE_CONFIG_H #include #endif #include /* * 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; }