feat(math): abs/round/trunc/frexp/ldexp/scalbn/copysign/fmin/fmax/fmod
This commit is contained in:
+215
@@ -0,0 +1,215 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user