feat(math): abs/round/trunc/frexp/ldexp/scalbn/copysign/fmin/fmax/fmod
This commit is contained in:
+173
@@ -0,0 +1,173 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* Smallest integral value not less than x (C23 7.12.9.1), all three
|
||||
* precisions.
|
||||
*
|
||||
* As with floor (see floor.c), GCC does not fold the __builtin_ceil forms
|
||||
* on this target, so each function works on the IEEE 754 bit pattern.
|
||||
* Clearing the fraction bits rounds toward zero, which is already the
|
||||
* correct direction for a negative argument; a positive argument with a
|
||||
* nonzero fraction must then step up by one (an exact integer + 1.0).
|
||||
* ceil(-0.3) is a real -0.0, and ±0/±Inf/NaN pass through unchanged.
|
||||
*/
|
||||
|
||||
static double
|
||||
ceil_d(double x)
|
||||
{
|
||||
const unsigned long long sign_mask = 1ULL << 63;
|
||||
unsigned long long bits;
|
||||
unsigned long long frac;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
e = (int)((bits >> 52) & 0x7ff);
|
||||
|
||||
if (e >= 1075)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 1023)
|
||||
{
|
||||
if ((bits & ~sign_mask) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
return (bits & sign_mask) != 0 ? -0.0 : 1.0;
|
||||
}
|
||||
|
||||
shift = 1075 - e;
|
||||
frac = (1ULL << shift) - 1;
|
||||
if ((bits & sign_mask) != 0)
|
||||
{
|
||||
bits &= ~frac;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
if ((bits & frac) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
bits &= ~frac;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x + 1.0;
|
||||
}
|
||||
|
||||
static float
|
||||
ceil_f(float x)
|
||||
{
|
||||
const unsigned int sign_mask = 1U << 31;
|
||||
unsigned int bits;
|
||||
unsigned int frac;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
e = (int)((bits >> 23) & 0xff);
|
||||
|
||||
if (e >= 150)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 127)
|
||||
{
|
||||
if ((bits & ~sign_mask) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
return (bits & sign_mask) != 0 ? -0.0f : 1.0f;
|
||||
}
|
||||
|
||||
shift = 150 - e;
|
||||
frac = (1U << shift) - 1U;
|
||||
if ((bits & sign_mask) != 0)
|
||||
{
|
||||
bits &= ~frac;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
if ((bits & frac) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
bits &= ~frac;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x + 1.0f;
|
||||
}
|
||||
|
||||
static long double
|
||||
ceil_ld(long double x)
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
} p;
|
||||
unsigned long long frac;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
e = p.se & 0x7fff;
|
||||
|
||||
if (e >= 16446)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 16383)
|
||||
{
|
||||
if (p.m == 0 && (p.se & 0x7fff) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
return (p.se & 0x8000) != 0 ? -0.0L : 1.0L;
|
||||
}
|
||||
|
||||
shift = 63 - (e - 16383);
|
||||
frac = (1ULL << shift) - 1ULL;
|
||||
if ((p.se & 0x8000) != 0)
|
||||
{
|
||||
p.m &= ~frac;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
if ((p.m & frac) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
p.m &= ~frac;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x + 1.0L;
|
||||
}
|
||||
|
||||
/*
|
||||
* As ceil, for a float argument.
|
||||
*/
|
||||
float
|
||||
ceilf(float x)
|
||||
{
|
||||
return ceil_f(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As ceil, for a double argument.
|
||||
*/
|
||||
double
|
||||
ceil(double x)
|
||||
{
|
||||
return ceil_d(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As ceil, for a long double argument.
|
||||
*/
|
||||
long double
|
||||
ceill(long double x)
|
||||
{
|
||||
return ceil_ld(x);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* Copy the sign of y onto the magnitude of x, all three precisions (C23
|
||||
* 7.12.7.3). Each function below splices the sign bit of y into the IEEE
|
||||
* 754 bit pattern of x: the magnitude of x is untouched (so a NaN keeps
|
||||
* its payload) and copysign(±0, y) carries y's sign. GCC's
|
||||
* __builtin_copysign forms do fold to andp/orp pairs on this target, but
|
||||
* the compiler diagnoses the __builtin_ call inside the identically named
|
||||
* function as infinite recursion, so the splice is written out directly;
|
||||
* it compiles to the same two instructions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A float with the magnitude of x and the sign of y.
|
||||
*/
|
||||
float
|
||||
copysignf(float x, float y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
unsigned int xb;
|
||||
unsigned int yb;
|
||||
|
||||
__builtin_memcpy(&xb, &x, sizeof xb);
|
||||
__builtin_memcpy(&yb, &y, sizeof yb);
|
||||
xb = (xb & 0x7fffffffU) | (yb & 0x80000000U);
|
||||
__builtin_memcpy(&x, &xb, sizeof xb);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* A double with the magnitude of x and the sign of y.
|
||||
*/
|
||||
double
|
||||
copysign(double x, double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
unsigned long long xb;
|
||||
unsigned long long yb;
|
||||
|
||||
__builtin_memcpy(&xb, &x, sizeof xb);
|
||||
__builtin_memcpy(&yb, &y, sizeof yb);
|
||||
xb = (xb & 0x7fffffffffffffffULL) | (yb & 0x8000000000000000ULL);
|
||||
__builtin_memcpy(&x, &xb, sizeof xb);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* A long double with the magnitude of x and the sign of y. The x86 80-bit
|
||||
* extended format keeps the sign in bit 15 of the sign/exponent word at
|
||||
* bytes 8..9, so only that bit is spliced.
|
||||
*/
|
||||
long double
|
||||
copysignl(long double x, long double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
} xp;
|
||||
struct
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
} yp;
|
||||
|
||||
__builtin_memcpy(&xp, &x, sizeof xp);
|
||||
__builtin_memcpy(&yp, &y, sizeof yp);
|
||||
xp.se = (unsigned short)((xp.se & 0x7fff) | (yp.se & 0x8000));
|
||||
__builtin_memcpy(&x, &xp, sizeof xp);
|
||||
return x;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* Absolute value, all three precisions (C23 7.12.7.2). GCC folds
|
||||
* __builtin_fabs/__builtin_fabsf/__builtin_fabsl into a single
|
||||
* sign-clearing SSE/x87 instruction at every optimization level (verified
|
||||
* at -O0 and -O2), so the call never recurses and no errno path exists.
|
||||
* The sign-bit clear is exact: fabs(-0.0) is +0.0, fabs(±Inf) is +Inf,
|
||||
* and a NaN keeps its payload.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Absolute value of x as a float.
|
||||
*/
|
||||
float
|
||||
fabsf(float x)
|
||||
{
|
||||
return __builtin_fabsf(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* Absolute value of x as a double.
|
||||
*/
|
||||
double
|
||||
fabs(double x)
|
||||
{
|
||||
return __builtin_fabs(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* Absolute value of x as a long double.
|
||||
*/
|
||||
long double
|
||||
fabsl(long double x)
|
||||
{
|
||||
return __builtin_fabsl(x);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* The positive difference x - y when x > y and +0.0 otherwise (C23
|
||||
* 7.12.12.2), all three precisions.
|
||||
*
|
||||
* C23 keeps fdim(x, NaN) and fdim(NaN, x) NaN, so the two arguments are
|
||||
* screened before the ordering test; a NaN result is the quiet NaN that
|
||||
* the x + y addition below produces (matching the host glibc). With both
|
||||
* operands numeric, x > y is an ordinary comparison (no exceptions) and
|
||||
* the single subtraction x - y is the whole computation: an exact
|
||||
* representable difference stays exact, and a difference too large for the
|
||||
* format overflows through the hardware into +Inf exactly as glibc's does,
|
||||
* with the overflow flag raised and no extra help needed. x <= y -- the
|
||||
* signed-zero and equal cases included -- returns a plain +0.0.
|
||||
*/
|
||||
|
||||
/*
|
||||
* fdim of two floats.
|
||||
*/
|
||||
float
|
||||
fdimf(float x, float y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
if (isnan(x) || isnan(y))
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
if (x > y)
|
||||
{
|
||||
return x - y;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
* fdim of two doubles.
|
||||
*/
|
||||
double
|
||||
fdim(double x, double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
if (isnan(x) || isnan(y))
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
if (x > y)
|
||||
{
|
||||
return x - y;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fdim of two long doubles.
|
||||
*/
|
||||
long double
|
||||
fdiml(long double x, long double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
if (isnan(x) || isnan(y))
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
if (x > y)
|
||||
{
|
||||
return x - y;
|
||||
}
|
||||
return 0.0L;
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* Largest integral value not greater than x (C23 7.12.9.2), all three
|
||||
* precisions.
|
||||
*
|
||||
* GCC emits an external floor/floorf/floorl call for the __builtin_ forms
|
||||
* at every optimization level on this target (no SSE4.1 in the default
|
||||
* -march, so the roundsd expansion is unavailable and the builtin is not
|
||||
* folded), so each function below is implemented directly on the IEEE 754
|
||||
* bit pattern instead: clearing the fraction bits rounds toward zero, and
|
||||
* a negative argument with a nonzero fraction must then step down by one.
|
||||
* The clearing and the exact integer - 1.0 are both exact, so no rounding
|
||||
* mode and no floating-point exception is involved; ±0/±Inf/NaN pass
|
||||
* through and signed zero is preserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The double format: bit 63 is the sign, bits 62..52 the exponent biased
|
||||
* by 1023, bits 51..0 the fraction. A finite value with exponent e has
|
||||
* |x| in [2^(e-1023), 2^(e-1022)) and a fraction only when e - 1023 < 52,
|
||||
* i.e. e < 1075; for e in [1023, 1074] exactly the low (1075 - e) bits of
|
||||
* the fraction word are the fractional part.
|
||||
*/
|
||||
static double
|
||||
floor_d(double x)
|
||||
{
|
||||
const unsigned long long sign_mask = 1ULL << 63;
|
||||
unsigned long long bits;
|
||||
unsigned long long frac;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
e = (int)((bits >> 52) & 0x7ff);
|
||||
|
||||
/* |x| >= 2^52 is already integral; Inf (e == 0x7ff) and NaN must pass
|
||||
* through unchanged as well. */
|
||||
if (e >= 1075)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
/* |x| < 1: floor is +0 for a nonnegative x and -1 for a negative one,
|
||||
* except that ±0 is its own floor. */
|
||||
if (e < 1023)
|
||||
{
|
||||
if ((bits & ~sign_mask) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
return (bits & sign_mask) != 0 ? -1.0 : 0.0;
|
||||
}
|
||||
|
||||
shift = 1075 - e;
|
||||
frac = (1ULL << shift) - 1;
|
||||
if ((bits & sign_mask) == 0)
|
||||
{
|
||||
bits &= ~frac;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Negative: round toward zero, then take one more step down when a
|
||||
* fraction was dropped. The truncation leaves an integer-valued
|
||||
* double, so subtracting 1.0 is exact. */
|
||||
if ((bits & frac) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
bits &= ~frac;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x - 1.0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The float format: bit 31 is the sign, bits 30..23 the exponent biased
|
||||
* by 127, bits 22..0 the fraction. Fraction bits exist exactly when the
|
||||
* exponent e is in [127, 149]; the low (150 - e) bits are fractional.
|
||||
*/
|
||||
static float
|
||||
floor_f(float x)
|
||||
{
|
||||
const unsigned int sign_mask = 1U << 31;
|
||||
unsigned int bits;
|
||||
unsigned int frac;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
e = (int)((bits >> 23) & 0xff);
|
||||
|
||||
if (e >= 150)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 127)
|
||||
{
|
||||
if ((bits & ~sign_mask) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
return (bits & sign_mask) != 0 ? -1.0f : 0.0f;
|
||||
}
|
||||
|
||||
shift = 150 - e;
|
||||
frac = (1U << shift) - 1U;
|
||||
if ((bits & sign_mask) == 0)
|
||||
{
|
||||
bits &= ~frac;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
if ((bits & frac) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
bits &= ~frac;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x - 1.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
* The x86 80-bit extended format: 64 significand bits m (the integer bit
|
||||
* is explicit) in bytes 0..7 and a sign/exponent word se in bytes 8..9,
|
||||
* with the sign in bit 15 and the exponent (biased by 16383) in bits
|
||||
* 14..0. A value m * 2^(e - 16446) has fractional bits only when
|
||||
* e - 16383 < 63, i.e. e < 16446; for e in [16383, 16445] exactly the low
|
||||
* (63 - (e - 16383)) bits of m are fractional.
|
||||
*/
|
||||
static long double
|
||||
floor_ld(long double x)
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
} p;
|
||||
unsigned long long frac;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
e = p.se & 0x7fff;
|
||||
|
||||
/* |x| >= 2^63 is already integral; Inf (e == 0x7fff) and NaN pass
|
||||
* through unchanged as well. */
|
||||
if (e >= 16446)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 16383)
|
||||
{
|
||||
if (p.m == 0 && (p.se & 0x7fff) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
return (p.se & 0x8000) != 0 ? -1.0L : 0.0L;
|
||||
}
|
||||
|
||||
shift = 63 - (e - 16383);
|
||||
frac = (1ULL << shift) - 1ULL;
|
||||
if ((p.se & 0x8000) == 0)
|
||||
{
|
||||
p.m &= ~frac;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
if ((p.m & frac) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
p.m &= ~frac;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x - 1.0L;
|
||||
}
|
||||
|
||||
/*
|
||||
* As floor, for a float argument.
|
||||
*/
|
||||
float
|
||||
floorf(float x)
|
||||
{
|
||||
return floor_f(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As floor, for a double argument.
|
||||
*/
|
||||
double
|
||||
floor(double x)
|
||||
{
|
||||
return floor_d(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As floor, for a long double argument.
|
||||
*/
|
||||
long double
|
||||
floorl(long double x)
|
||||
{
|
||||
return floor_ld(x);
|
||||
}
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* The larger of x and y (C23 7.12.12.3), all three precisions.
|
||||
*
|
||||
* The mirror image of fmin (see fmin.c for the full reasoning): a quiet
|
||||
* NaN argument is ignored in favor of the numeric one, a signaling NaN
|
||||
* argument makes the result that signaling NaN quieted, and a +0.0/-0.0
|
||||
* pair returns +0.0. Only the equal-argument tie rule (and, with it, the
|
||||
* direction of the zero preference) differs from fmin; the numeric
|
||||
* comparisons, the NaN screens and the word-level quiet splice are
|
||||
* otherwise identical, so the implementation shares the shape of fmin.c
|
||||
* and is likewise pure.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The double format: bit 63 is the sign, bits 62..52 the exponent biased
|
||||
* by 1023, bits 51..0 the fraction; exponent 0x7ff with a nonzero fraction
|
||||
* is a NaN, quiet bit 0x0008000000000000.
|
||||
*/
|
||||
static int
|
||||
fmax_nan_d(unsigned long long b)
|
||||
{
|
||||
return ((b >> 52) & 0x7ff) == 0x7ff && (b & 0xFFFFFFFFFFFFFULL) != 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fmax_snan_d(unsigned long long b)
|
||||
{
|
||||
return fmax_nan_d(b) && (b & 0x0008000000000000ULL) == 0;
|
||||
}
|
||||
|
||||
static double
|
||||
fmax_mm_d(double x, double y)
|
||||
{
|
||||
unsigned long long xb;
|
||||
unsigned long long yb;
|
||||
int xneg;
|
||||
int yneg;
|
||||
|
||||
__builtin_memcpy(&xb, &x, sizeof xb);
|
||||
__builtin_memcpy(&yb, &y, sizeof yb);
|
||||
|
||||
if (fmax_snan_d(xb))
|
||||
{
|
||||
xb |= 0x0008000000000000ULL;
|
||||
__builtin_memcpy(&x, &xb, sizeof xb);
|
||||
return x;
|
||||
}
|
||||
if (fmax_snan_d(yb))
|
||||
{
|
||||
yb |= 0x0008000000000000ULL;
|
||||
__builtin_memcpy(&y, &yb, sizeof yb);
|
||||
return y;
|
||||
}
|
||||
if (fmax_nan_d(xb))
|
||||
{
|
||||
return fmax_nan_d(yb) ? x : y;
|
||||
}
|
||||
if (fmax_nan_d(yb))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
if (x < y)
|
||||
{
|
||||
return y;
|
||||
}
|
||||
if (y < x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Equal, so possibly a +0/-0 pair: fmax prefers +0. */
|
||||
if (x == 0.0)
|
||||
{
|
||||
xneg = (int)(xb >> 63);
|
||||
yneg = (int)(yb >> 63);
|
||||
if (xneg != yneg)
|
||||
{
|
||||
return xneg ? y : x;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The float format: bit 31 the sign, bits 30..23 the exponent biased by
|
||||
* 127, bits 22..0 the fraction; quiet bit 0x00400000.
|
||||
*/
|
||||
static int
|
||||
fmax_nan_f(unsigned int b)
|
||||
{
|
||||
return ((b >> 23) & 0xff) == 0xff && (b & 0x7FFFFFU) != 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fmax_snan_f(unsigned int b)
|
||||
{
|
||||
return fmax_nan_f(b) && (b & 0x00400000U) == 0;
|
||||
}
|
||||
|
||||
static float
|
||||
fmax_mm_f(float x, float y)
|
||||
{
|
||||
unsigned int xb;
|
||||
unsigned int yb;
|
||||
int xneg;
|
||||
int yneg;
|
||||
|
||||
__builtin_memcpy(&xb, &x, sizeof xb);
|
||||
__builtin_memcpy(&yb, &y, sizeof yb);
|
||||
|
||||
if (fmax_snan_f(xb))
|
||||
{
|
||||
xb |= 0x00400000U;
|
||||
__builtin_memcpy(&x, &xb, sizeof xb);
|
||||
return x;
|
||||
}
|
||||
if (fmax_snan_f(yb))
|
||||
{
|
||||
yb |= 0x00400000U;
|
||||
__builtin_memcpy(&y, &yb, sizeof yb);
|
||||
return y;
|
||||
}
|
||||
if (fmax_nan_f(xb))
|
||||
{
|
||||
return fmax_nan_f(yb) ? x : y;
|
||||
}
|
||||
if (fmax_nan_f(yb))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
if (x < y)
|
||||
{
|
||||
return y;
|
||||
}
|
||||
if (y < x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (x == 0.0f)
|
||||
{
|
||||
xneg = (int)(xb >> 31);
|
||||
yneg = (int)(yb >> 31);
|
||||
if (xneg != yneg)
|
||||
{
|
||||
return xneg ? y : x;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The x86 80-bit extended format: 64-bit significand m (explicit integer
|
||||
* bit) in bytes 0..7, sign/exponent word se in bytes 8..9 with the sign in
|
||||
* bit 15 and the exponent biased by 16383 in bits 14..0. NaN has
|
||||
* (se & 0x7fff) == 0x7fff with a nonzero fraction; the quiet bit is bit 62
|
||||
* of m.
|
||||
*/
|
||||
struct fmax_ld_word
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
};
|
||||
|
||||
static int
|
||||
fmax_nan_l(struct fmax_ld_word p)
|
||||
{
|
||||
return (p.se & 0x7fff) == 0x7fff && (p.m & 0x7FFFFFFFFFFFFFFFULL) != 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fmax_snan_l(struct fmax_ld_word p)
|
||||
{
|
||||
return fmax_nan_l(p) && (p.m & (1ULL << 62)) == 0;
|
||||
}
|
||||
|
||||
static long double
|
||||
fmax_mm_l(long double x, long double y)
|
||||
{
|
||||
struct fmax_ld_word p;
|
||||
struct fmax_ld_word q;
|
||||
int xneg;
|
||||
int yneg;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
__builtin_memcpy(&q, &y, sizeof q);
|
||||
|
||||
if (fmax_snan_l(p))
|
||||
{
|
||||
p.m |= 1ULL << 62;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
if (fmax_snan_l(q))
|
||||
{
|
||||
q.m |= 1ULL << 62;
|
||||
__builtin_memcpy(&y, &q, sizeof q);
|
||||
return y;
|
||||
}
|
||||
if (fmax_nan_l(p))
|
||||
{
|
||||
return fmax_nan_l(q) ? x : y;
|
||||
}
|
||||
if (fmax_nan_l(q))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
if (x < y)
|
||||
{
|
||||
return y;
|
||||
}
|
||||
if (y < x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (x == 0.0L)
|
||||
{
|
||||
xneg = (int)(p.se >> 15);
|
||||
yneg = (int)(q.se >> 15);
|
||||
if (xneg != yneg)
|
||||
{
|
||||
return xneg ? y : x;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The larger of two floats.
|
||||
*/
|
||||
float
|
||||
fmaxf(float x, float y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return fmax_mm_f(x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
* The larger of two doubles.
|
||||
*/
|
||||
double
|
||||
fmax(double x, double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return fmax_mm_d(x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
* The larger of two long doubles.
|
||||
*/
|
||||
long double
|
||||
fmaxl(long double x, long double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return fmax_mm_l(x, y);
|
||||
}
|
||||
+267
@@ -0,0 +1,267 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* The smaller of x and y (C23 7.12.12.4), all three precisions.
|
||||
*
|
||||
* A quiet NaN argument is ignored in favor of the numeric one; a signaling
|
||||
* NaN argument makes the result a quiet NaN (the host glibc returns the
|
||||
* signaling argument quieted, payload preserved). When the arguments are
|
||||
* +0.0 and -0.0 the result is -0.0, and a pair of equal nonzero values
|
||||
* returns either. Numeric ordering is an ordinary comparison on the
|
||||
* already-NaN-screened operands, so no exception is raised and the chosen
|
||||
* operand is returned with its bits untouched. The NaN detection and the
|
||||
* quiet splice are done on the raw IEEE 754 word (the __builtin_isnan
|
||||
* classification would be equally exact but the word form also exposes the
|
||||
* signaling bit); no rounding mode and no arithmetic instruction is
|
||||
* involved, so the function is pure and fold-free at every level.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The double format: bit 63 is the sign, bits 62..52 the exponent biased
|
||||
* by 1023, bits 51..0 the fraction; exponent 0x7ff with a nonzero fraction
|
||||
* is a NaN, and the quiet bit is 0x0008000000000000 (bit 51).
|
||||
*/
|
||||
static int
|
||||
fmin_nan_d(unsigned long long b)
|
||||
{
|
||||
return ((b >> 52) & 0x7ff) == 0x7ff && (b & 0xFFFFFFFFFFFFFULL) != 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fmin_snan_d(unsigned long long b)
|
||||
{
|
||||
return fmin_nan_d(b) && (b & 0x0008000000000000ULL) == 0;
|
||||
}
|
||||
|
||||
static double
|
||||
fmin_mm_d(double x, double y, int want_max)
|
||||
{
|
||||
unsigned long long xb;
|
||||
unsigned long long yb;
|
||||
int xneg;
|
||||
int yneg;
|
||||
|
||||
__builtin_memcpy(&xb, &x, sizeof xb);
|
||||
__builtin_memcpy(&yb, &y, sizeof yb);
|
||||
|
||||
/* A signaling NaN in either argument wins, quieted with its payload. */
|
||||
if (fmin_snan_d(xb))
|
||||
{
|
||||
xb |= 0x0008000000000000ULL;
|
||||
__builtin_memcpy(&x, &xb, sizeof xb);
|
||||
return x;
|
||||
}
|
||||
if (fmin_snan_d(yb))
|
||||
{
|
||||
yb |= 0x0008000000000000ULL;
|
||||
__builtin_memcpy(&y, &yb, sizeof yb);
|
||||
return y;
|
||||
}
|
||||
|
||||
/* Quiet NaNs are ignored: the numeric argument (or x, for two) wins. */
|
||||
if (fmin_nan_d(xb))
|
||||
{
|
||||
return fmin_nan_d(yb) ? x : y;
|
||||
}
|
||||
if (fmin_nan_d(yb))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
if (x < y)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (y < x)
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
/* Equal, so possibly a +0/-0 pair: fmin prefers -0, fmax prefers +0. */
|
||||
if (x == 0.0)
|
||||
{
|
||||
xneg = (int)(xb >> 63);
|
||||
yneg = (int)(yb >> 63);
|
||||
if (xneg != yneg)
|
||||
{
|
||||
return want_max ? (xneg ? y : x) : (xneg ? x : y);
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The float format: bit 31 the sign, bits 30..23 the exponent biased by
|
||||
* 127, bits 22..0 the fraction; quiet bit 0x00400000 (bit 22).
|
||||
*/
|
||||
static int
|
||||
fmin_nan_f(unsigned int b)
|
||||
{
|
||||
return ((b >> 23) & 0xff) == 0xff && (b & 0x7FFFFFU) != 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fmin_snan_f(unsigned int b)
|
||||
{
|
||||
return fmin_nan_f(b) && (b & 0x00400000U) == 0;
|
||||
}
|
||||
|
||||
static float
|
||||
fmin_mm_f(float x, float y, int want_max)
|
||||
{
|
||||
unsigned int xb;
|
||||
unsigned int yb;
|
||||
int xneg;
|
||||
int yneg;
|
||||
|
||||
__builtin_memcpy(&xb, &x, sizeof xb);
|
||||
__builtin_memcpy(&yb, &y, sizeof yb);
|
||||
|
||||
if (fmin_snan_f(xb))
|
||||
{
|
||||
xb |= 0x00400000U;
|
||||
__builtin_memcpy(&x, &xb, sizeof xb);
|
||||
return x;
|
||||
}
|
||||
if (fmin_snan_f(yb))
|
||||
{
|
||||
yb |= 0x00400000U;
|
||||
__builtin_memcpy(&y, &yb, sizeof yb);
|
||||
return y;
|
||||
}
|
||||
if (fmin_nan_f(xb))
|
||||
{
|
||||
return fmin_nan_f(yb) ? x : y;
|
||||
}
|
||||
if (fmin_nan_f(yb))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
if (x < y)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (y < x)
|
||||
{
|
||||
return y;
|
||||
}
|
||||
if (x == 0.0f)
|
||||
{
|
||||
xneg = (int)(xb >> 31);
|
||||
yneg = (int)(yb >> 31);
|
||||
if (xneg != yneg)
|
||||
{
|
||||
return want_max ? (xneg ? y : x) : (xneg ? x : y);
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The x86 80-bit extended format: 64-bit significand m in bytes 0..7 (the
|
||||
* integer bit is explicit) and a sign/exponent word se in bytes 8..9, sign
|
||||
* in bit 15 and exponent biased by 16383 in bits 14..0. A NaN has
|
||||
* (se & 0x7fff) == 0x7fff with a nonzero fraction; the quiet bit is bit 62
|
||||
* of m.
|
||||
*/
|
||||
struct fmin_ld_word
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
};
|
||||
|
||||
static int
|
||||
fmin_nan_l(struct fmin_ld_word p)
|
||||
{
|
||||
return (p.se & 0x7fff) == 0x7fff && (p.m & 0x7FFFFFFFFFFFFFFFULL) != 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fmin_snan_l(struct fmin_ld_word p)
|
||||
{
|
||||
return fmin_nan_l(p) && (p.m & (1ULL << 62)) == 0;
|
||||
}
|
||||
|
||||
static long double
|
||||
fmin_mm_l(long double x, long double y, int want_max)
|
||||
{
|
||||
struct fmin_ld_word p;
|
||||
struct fmin_ld_word q;
|
||||
int xneg;
|
||||
int yneg;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
__builtin_memcpy(&q, &y, sizeof q);
|
||||
|
||||
if (fmin_snan_l(p))
|
||||
{
|
||||
p.m |= 1ULL << 62;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
if (fmin_snan_l(q))
|
||||
{
|
||||
q.m |= 1ULL << 62;
|
||||
__builtin_memcpy(&y, &q, sizeof q);
|
||||
return y;
|
||||
}
|
||||
if (fmin_nan_l(p))
|
||||
{
|
||||
return fmin_nan_l(q) ? x : y;
|
||||
}
|
||||
if (fmin_nan_l(q))
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
if (x < y)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (y < x)
|
||||
{
|
||||
return y;
|
||||
}
|
||||
if (x == 0.0L)
|
||||
{
|
||||
xneg = (int)(p.se >> 15);
|
||||
yneg = (int)(q.se >> 15);
|
||||
if (xneg != yneg)
|
||||
{
|
||||
return want_max ? (xneg ? y : x) : (xneg ? x : y);
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The smaller of two floats.
|
||||
*/
|
||||
float
|
||||
fminf(float x, float y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return fmin_mm_f(x, y, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The smaller of two doubles.
|
||||
*/
|
||||
double
|
||||
fmin(double x, double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return fmin_mm_d(x, y, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The smaller of two long doubles.
|
||||
*/
|
||||
long double
|
||||
fminl(long double x, long double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return fmin_mm_l(x, y, 0);
|
||||
}
|
||||
+423
@@ -0,0 +1,423 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The floating-point remainder x - n*y with n = x/y truncated toward zero
|
||||
* (C23 7.12.10.1), all three precisions. The remainder is always exact
|
||||
* and carries x's sign (a zero result is a signed zero with x's sign), so
|
||||
* every implementation must agree bit for bit; the result is computed with
|
||||
* a restoring long division on the significands, in the style of the musl
|
||||
* fmod family but derived here from first principles.
|
||||
*
|
||||
* Each operand is normalized into
|
||||
*
|
||||
* value = m * 2^(ex - W)
|
||||
*
|
||||
* where m is the significand with its msb pinned to bit P (P = 52/23/63
|
||||
* and W = 1075/150/16446 for double/float/80-bit) and ex is the exponent
|
||||
* in the same units as the biased field (so ex is the stored exponent for
|
||||
* normals and goes negative for subnormals). Aligned this way, one binary
|
||||
* long-division step per exponent difference decides whether a multiple of
|
||||
* the divisor fits: the current remainder significand is compared against
|
||||
* the divisor significand, the divisor is subtracted once when it fits,
|
||||
* and the remainder is doubled for the next, half-weight, digit. The
|
||||
* comparison invariant keeps the remainder below twice the divisor at
|
||||
* every step, so one subtraction per digit is always enough and every
|
||||
* subtraction (and the exact zero test) is a plain integer operation.
|
||||
*
|
||||
* Domain errors mirror the host glibc: fmod(+-0, +-0), fmod(+-Inf, y) and
|
||||
* any NaN argument return a NaN (the classic indefinite pattern, which is
|
||||
* what glibc's x87 path produces) and, in the library build only, set
|
||||
* errno to EDOM. fmod(x, +-Inf) is x for a finite x, and |x| <= |y| hands
|
||||
* x back unchanged, which keeps the signed-zero and exact cases exact.
|
||||
*/
|
||||
|
||||
/* The double format: bit 63 the sign, bits 62..52 the exponent biased by
|
||||
* 1023, bits 51..0 the fraction. Value = m * 2^(ex - 1075) with the msb
|
||||
* of m at bit 52. */
|
||||
static double
|
||||
fmod_d(double x, double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
unsigned long long xb;
|
||||
unsigned long long yb;
|
||||
unsigned long long sx;
|
||||
unsigned long long mx;
|
||||
unsigned long long my;
|
||||
unsigned long long s;
|
||||
unsigned long long i;
|
||||
int ex;
|
||||
int ey;
|
||||
|
||||
__builtin_memcpy(&xb, &x, sizeof xb);
|
||||
__builtin_memcpy(&yb, &y, sizeof yb);
|
||||
sx = xb & (1ULL << 63);
|
||||
ex = (int)((xb >> 52) & 0x7ff);
|
||||
ey = (int)((yb >> 52) & 0x7ff);
|
||||
|
||||
/* x not finite, y zero, or y a NaN: domain error. */
|
||||
if (ex == 0x7ff || (yb << 1) == 0 || (ey == 0x7ff && (yb & 0xFFFFFFFFFFFFFULL) != 0))
|
||||
{
|
||||
#ifdef HAVE_CONFIG_H
|
||||
errno = EDOM;
|
||||
#endif
|
||||
return __builtin_nan(""); /* indefinite NaN, sign negative */
|
||||
}
|
||||
/* x zero or a finite x below an infinite y: x unchanged. (x a NaN or
|
||||
* +-Inf fell into the domain branch above, which returns a NaN for
|
||||
* both.) */
|
||||
if ((xb << 1) == 0 || ey == 0x7ff)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Compare magnitudes directly on the (biased exponent, fraction)
|
||||
* words: finite IEEE magnitudes order lexicographically, so a plain
|
||||
* integer compare of the sign-stripped words decides |x| vs |y|. */
|
||||
if ((xb & 0x7FFFFFFFFFFFFFFFULL) <= (yb & 0x7FFFFFFFFFFFFFFFULL))
|
||||
{
|
||||
if ((xb & 0x7FFFFFFFFFFFFFFFULL) == (yb & 0x7FFFFFFFFFFFFFFFULL))
|
||||
{
|
||||
return x * 0.0; /* exact: result is +-0 with x's sign */
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Normalize x: subnormals (ex == 0) get their msb shifted up to bit
|
||||
* 52 and ex counts the shift below the smallest normal. */
|
||||
mx = xb & 0xFFFFFFFFFFFFFULL;
|
||||
if (ex == 0)
|
||||
{
|
||||
s = 63 - (unsigned long long)__builtin_clzll(mx);
|
||||
mx <<= (52 - s);
|
||||
ex = (int)s - 51;
|
||||
}
|
||||
else
|
||||
{
|
||||
mx |= 1ULL << 52;
|
||||
}
|
||||
my = yb & 0xFFFFFFFFFFFFFULL;
|
||||
if (ey == 0)
|
||||
{
|
||||
s = 63 - (unsigned long long)__builtin_clzll(my);
|
||||
my <<= (52 - s);
|
||||
ey = (int)s - 51;
|
||||
}
|
||||
else
|
||||
{
|
||||
my |= 1ULL << 52;
|
||||
}
|
||||
|
||||
/* Long division: subtract the aligned divisor significand once per
|
||||
* bit of quotient, doubling the remainder between bits. */
|
||||
for (; ex > ey; ex--)
|
||||
{
|
||||
if (mx >= my)
|
||||
{
|
||||
i = mx - my;
|
||||
if (i == 0)
|
||||
{
|
||||
return x * 0.0;
|
||||
}
|
||||
mx = i;
|
||||
}
|
||||
mx <<= 1;
|
||||
}
|
||||
i = mx - my;
|
||||
if (mx >= my)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
return x * 0.0;
|
||||
}
|
||||
mx = i;
|
||||
}
|
||||
|
||||
/* Bring the msb of the remainder back to bit 52. */
|
||||
for (; (mx >> 52) == 0; mx <<= 1, ex--)
|
||||
{
|
||||
}
|
||||
|
||||
if (ex > 0)
|
||||
{
|
||||
xb = sx | ((unsigned long long)ex << 52) | (mx - (1ULL << 52));
|
||||
}
|
||||
else
|
||||
{
|
||||
xb = sx | (mx >> (1 - ex));
|
||||
}
|
||||
__builtin_memcpy(&x, &xb, sizeof xb);
|
||||
return x;
|
||||
}
|
||||
|
||||
/* The float format: bit 31 the sign, bits 30..23 the exponent biased by
|
||||
* 127, bits 22..0 the fraction. Value = m * 2^(ex - 150) with the msb of
|
||||
* m at bit 23. */
|
||||
static float
|
||||
fmod_f(float x, float y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
unsigned int xb;
|
||||
unsigned int yb;
|
||||
unsigned int sx;
|
||||
unsigned int mx;
|
||||
unsigned int my;
|
||||
unsigned int s;
|
||||
unsigned int i;
|
||||
int ex;
|
||||
int ey;
|
||||
|
||||
__builtin_memcpy(&xb, &x, sizeof xb);
|
||||
__builtin_memcpy(&yb, &y, sizeof yb);
|
||||
sx = xb & (1U << 31);
|
||||
ex = (int)((xb >> 23) & 0xff);
|
||||
ey = (int)((yb >> 23) & 0xff);
|
||||
|
||||
if (ex == 0xff || (yb << 1) == 0 || (ey == 0xff && (yb & 0x7FFFFFU) != 0))
|
||||
{
|
||||
#ifdef HAVE_CONFIG_H
|
||||
errno = EDOM;
|
||||
#endif
|
||||
return __builtin_nanf("");
|
||||
}
|
||||
if ((xb << 1) == 0 || ey == 0xff)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
if ((xb & 0x7FFFFFFFU) <= (yb & 0x7FFFFFFFU))
|
||||
{
|
||||
if ((xb & 0x7FFFFFFFU) == (yb & 0x7FFFFFFFU))
|
||||
{
|
||||
return x * 0.0f;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
mx = xb & 0x7FFFFFU;
|
||||
if (ex == 0)
|
||||
{
|
||||
s = 31 - (unsigned int)__builtin_clz(mx);
|
||||
mx <<= (23 - s);
|
||||
ex = (int)s - 22;
|
||||
}
|
||||
else
|
||||
{
|
||||
mx |= 1U << 23;
|
||||
}
|
||||
my = yb & 0x7FFFFFU;
|
||||
if (ey == 0)
|
||||
{
|
||||
s = 31 - (unsigned int)__builtin_clz(my);
|
||||
my <<= (23 - s);
|
||||
ey = (int)s - 22;
|
||||
}
|
||||
else
|
||||
{
|
||||
my |= 1U << 23;
|
||||
}
|
||||
|
||||
for (; ex > ey; ex--)
|
||||
{
|
||||
if (mx >= my)
|
||||
{
|
||||
i = mx - my;
|
||||
if (i == 0)
|
||||
{
|
||||
return x * 0.0f;
|
||||
}
|
||||
mx = i;
|
||||
}
|
||||
mx <<= 1;
|
||||
}
|
||||
i = mx - my;
|
||||
if (mx >= my)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
return x * 0.0f;
|
||||
}
|
||||
mx = i;
|
||||
}
|
||||
|
||||
for (; (mx >> 23) == 0; mx <<= 1, ex--)
|
||||
{
|
||||
}
|
||||
|
||||
if (ex > 0)
|
||||
{
|
||||
xb = sx | ((unsigned int)ex << 23) | (mx - (1U << 23));
|
||||
}
|
||||
else
|
||||
{
|
||||
xb = sx | (mx >> (1 - ex));
|
||||
}
|
||||
__builtin_memcpy(&x, &xb, sizeof xb);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The x86 80-bit extended format: 64-bit significand m with an explicit
|
||||
* integer bit in bytes 0..7, sign/exponent word se in bytes 8..9. Value =
|
||||
* m * 2^(ex - 16446) with the msb of m at bit 63; a canonical normal has
|
||||
* ex = se & 0x7fff, and a subnormal (se field 0) or a defensive unnormal
|
||||
* (nonzero field with m < 2^63) is normalized by shifting m's msb up to
|
||||
* bit 63. The division reuses the same digit loop as the narrower
|
||||
* formats; only the doubling step differs, because a full-width
|
||||
* significand has no free bit above its msb (see the three-way branch in
|
||||
* the loop below).
|
||||
*/
|
||||
struct fmod_ld_word
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
};
|
||||
|
||||
static long double
|
||||
fmod_l(long double x, long double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
struct fmod_ld_word p;
|
||||
struct fmod_ld_word q;
|
||||
unsigned long long s;
|
||||
unsigned long long mx;
|
||||
unsigned long long my;
|
||||
unsigned long long i;
|
||||
int ex;
|
||||
int ey;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
__builtin_memcpy(&q, &y, sizeof q);
|
||||
ex = p.se & 0x7fff;
|
||||
ey = q.se & 0x7fff;
|
||||
|
||||
/* x not finite, y zero, or y a NaN: domain error. */
|
||||
if (ex == 0x7fff || (q.m == 0 && ey == 0) ||
|
||||
(ey == 0x7fff && (q.m & 0x7FFFFFFFFFFFFFFFULL) != 0))
|
||||
{
|
||||
#ifdef HAVE_CONFIG_H
|
||||
errno = EDOM;
|
||||
#endif
|
||||
p.m = 0xC000000000000000ULL;
|
||||
p.se = 0xFFFF;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
/* x zero or a finite x below an infinite y: x unchanged. (x a NaN or
|
||||
* +-Inf fell into the domain branch above.) */
|
||||
if ((p.m == 0 && ex == 0) || ey == 0x7fff)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Normalize both significands to the [2^63, 2^64) frame; a subnormal
|
||||
* (field 0) or defensive unnormal (field nonzero, msb below 63) has
|
||||
* its msb shifted up to bit 63 with the exponent adjusted, so every
|
||||
* value below obeys value = m * 2^(ex - 16446). */
|
||||
if (p.m < 0x8000000000000000ULL)
|
||||
{
|
||||
s = 63 - (unsigned long long)__builtin_clzll(p.m);
|
||||
p.m <<= (63 - s);
|
||||
ex = (ex == 0 ? 1 : ex) + (int)s - 63;
|
||||
}
|
||||
if (q.m < 0x8000000000000000ULL)
|
||||
{
|
||||
s = 63 - (unsigned long long)__builtin_clzll(q.m);
|
||||
q.m <<= (63 - s);
|
||||
ey = (ey == 0 ? 1 : ey) + (int)s - 63;
|
||||
}
|
||||
mx = p.m;
|
||||
my = q.m;
|
||||
|
||||
if (ex < ey || (ex == ey && mx <= my))
|
||||
{
|
||||
if (ex == ey && mx == my)
|
||||
{
|
||||
return x * 0.0L;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Long division with a full-width significand: a 64-bit divisor
|
||||
* leaves no headroom above its own msb for the per-bit doubling, so
|
||||
* the doubled remainder that overflows is exactly one divisor at the
|
||||
* next, half, weight and is absorbed by a subtraction there. */
|
||||
for (; ex > ey; ex--)
|
||||
{
|
||||
i = mx - my;
|
||||
if (mx >= my)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
return x * 0.0L;
|
||||
}
|
||||
mx = 2 * i;
|
||||
}
|
||||
else if (2 * mx < mx)
|
||||
{
|
||||
mx = 2 * mx - my;
|
||||
}
|
||||
else
|
||||
{
|
||||
mx = 2 * mx;
|
||||
}
|
||||
}
|
||||
i = mx - my;
|
||||
if (mx >= my)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
return x * 0.0L;
|
||||
}
|
||||
mx = i;
|
||||
}
|
||||
|
||||
/* Bring the msb of the remainder back to bit 63. */
|
||||
for (; mx < 0x8000000000000000ULL; mx <<= 1, ex--)
|
||||
{
|
||||
}
|
||||
|
||||
if (ex > 0)
|
||||
{
|
||||
p.se = (unsigned short)((p.se & 0x8000) | (unsigned short)ex);
|
||||
p.m = mx;
|
||||
}
|
||||
else
|
||||
{
|
||||
p.se = (unsigned short)(p.se & 0x8000);
|
||||
p.m = mx >> (1 - ex);
|
||||
}
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The float remainder, as fmod_d.
|
||||
*/
|
||||
float
|
||||
fmodf(float x, float y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return fmod_f(x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
* The double remainder, as fmod_d.
|
||||
*/
|
||||
double
|
||||
fmod(double x, double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return fmod_d(x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
* The long double remainder, as fmod_d.
|
||||
*/
|
||||
long double
|
||||
fmodl(long double x, long double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return fmod_l(x, y);
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* Split x into a fraction f in [1/2, 1) (or 0) and an integer exponent
|
||||
* *exp with x == f * 2^(*exp), all three precisions (C23 7.12.6.4).
|
||||
* frexp(±0) returns x with *exp 0; frexp(±Inf) and frexp(NaN) return x
|
||||
* with *exp 0 (the glibc behavior the tests pin down; the C standard
|
||||
* leaves the Inf/NaN exponent unspecified). The fraction keeps x's sign,
|
||||
* so frexp(-6.0) is -0.75 with *exp 3 and frexp(0x1p-1074) is 0.5 with
|
||||
* *exp -1073.
|
||||
*
|
||||
* Each precision works from the same unified view used across the
|
||||
* src/math/ slices (see math_impl.h): a finite value is m * 2^p with m the
|
||||
* integer significand carrying the explicit integer bit. The fraction is
|
||||
* m * 2^-w (w = 53/24/64 significand bits), which sits in [1/2, 1), so
|
||||
* *exp is p + w and the result keeps the significand's low bits — for a
|
||||
* normal input the fraction field is simply unchanged and only the
|
||||
* exponent field is rewritten.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The double format: bit 63 the sign, bits 62..52 the exponent biased by
|
||||
* 1023, bits 51..0 the fraction, 53-bit significand. A normal input has
|
||||
* p = ef - 1075, so *exp = ef - 1022 and the fraction field is the input's
|
||||
* own 52-bit fraction (the implicit bit stays put as the leading 1 of the
|
||||
* fraction's [1/2, 1) significand). A subnormal input with fraction msb
|
||||
* at position s (0..51) is value frac * 2^-1074; shifting frac up to the
|
||||
* implicit-bit position makes m = frac << (52 - s), hence *exp = s - 1073
|
||||
* and fraction field m - 2^52.
|
||||
*/
|
||||
double
|
||||
frexp(double x, int *exp)
|
||||
{
|
||||
unsigned long long bits;
|
||||
unsigned long long sign;
|
||||
unsigned long long ef;
|
||||
unsigned long long frac;
|
||||
unsigned long long m;
|
||||
int s;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
sign = bits & (1ULL << 63);
|
||||
ef = (bits >> 52) & 0x7ff;
|
||||
frac = bits & 0xFFFFFFFFFFFFFULL;
|
||||
|
||||
if (ef == 0x7ff)
|
||||
{
|
||||
*exp = 0;
|
||||
return x; /* ±Inf and NaN */
|
||||
}
|
||||
if (ef == 0)
|
||||
{
|
||||
if (frac == 0)
|
||||
{
|
||||
*exp = 0;
|
||||
return x; /* ±0 */
|
||||
}
|
||||
s = 63 - __builtin_clzll(frac);
|
||||
m = frac << (52 - s);
|
||||
*exp = s - 1073;
|
||||
bits = sign | (0x3feULL << 52) | (m - (1ULL << 52));
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
*exp = (int)ef - 1022;
|
||||
bits = sign | (0x3feULL << 52) | frac;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The float format: bit 31 the sign, bits 30..23 the exponent biased by
|
||||
* 127, bits 22..0 the fraction, 24-bit significand. Normal *exp =
|
||||
* ef - 126; a subnormal input with fraction msb at s (0..22) normalizes to
|
||||
* m = frac << (23 - s) and has *exp = s - 148.
|
||||
*/
|
||||
float
|
||||
frexpf(float x, int *exp)
|
||||
{
|
||||
unsigned int bits;
|
||||
unsigned int sign;
|
||||
unsigned int ef;
|
||||
unsigned int frac;
|
||||
unsigned int m;
|
||||
int s;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
sign = bits & (1U << 31);
|
||||
ef = (bits >> 23) & 0xff;
|
||||
frac = bits & 0x7FFFFFU;
|
||||
|
||||
if (ef == 0xff)
|
||||
{
|
||||
*exp = 0;
|
||||
return x;
|
||||
}
|
||||
if (ef == 0)
|
||||
{
|
||||
if (frac == 0)
|
||||
{
|
||||
*exp = 0;
|
||||
return x;
|
||||
}
|
||||
s = 31 - __builtin_clz(frac);
|
||||
m = frac << (23 - s);
|
||||
*exp = s - 148;
|
||||
bits = sign | (0x7eU << 23) | (m - (1U << 23));
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
*exp = (int)ef - 126;
|
||||
bits = sign | (0x7eU << 23) | frac;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The x86 80-bit extended format: 64 significand bits m with an explicit
|
||||
* integer bit, plus a sign/exponent word se biased by 16383. A canonical
|
||||
* normal has m in [2^63, 2^64) and p = ef - 16446, so *exp = ef - 16382
|
||||
* and the fraction is m * 2^-64 with se rewritten to 16382. A subnormal
|
||||
* (ef == 0) is value m * 2^-16445; shifting m's msb (position s, 0..62)
|
||||
* up to bit 63 gives *exp = s - 16444. Unnormal inputs (ef > 0 with
|
||||
* m < 2^63) normalize the same way with *exp = ef + s - 16445.
|
||||
*/
|
||||
long double
|
||||
frexpl(long double x, int *exp)
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
} p;
|
||||
unsigned long long m;
|
||||
int ef;
|
||||
int s;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
m = p.m;
|
||||
ef = p.se & 0x7fff;
|
||||
|
||||
if (ef == 0x7fff)
|
||||
{
|
||||
*exp = 0;
|
||||
return x;
|
||||
}
|
||||
if (m == 0)
|
||||
{
|
||||
*exp = 0;
|
||||
return x; /* ±0 and empty degenerate encodings */
|
||||
}
|
||||
if (m < 0x8000000000000000ULL)
|
||||
{
|
||||
s = 63 - __builtin_clzll(m);
|
||||
m <<= (63 - s);
|
||||
*exp = (ef == 0 ? 1 : ef) + s - 16445;
|
||||
p.se = (unsigned short)((p.se & 0x8000) | 0x3ffe);
|
||||
p.m = m;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
|
||||
*exp = ef - 16382;
|
||||
p.se = (unsigned short)((p.se & 0x8000) | 0x3ffe);
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* The signed exponent of x as an int (C23 7.12.6.5p1), all three
|
||||
* precisions: ilogb(x) is floor(log2 |x|) for a nonzero finite x. The
|
||||
* sentinel returns are FP_ILOGB0 (INT_MIN) for ±0 and FP_ILOGBNAN
|
||||
* (INT_MAX) for ±Inf and NaN, without touching errno, so the functions
|
||||
* carry the const attribute and never trap. Subnormal arguments are
|
||||
* normalized by scanning the fraction for its highest set bit.
|
||||
*
|
||||
* ilogb(1.0) == 0, ilogb(8.0) == 3, ilogb(0.5) == -1, and the smallest
|
||||
* subnormal double, 2^-1074, yields -1074.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The double format: bits 62..52 hold the exponent biased by 1023 and
|
||||
* bits 51..0 the fraction; a subnormal with fraction F (no implicit
|
||||
* bit) is F * 2^-1074, so its exponent is the fraction's highest set
|
||||
* bit position minus 1074.
|
||||
*/
|
||||
int
|
||||
ilogb(double x)
|
||||
{
|
||||
unsigned long long bits;
|
||||
unsigned long long frac;
|
||||
int e;
|
||||
int msb;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
frac = bits & 0xFFFFFFFFFFFFFULL;
|
||||
e = (int)((bits >> 52) & 0x7ff);
|
||||
|
||||
if (e == 0x7ff)
|
||||
{
|
||||
/* ±Inf and NaN both map to FP_ILOGBNAN. */
|
||||
return FP_ILOGBNAN;
|
||||
}
|
||||
if (e == 0)
|
||||
{
|
||||
if (frac == 0)
|
||||
{
|
||||
return FP_ILOGB0;
|
||||
}
|
||||
msb = 63 - __builtin_clzll(frac);
|
||||
return msb - 1074;
|
||||
}
|
||||
return e - 1023;
|
||||
}
|
||||
|
||||
/*
|
||||
* The float format: bits 30..23 hold the exponent biased by 127 and
|
||||
* bits 22..0 the fraction; a subnormal with fraction F is F * 2^-149.
|
||||
*/
|
||||
int
|
||||
ilogbf(float x)
|
||||
{
|
||||
unsigned int bits;
|
||||
unsigned int frac;
|
||||
int e;
|
||||
int msb;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
frac = bits & 0x7FFFFFU;
|
||||
e = (int)((bits >> 23) & 0xff);
|
||||
|
||||
if (e == 0xff)
|
||||
{
|
||||
return FP_ILOGBNAN;
|
||||
}
|
||||
if (e == 0)
|
||||
{
|
||||
if (frac == 0)
|
||||
{
|
||||
return FP_ILOGB0;
|
||||
}
|
||||
msb = 31 - __builtin_clz(frac);
|
||||
return msb - 149;
|
||||
}
|
||||
return e - 127;
|
||||
}
|
||||
|
||||
/*
|
||||
* The x86 80-bit extended format: 64 significand bits m (explicit
|
||||
* integer bit) with a sign/exponent word se biased by 16383. A normal m
|
||||
* in [2^63, 2^64) sits in [2^(e-16383), 2^(e-16382)). A subnormal with
|
||||
* e == 0 is interpreted as if e were 1, i.e. m * 2^-16445; an unnormal
|
||||
* (e > 0 with m < 2^63) is m * 2^(e - 16446).
|
||||
*/
|
||||
int
|
||||
ilogbl(long double x)
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
} p;
|
||||
int e;
|
||||
int msb;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
e = p.se & 0x7fff;
|
||||
|
||||
if (e == 0x7fff)
|
||||
{
|
||||
return FP_ILOGBNAN;
|
||||
}
|
||||
if (p.m == 0)
|
||||
{
|
||||
return FP_ILOGB0;
|
||||
}
|
||||
if (e == 0)
|
||||
{
|
||||
msb = 63 - __builtin_clzll(p.m);
|
||||
return msb - 16445;
|
||||
}
|
||||
if (p.m < 0x8000000000000000ULL)
|
||||
{
|
||||
msb = 63 - __builtin_clzll(p.m);
|
||||
return msb + e - 16446;
|
||||
}
|
||||
return e - 16383;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "math_impl.h"
|
||||
|
||||
/*
|
||||
* x times 2^n (C23 7.12.6.3), all three precisions: the inverse of frexp.
|
||||
* Scaling a finite value by a power of two is exact whenever the result is
|
||||
* a normal number; only a result that lands in the subnormal range can
|
||||
* need rounding (the vl_rne_u64 round-to-nearest-even shift in the shared
|
||||
* scale cores, see math_impl.h). Overflow returns +-Inf and, in the
|
||||
* library build, sets errno to ERANGE as POSIX requires.
|
||||
*
|
||||
* The errno write is a TCB dereference that only exists when this file is
|
||||
* compiled as part of the real library (config.h present). The host-
|
||||
* linked standalone test binaries compile these sources without
|
||||
* HAVE_CONFIG_H, so they never reference __errno_location and never touch
|
||||
* the host's errno thread slot; the tests therefore check values only.
|
||||
* ldexp(±0) is ±0 for any n, and ±Inf/NaN pass through unchanged.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Scale a double: the shared core reports overflow through the flag and
|
||||
* this wrapper raises ERANGE when the library build demands it.
|
||||
*/
|
||||
double
|
||||
ldexp(double x, int n)
|
||||
{
|
||||
int overflowed = 0;
|
||||
double r = vl_scale2_d(x, n, &overflowed);
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
if (overflowed)
|
||||
{
|
||||
errno = ERANGE;
|
||||
}
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
float
|
||||
ldexpf(float x, int n)
|
||||
{
|
||||
int overflowed = 0;
|
||||
float r = vl_scale2_f(x, n, &overflowed);
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
if (overflowed)
|
||||
{
|
||||
errno = ERANGE;
|
||||
}
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
long double
|
||||
ldexpl(long double x, int n)
|
||||
{
|
||||
int overflowed = 0;
|
||||
long double r = vl_scale2_ld(x, n, &overflowed);
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
if (overflowed)
|
||||
{
|
||||
errno = ERANGE;
|
||||
}
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* The nearest integral value to x in the current rounding direction,
|
||||
* returned as long long (C23 7.12.9.8), all three precisions. A result
|
||||
* outside the range of long long is a range error whose return value is
|
||||
* unspecified, so the header declares no const attribute; the test
|
||||
* corpus keeps |x| < 2^62 where every result is exact.
|
||||
*
|
||||
* As for lrint (see lrint.c): the __builtin_llrint* forms are never
|
||||
* folded on this target, so llrint is built as rint-then-convert, with
|
||||
* __builtin_rint* folding to the in-line round-to-nearest-even sequence
|
||||
* and the cast to long long being exact on the integral result.
|
||||
*/
|
||||
|
||||
/*
|
||||
* As llrint, for a float argument.
|
||||
*/
|
||||
long long
|
||||
llrintf(float x)
|
||||
{
|
||||
return (long long)__builtin_rintf(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As llrint, for a double argument.
|
||||
*/
|
||||
long long
|
||||
llrint(double x)
|
||||
{
|
||||
return (long long)__builtin_rint(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As llrint, for a long double argument.
|
||||
*/
|
||||
long long
|
||||
llrintl(long double x)
|
||||
{
|
||||
return (long long)__builtin_rintl(x);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* The nearest integral value to x, halfway cases rounded away from zero,
|
||||
* returned as long long (C23 7.12.9.10), all three precisions.
|
||||
*
|
||||
* Rounding is delegated to the round/roundf/roundl implementations (see
|
||||
* round.c): on this target every __builtin_round* is an external call even
|
||||
* at -O2 -- no SSE4.1 in the default -march -- so round() here reaches the
|
||||
* library's own half-away-from-zero rounding, returning an exactly
|
||||
* integral value of the same floating type. Narrowing that value to long
|
||||
* long is then a plain, exact conversion whenever it is in range.
|
||||
*
|
||||
* The unrepresentable cases mirror the host glibc on x86-64, whose lround
|
||||
* family is the hardware cvttsd2si sequence: a NaN, an Inf, and any finite
|
||||
* result of magnitude >= 2^63 (the smallest such rounded value is exactly
|
||||
* 2^63) all collapse to LLONG_MIN with errno untouched -- measured against
|
||||
* glibc 2.44, which returns LLONG_MIN for 1e300, -1e300, +-Inf and NaN and
|
||||
* never sets errno. The range checks happen in the argument's own
|
||||
* precision (0x1p63 is exact in float, double and the x87 extended
|
||||
* format), and -2^63 -- exactly representable and equal to LLONG_MIN -- is
|
||||
* deliberately allowed through the strict lower-bound test.
|
||||
*/
|
||||
|
||||
/*
|
||||
* As llround, for a float argument.
|
||||
*/
|
||||
long long
|
||||
llroundf(float x)
|
||||
{
|
||||
float r = roundf(x);
|
||||
|
||||
if (isnan(r) || r >= 0x1p63f || r < -0x1p63f)
|
||||
{
|
||||
return LLONG_MIN;
|
||||
}
|
||||
return (long long)r;
|
||||
}
|
||||
|
||||
/*
|
||||
* As llround, for a double argument.
|
||||
*/
|
||||
long long
|
||||
llround(double x)
|
||||
{
|
||||
double r = round(x);
|
||||
|
||||
if (isnan(r) || r >= 0x1p63 || r < -0x1p63)
|
||||
{
|
||||
return LLONG_MIN;
|
||||
}
|
||||
return (long long)r;
|
||||
}
|
||||
|
||||
/*
|
||||
* As llround, for a long double argument.
|
||||
*/
|
||||
long long
|
||||
llroundl(long double x)
|
||||
{
|
||||
long double r = roundl(x);
|
||||
|
||||
if (isnan(r) || r >= 0x1p63L || r < -0x1p63L)
|
||||
{
|
||||
return LLONG_MIN;
|
||||
}
|
||||
return (long long)r;
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* The signed exponent of x as a floating-point value (C23 7.12.6.6),
|
||||
* all three precisions: logb(x) is floor(log2 |x|) as a float/double/
|
||||
* long double. logb(±0) is -Inf and logb(±Inf) is +Inf, each raising
|
||||
* the division-by-zero/invalid exception through the hardware but
|
||||
* without an errno path in the representable domain; logb(NaN) returns
|
||||
* the NaN. Pure, so the header marks the functions const; the exponent
|
||||
* extraction is exactly the ilogb one (see ilogb.c) with the int result
|
||||
* converted back to the argument's precision.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The double format: bits 62..52 hold the exponent biased by 1023 and
|
||||
* bits 51..0 the fraction. A subnormal with fraction F is F * 2^-1074.
|
||||
*/
|
||||
double
|
||||
logb(double x)
|
||||
{
|
||||
unsigned long long bits;
|
||||
unsigned long long frac;
|
||||
int e;
|
||||
int msb;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
frac = bits & 0xFFFFFFFFFFFFFULL;
|
||||
e = (int)((bits >> 52) & 0x7ff);
|
||||
|
||||
if (e == 0x7ff)
|
||||
{
|
||||
/* Inf maps to +Inf (both signs); NaN passes through. */
|
||||
return frac == 0 ? HUGE_VAL : x;
|
||||
}
|
||||
if (e == 0)
|
||||
{
|
||||
if (frac == 0)
|
||||
{
|
||||
return -HUGE_VAL;
|
||||
}
|
||||
msb = 63 - __builtin_clzll(frac);
|
||||
return (double)(msb - 1074);
|
||||
}
|
||||
return (double)(e - 1023);
|
||||
}
|
||||
|
||||
/*
|
||||
* The float format: bits 30..23 hold the exponent biased by 127 and
|
||||
* bits 22..0 the fraction; a subnormal with fraction F is F * 2^-149.
|
||||
*/
|
||||
float
|
||||
logbf(float x)
|
||||
{
|
||||
unsigned int bits;
|
||||
unsigned int frac;
|
||||
int e;
|
||||
int msb;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
frac = bits & 0x7FFFFFU;
|
||||
e = (int)((bits >> 23) & 0xff);
|
||||
|
||||
if (e == 0xff)
|
||||
{
|
||||
return frac == 0 ? HUGE_VALF : x;
|
||||
}
|
||||
if (e == 0)
|
||||
{
|
||||
if (frac == 0)
|
||||
{
|
||||
return -HUGE_VALF;
|
||||
}
|
||||
msb = 31 - __builtin_clz(frac);
|
||||
return (float)(msb - 149);
|
||||
}
|
||||
return (float)(e - 127);
|
||||
}
|
||||
|
||||
/*
|
||||
* The x86 80-bit extended format: 64 significand bits m (explicit
|
||||
* integer bit) with a sign/exponent word se biased by 16383. A normal m
|
||||
* in [2^63, 2^64) sits in [2^(e-16383), 2^(e-16382)). A subnormal with
|
||||
* e == 0 is interpreted as if e were 1, i.e. m * 2^-16445; an unnormal
|
||||
* (e > 0 with m < 2^63) is m * 2^(e - 16446).
|
||||
*/
|
||||
long double
|
||||
logbl(long double x)
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
} p;
|
||||
int e;
|
||||
int msb;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
e = p.se & 0x7fff;
|
||||
|
||||
if (e == 0x7fff)
|
||||
{
|
||||
return (p.m & 0x7FFFFFFFFFFFFFFFULL) == 0 ? HUGE_VALL : x;
|
||||
}
|
||||
if (p.m == 0)
|
||||
{
|
||||
return -HUGE_VALL;
|
||||
}
|
||||
if (e == 0)
|
||||
{
|
||||
msb = 63 - __builtin_clzll(p.m);
|
||||
return (long double)(msb - 16445);
|
||||
}
|
||||
if (p.m < 0x8000000000000000ULL)
|
||||
{
|
||||
msb = 63 - __builtin_clzll(p.m);
|
||||
return (long double)(msb + e - 16446);
|
||||
}
|
||||
return (long double)(e - 16383);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* The nearest integral value to x in the current rounding direction,
|
||||
* returned as long (C23 7.12.9.7), all three precisions. A result
|
||||
* outside the range of long is a range error whose return value is
|
||||
* unspecified, so the header declares no const attribute; the test
|
||||
* corpus keeps |x| < 2^62 where every result is exact.
|
||||
*
|
||||
* GCC never folds the __builtin_lrint* forms on this target (external
|
||||
* lrint@PLT calls at every optimization level), so lrint is built as
|
||||
* rint-then-convert: __builtin_rint* folds to the in-line round-to-
|
||||
* nearest-even sequence (see rint.c), producing an exact integral value,
|
||||
* and the cast to long is then exact no matter which conversion
|
||||
* instruction GCC emits. The rint step honors the MXCSR/x87 rounding
|
||||
* mode, the only reachable one being the default round-to-nearest-even
|
||||
* (no <fenv.h> exists in vlibc yet).
|
||||
*/
|
||||
|
||||
/*
|
||||
* As lrint, for a float argument.
|
||||
*/
|
||||
long
|
||||
lrintf(float x)
|
||||
{
|
||||
return (long)__builtin_rintf(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As lrint, for a double argument.
|
||||
*/
|
||||
long
|
||||
lrint(double x)
|
||||
{
|
||||
return (long)__builtin_rint(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As lrint, for a long double argument.
|
||||
*/
|
||||
long
|
||||
lrintl(long double x)
|
||||
{
|
||||
return (long)__builtin_rintl(x);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* The nearest integral value to x, halfway cases rounded away from zero,
|
||||
* returned as long (C23 7.12.9.9), all three precisions.
|
||||
*
|
||||
* On this LP64 target long is 64 bits wide, so lround is llround in every
|
||||
* observable way: the value is rounded half away from zero by round.c and
|
||||
* narrowed, and a NaN, an Inf, or any rounded magnitude >= 2^63 collapses
|
||||
* to LONG_MIN, exactly what the host glibc's hardware-conversion lround
|
||||
* returns for such arguments (measured on glibc 2.44; errno untouched).
|
||||
* The reasoning, the range test shape and the -2^63 == LONG_MIN boundary
|
||||
* subtlety are those documented in llround.c.
|
||||
*/
|
||||
|
||||
/*
|
||||
* As lround, for a float argument.
|
||||
*/
|
||||
long
|
||||
lroundf(float x)
|
||||
{
|
||||
float r = roundf(x);
|
||||
|
||||
if (isnan(r) || r >= 0x1p63f || r < -0x1p63f)
|
||||
{
|
||||
return LONG_MIN;
|
||||
}
|
||||
return (long)r;
|
||||
}
|
||||
|
||||
/*
|
||||
* As lround, for a double argument.
|
||||
*/
|
||||
long
|
||||
lround(double x)
|
||||
{
|
||||
double r = round(x);
|
||||
|
||||
if (isnan(r) || r >= 0x1p63 || r < -0x1p63)
|
||||
{
|
||||
return LONG_MIN;
|
||||
}
|
||||
return (long)r;
|
||||
}
|
||||
|
||||
/*
|
||||
* As lround, for a long double argument.
|
||||
*/
|
||||
long
|
||||
lroundl(long double x)
|
||||
{
|
||||
long double r = roundl(x);
|
||||
|
||||
if (isnan(r) || r >= 0x1p63L || r < -0x1p63L)
|
||||
{
|
||||
return LONG_MIN;
|
||||
}
|
||||
return (long)r;
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
#ifndef VLIBC_MATH_IMPL_H
|
||||
#define VLIBC_MATH_IMPL_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* vlibc — private helpers shared by the src/math/ implementation files.
|
||||
*
|
||||
* This header is internal to the todo-39 arithmetic slices (frexp, ldexp,
|
||||
* modf, scalbn, scalbln, and later slices that need to scale a value by a
|
||||
* power of two); it is never installed and is not public API.
|
||||
*
|
||||
* Every real function below is spelled for all three precisions around one
|
||||
* unified representation of a finite value:
|
||||
*
|
||||
* value = m * 2^p
|
||||
*
|
||||
* where m is an integer significand that carries the explicit integer bit
|
||||
* (m in [2^52, 2^53) for double, [2^23, 2^24) for float, [2^63, 2^64) for
|
||||
* the x86 80-bit extended format) and p is the exact unbiased power of
|
||||
* two. Normalizing a subnormal input (and an 80-bit unnormal) into this
|
||||
* shape is an exact left shift, so the scaling logic that follows never
|
||||
* has to special-case the input class again.
|
||||
*
|
||||
* Scaling by 2^n only moves p: value = m * 2^(p + n). The result class
|
||||
* is read straight off the target exponent k = p + n, and a right shift
|
||||
* with round-to-nearest-even (vl_rne_u64) is needed only when the scaled
|
||||
* value lands in the subnormal range and some low significand bits must be
|
||||
* dropped.
|
||||
*
|
||||
* The format constants (mask widths, exponent biases) are the ones the
|
||||
* rounding-family files (round.c, rint.c, ilogb.c, ...) already document;
|
||||
* only the value interpretation changes here.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Round m >> r to nearest, ties to even, returning the kept integer. r is
|
||||
* in [1, 64]; for r == 64 the entire significand is dropped and the only
|
||||
* values that can survive are those above the tie point (1 is returned),
|
||||
* while r > 64 can never round up because m < 2^64 is below the half-way
|
||||
* threshold. Callers guarantee m < 2^64 and r >= 1.
|
||||
*/
|
||||
static inline unsigned long long
|
||||
vl_rne_u64(unsigned long long m, int r)
|
||||
{
|
||||
unsigned long long kept;
|
||||
unsigned long long dropped;
|
||||
unsigned long long half;
|
||||
|
||||
if (r >= 64)
|
||||
{
|
||||
return (r > 64 || m <= (1ULL << 63)) ? 0 : 1;
|
||||
}
|
||||
kept = m >> r;
|
||||
dropped = m & ((1ULL << r) - 1ULL);
|
||||
half = 1ULL << (r - 1);
|
||||
if (dropped > half || (dropped == half && (kept & 1ULL) != 0))
|
||||
{
|
||||
kept++;
|
||||
}
|
||||
return kept;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scale a double by 2^n. Bits 62..52 are the exponent biased by 1023,
|
||||
* bits 51..0 the fraction; the significand is 53 bits wide, so a normal
|
||||
* input has m = 2^52 | frac and p = ef - 1075. A subnormal (ef == 0,
|
||||
* frac != 0) with msb at position s (0..51) normalizes exactly to
|
||||
* m = frac << (52 - s) with p = s - 1126.
|
||||
*
|
||||
* Target k = p + n: k >= 972 overflows (the exact result exceeds DBL_MAX;
|
||||
* the flag is raised and +-Inf returned), k in [-1074, 971] is an exact
|
||||
* normal result, and k <= -1075 is subnormal-or-zero with r = -1074 - k
|
||||
* dropped bits; r >= 54 always rounds to zero, and a rounded-up field of
|
||||
* exactly 2^52 is the smallest normal (ef 1, frac 0), reached when the
|
||||
* exact value is the tie just above the largest subnormal.
|
||||
*/
|
||||
static inline double
|
||||
vl_scale2_d(double x, int n, int *overflowed) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
unsigned long long bits;
|
||||
unsigned long long sign;
|
||||
unsigned long long ef;
|
||||
unsigned long long frac;
|
||||
unsigned long long m;
|
||||
unsigned long long f;
|
||||
int s;
|
||||
int p;
|
||||
int k;
|
||||
int r;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
sign = bits & (1ULL << 63);
|
||||
ef = (bits >> 52) & 0x7ff;
|
||||
frac = bits & 0xFFFFFFFFFFFFFULL;
|
||||
|
||||
if (ef == 0x7ff)
|
||||
{
|
||||
return x; /* +-Inf and NaN pass through unchanged */
|
||||
}
|
||||
if (ef == 0)
|
||||
{
|
||||
if (frac == 0)
|
||||
{
|
||||
return x; /* +-0 stays +-0 for any n */
|
||||
}
|
||||
s = 63 - __builtin_clzll(frac);
|
||||
m = frac << (52 - s);
|
||||
p = s - 1126;
|
||||
}
|
||||
else
|
||||
{
|
||||
m = frac | (1ULL << 52);
|
||||
p = (int)ef - 1075;
|
||||
}
|
||||
|
||||
k = p + n;
|
||||
if (k >= 972)
|
||||
{
|
||||
if (overflowed != NULL)
|
||||
{
|
||||
*overflowed = 1;
|
||||
}
|
||||
bits = sign | (0x7ffULL << 52);
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
if (k >= -1074)
|
||||
{
|
||||
bits = sign | ((unsigned long long)(k + 1075) << 52) | (m - (1ULL << 52));
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
r = -1074 - k;
|
||||
if (r >= 54)
|
||||
{
|
||||
bits = sign;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
f = vl_rne_u64(m, r);
|
||||
if (f == 0)
|
||||
{
|
||||
bits = sign;
|
||||
}
|
||||
else if (f == (1ULL << 52))
|
||||
{
|
||||
bits = sign | (1ULL << 52); /* smallest normal, reached by rounding up */
|
||||
}
|
||||
else
|
||||
{
|
||||
bits = sign | f;
|
||||
}
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scale a float by 2^n. Bits 30..23 are the exponent biased by 127, bits
|
||||
* 22..0 the fraction; a normal input has m = 2^23 | frac and p = ef - 150.
|
||||
* A subnormal (ef == 0, frac != 0) with msb at s (0..22) normalizes to
|
||||
* m = frac << (23 - s) with p = s - 172.
|
||||
*
|
||||
* k >= 105 overflows, k in [-149, 104] is an exact normal result, and
|
||||
* k <= -150 is subnormal-or-zero with r = -149 - k; r >= 25 always rounds
|
||||
* to zero and a rounded-up field of exactly 2^23 is the smallest normal.
|
||||
*/
|
||||
static inline float
|
||||
vl_scale2_f(float x, int n, int *overflowed) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
unsigned int bits;
|
||||
unsigned int sign;
|
||||
unsigned int ef;
|
||||
unsigned int frac;
|
||||
unsigned int m;
|
||||
unsigned int f;
|
||||
int s;
|
||||
int p;
|
||||
int k;
|
||||
int r;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
sign = bits & (1U << 31);
|
||||
ef = (bits >> 23) & 0xff;
|
||||
frac = bits & 0x7FFFFFU;
|
||||
|
||||
if (ef == 0xff)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (ef == 0)
|
||||
{
|
||||
if (frac == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
s = 31 - __builtin_clz(frac);
|
||||
m = frac << (23 - s);
|
||||
p = s - 172;
|
||||
}
|
||||
else
|
||||
{
|
||||
m = frac | (1U << 23);
|
||||
p = (int)ef - 150;
|
||||
}
|
||||
|
||||
k = p + n;
|
||||
if (k >= 105)
|
||||
{
|
||||
if (overflowed != NULL)
|
||||
{
|
||||
*overflowed = 1;
|
||||
}
|
||||
bits = sign | (0xffU << 23);
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
if (k >= -149)
|
||||
{
|
||||
bits = sign | ((unsigned int)(k + 150) << 23) | (m - (1U << 23));
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
r = -149 - k;
|
||||
if (r >= 25)
|
||||
{
|
||||
bits = sign;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
f = (unsigned int)vl_rne_u64((unsigned long long)m, r);
|
||||
if (f == 0)
|
||||
{
|
||||
bits = sign;
|
||||
}
|
||||
else if (f == (1U << 23))
|
||||
{
|
||||
bits = sign | (1U << 23);
|
||||
}
|
||||
else
|
||||
{
|
||||
bits = sign | f;
|
||||
}
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scale an x86 80-bit extended value by 2^n. The significand m is 64 bits
|
||||
* wide with an explicit integer bit; se holds the sign (bit 15) and the
|
||||
* exponent biased by 16383 (bits 14..0). A canonical normal has m in
|
||||
* [2^63, 2^64) and p = ef - 16446 (value = m * 2^(ef - 16383 - 63)). A
|
||||
* subnormal (ef == 0, m != 0) — and, defensively, an unnormal (ef > 0 with
|
||||
* m < 2^63) — is interpreted as if the exponent were max(ef, 1) and
|
||||
* normalizes exactly by shifting m left until its msb sits at bit 63.
|
||||
*
|
||||
* k >= 16321 overflows, k in [-16445, 16320] is an exact normal result
|
||||
* (for the subnormal minimum, m = 2^63 with ef' = 1), and k <= -16446 is
|
||||
* subnormal-or-zero with r = -16445 - k; r >= 65 always rounds to zero.
|
||||
* The 64-bit significand makes r == 64 the deepest meaningful shift: only
|
||||
* m above 2^63 then rounds up (to the smallest subnormal, 2^-16445).
|
||||
*/
|
||||
static inline long double
|
||||
vl_scale2_ld(long double x, int n, int *overflowed) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
} p;
|
||||
unsigned long long m;
|
||||
unsigned long long f;
|
||||
unsigned short sign;
|
||||
int ef;
|
||||
int s;
|
||||
int pwr;
|
||||
int k;
|
||||
int r;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
m = p.m;
|
||||
sign = (unsigned short)(p.se & 0x8000);
|
||||
ef = p.se & 0x7fff;
|
||||
|
||||
if (ef == 0x7fff)
|
||||
{
|
||||
return x; /* +-Inf and NaN pass through unchanged */
|
||||
}
|
||||
if (m == 0)
|
||||
{
|
||||
return x; /* +-0 (and degenerate empty encodings) stay put */
|
||||
}
|
||||
if (m < 0x8000000000000000ULL)
|
||||
{
|
||||
s = 63 - __builtin_clzll(m);
|
||||
m <<= (63 - s);
|
||||
pwr = (ef == 0 ? 1 : ef) + s - 16509;
|
||||
}
|
||||
else
|
||||
{
|
||||
pwr = ef - 16446;
|
||||
}
|
||||
|
||||
k = pwr + n;
|
||||
if (k >= 16321)
|
||||
{
|
||||
if (overflowed != NULL)
|
||||
{
|
||||
*overflowed = 1;
|
||||
}
|
||||
p.se = (unsigned short)(sign | 0x7fff);
|
||||
p.m = 0x8000000000000000ULL;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
if (k >= -16445)
|
||||
{
|
||||
p.se = (unsigned short)(sign | (unsigned short)(k + 16446));
|
||||
p.m = m;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
|
||||
r = -16445 - k;
|
||||
if (r >= 65)
|
||||
{
|
||||
p.se = sign;
|
||||
p.m = 0;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
f = vl_rne_u64(m, r);
|
||||
p.se = sign;
|
||||
p.m = f;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
|
||||
#endif /* VLIBC_MATH_IMPL_H */
|
||||
+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;
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* Integral value nearest to x in the current rounding direction (C23
|
||||
* 7.12.9.5), all three precisions, guaranteed never to raise the inexact
|
||||
* exception. No <fenv.h> exists in vlibc yet, so the only reachable
|
||||
* rounding mode is the hardware default, round-to-nearest-even; the
|
||||
* functions must still fold to correct results once <fenv.h> lands, and
|
||||
* the const attribute promises no exception and no errno path.
|
||||
*
|
||||
* GCC never folds the __builtin_nearbyint forms on this target (the
|
||||
* roundsd expansion needs SSE4.1, absent from the default -march, so
|
||||
* every __builtin_nearbyint call becomes an external nearbyint@PLT call
|
||||
* at every optimization level), so each function below rounds directly
|
||||
* on the IEEE 754 bit pattern with round-to-nearest-even: drop the low
|
||||
* (frac-bits) of the significand; a dropped part above half an ulp steps
|
||||
* the kept significand up, a dropped part of exactly half an ulp steps
|
||||
* up only when the kept LSB is odd (ties to even). The step is a plain
|
||||
* integer add that carries into the exponent field when the kept
|
||||
* fraction is all ones, which renormalizes exactly; nothing here touches
|
||||
* a rounding mode or raises an exception. nearbyint(±0) is ±0,
|
||||
* nearbyint(-0.5) is -0.0 (tie to even zero), and ±Inf/NaN pass through.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The double format: bit 63 is the sign, bits 62..52 the exponent biased
|
||||
* by 1023, bits 51..0 the fraction. A finite value with exponent e has
|
||||
* fractional bits only when e < 1075; for e in [1023, 1074] exactly the
|
||||
* low (1075 - e) bits of the fraction word are the fractional part. The
|
||||
* significand is 53 bits wide (implicit 1 plus the 52-bit fraction), so
|
||||
* in the e == 1023 binade the tie-even test looks at the implicit bit:
|
||||
* the only half-way value there is 1.5, which rounds up to 2.
|
||||
*/
|
||||
static double
|
||||
nearbyint_d(double x)
|
||||
{
|
||||
unsigned long long bits;
|
||||
unsigned long long kept;
|
||||
unsigned long long frac;
|
||||
unsigned long long half;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
e = (int)((bits >> 52) & 0x7ff);
|
||||
|
||||
if (e >= 1075)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 1023)
|
||||
{
|
||||
if ((bits & ~(1ULL << 63)) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e == 1022)
|
||||
{
|
||||
/* [1/2, 1): 0.5 itself is a tie toward even zero; anything
|
||||
* above it rounds to ±1. */
|
||||
if ((bits & 0xFFFFFFFFFFFFFULL) == 0)
|
||||
{
|
||||
bits &= 1ULL << 63;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
bits = (bits & (1ULL << 63)) | 0x3FF0000000000000ULL;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
bits &= 1ULL << 63;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
shift = 1075 - e;
|
||||
half = 1ULL << (shift - 1);
|
||||
frac = bits & ((1ULL << shift) - 1ULL);
|
||||
kept = bits & ~((1ULL << shift) - 1ULL);
|
||||
if (frac > half || (frac == half && (shift == 52 || ((kept >> shift) & 1ULL) != 0)))
|
||||
{
|
||||
kept += 1ULL << shift;
|
||||
}
|
||||
__builtin_memcpy(&x, &kept, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The float format: bit 31 is the sign, bits 30..23 the exponent biased
|
||||
* by 127, bits 22..0 the fraction; the significand is 24 bits wide. For
|
||||
* e in [127, 149] the low (150 - e) fraction bits are fractional, and in
|
||||
* the e == 127 binade the tie-even test looks at the implicit bit.
|
||||
*/
|
||||
static float
|
||||
nearbyint_f(float x)
|
||||
{
|
||||
unsigned int bits;
|
||||
unsigned int kept;
|
||||
unsigned int frac;
|
||||
unsigned int half;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
e = (int)((bits >> 23) & 0xff);
|
||||
|
||||
if (e >= 150)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 127)
|
||||
{
|
||||
if ((bits & ~(1U << 31)) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e == 126)
|
||||
{
|
||||
if ((bits & 0x7FFFFFU) == 0)
|
||||
{
|
||||
bits &= 1U << 31;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
bits = (bits & (1U << 31)) | 0x3F800000U;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
bits &= 1U << 31;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
shift = 150 - e;
|
||||
half = 1U << (shift - 1);
|
||||
frac = bits & ((1U << shift) - 1U);
|
||||
kept = bits & ~((1U << shift) - 1U);
|
||||
if (frac > half || (frac == half && (shift == 23 || ((kept >> shift) & 1U) != 0)))
|
||||
{
|
||||
kept += 1U << shift;
|
||||
}
|
||||
__builtin_memcpy(&x, &kept, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The x86 80-bit extended format: 64 significand bits m (the integer bit
|
||||
* is explicit, so the tie-even test is always m's kept LSB) and a
|
||||
* sign/exponent word se. A value m * 2^(e - 16446) has fractional bits
|
||||
* only when e < 16446; for e in [16383, 16445] the low (16446 - e) bits
|
||||
* of m are fractional. The step may overflow m when the kept significand
|
||||
* is all ones; the carry then moves the value to the next binade.
|
||||
*/
|
||||
static long double
|
||||
nearbyint_ld(long double x)
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
} p;
|
||||
unsigned long long frac;
|
||||
unsigned long long half;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
e = p.se & 0x7fff;
|
||||
|
||||
if (e >= 16446)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 16383)
|
||||
{
|
||||
if (p.m == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e == 16382)
|
||||
{
|
||||
if (p.m == 0x8000000000000000ULL)
|
||||
{
|
||||
/* Exactly 0.5: tie toward even zero. */
|
||||
p.m = 0;
|
||||
p.se &= 0x8000;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
p.m = 0x8000000000000000ULL;
|
||||
p.se = (p.se & 0x8000) | 16383;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
p.m = 0;
|
||||
p.se &= 0x8000;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
|
||||
shift = 16446 - e;
|
||||
half = 1ULL << (shift - 1);
|
||||
frac = p.m & ((1ULL << shift) - 1ULL);
|
||||
p.m &= ~((1ULL << shift) - 1ULL);
|
||||
if (frac > half || (frac == half && ((p.m >> shift) & 1ULL) != 0))
|
||||
{
|
||||
p.m += 1ULL << shift;
|
||||
if (p.m == 0)
|
||||
{
|
||||
/* Kept significand was all ones: carry to the next binade. */
|
||||
p.m = 0x8000000000000000ULL;
|
||||
p.se = (p.se & 0x8000) | (unsigned short)(e + 1);
|
||||
}
|
||||
}
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* As nearbyint, for a float argument.
|
||||
*/
|
||||
float
|
||||
nearbyintf(float x)
|
||||
{
|
||||
return nearbyint_f(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As nearbyint, for a double argument.
|
||||
*/
|
||||
double
|
||||
nearbyint(double x)
|
||||
{
|
||||
return nearbyint_d(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As nearbyint, for a long double argument.
|
||||
*/
|
||||
long double
|
||||
nearbyintl(long double x)
|
||||
{
|
||||
return nearbyint_ld(x);
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The IEEE remainder x - n*y with n = x/y rounded to the nearest integer,
|
||||
* ties to even (C23 7.12.10.2), all three precisions.
|
||||
*
|
||||
* The implementation mirrors the host glibc 2.44 remainder, which is a
|
||||
* two-stage reduction: the exact fmod(x, y + y) first clears every whole
|
||||
* multiple of 2y, leaving a residual below 2y (the doubling is finite by
|
||||
* construction of the branch below), and the residual is then rounded to
|
||||
* the nearest multiple of y -- at most one subtraction can still be wrong,
|
||||
* so comparing the doubled residual against y decides the final n exactly,
|
||||
* and each subtraction is exact (Sterbenz), making the result exact. The
|
||||
* two stages run in x's magnitude and the sign of x is applied at the
|
||||
* end, matching glibc.
|
||||
*
|
||||
* For |y| so large that y + y would overflow (|y| >= 2^1023 for double,
|
||||
* >= 2^127 for float, >= 2^16383 for the 80-bit format) the fmod stage is
|
||||
* skipped and the same rounding logic runs against y/2 -- with x below
|
||||
* 2y at those magnitudes, at most two y subtractions can be needed, which
|
||||
* the doubled-compare decision still performs exactly. Domain errors
|
||||
* return a NaN (the classic indefinite pattern) and set errno to EDOM in
|
||||
* the library build, matching the measured host behavior.
|
||||
*/
|
||||
|
||||
/* The double format: bit 63 the sign, bits 62..52 the exponent biased by
|
||||
* 1023, bits 51..0 the fraction. */
|
||||
static double
|
||||
remainder_d(double x, double y)
|
||||
{
|
||||
const unsigned long long dbl_inf = 0x7FF0000000000000ULL;
|
||||
unsigned long long xw;
|
||||
unsigned long long yw;
|
||||
unsigned long long hx;
|
||||
unsigned long long hy;
|
||||
unsigned long long sx;
|
||||
double v;
|
||||
double yh;
|
||||
|
||||
__builtin_memcpy(&xw, &x, sizeof xw);
|
||||
__builtin_memcpy(&yw, &y, sizeof yw);
|
||||
sx = xw >> 63;
|
||||
hx = xw & 0x7FFFFFFFFFFFFFFFULL;
|
||||
hy = yw & 0x7FFFFFFFFFFFFFFFULL;
|
||||
|
||||
v = fabs(x);
|
||||
y = fabs(y);
|
||||
if (hy < 0x7FE0000000000000ULL)
|
||||
{
|
||||
v = fmod(v, y + y); /* now v < 2y */
|
||||
if (v + v > y)
|
||||
{
|
||||
v -= y;
|
||||
if (v + v >= y)
|
||||
{
|
||||
v -= y;
|
||||
}
|
||||
else if (v == 0.0)
|
||||
{
|
||||
v = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* x not finite or y a NaN */
|
||||
if (hx >= dbl_inf || hy > dbl_inf)
|
||||
{
|
||||
#ifdef HAVE_CONFIG_H
|
||||
errno = EDOM;
|
||||
#endif
|
||||
xw = 0xFFF8000000000000ULL;
|
||||
__builtin_memcpy(&x, &xw, sizeof xw);
|
||||
return x;
|
||||
}
|
||||
yh = 0.5 * y;
|
||||
if (v > yh)
|
||||
{
|
||||
v -= y;
|
||||
if (v >= yh)
|
||||
{
|
||||
v -= y;
|
||||
}
|
||||
else if (v == 0.0)
|
||||
{
|
||||
v = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sx)
|
||||
{
|
||||
v = -v;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/* The float format: bit 31 the sign, bits 30..23 the exponent biased by
|
||||
* 127, bits 22..0 the fraction. */
|
||||
static float
|
||||
remainder_f(float x, float y)
|
||||
{
|
||||
const unsigned int flt_inf = 0x7F800000U;
|
||||
unsigned int xw;
|
||||
unsigned int yw;
|
||||
unsigned int hx;
|
||||
unsigned int hy;
|
||||
unsigned int sx;
|
||||
float v;
|
||||
float yh;
|
||||
|
||||
__builtin_memcpy(&xw, &x, sizeof xw);
|
||||
__builtin_memcpy(&yw, &y, sizeof yw);
|
||||
sx = xw >> 31;
|
||||
hx = xw & 0x7FFFFFFFU;
|
||||
hy = yw & 0x7FFFFFFFU;
|
||||
|
||||
v = fabsf(x);
|
||||
y = fabsf(y);
|
||||
if (hy < 0x7F000000U)
|
||||
{
|
||||
v = fmodf(v, y + y); /* now v < 2y */
|
||||
if (v + v > y)
|
||||
{
|
||||
v -= y;
|
||||
if (v + v >= y)
|
||||
{
|
||||
v -= y;
|
||||
}
|
||||
else if (v == 0.0f)
|
||||
{
|
||||
v = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* x not finite or y a NaN */
|
||||
if (hx >= flt_inf || hy > flt_inf)
|
||||
{
|
||||
#ifdef HAVE_CONFIG_H
|
||||
errno = EDOM;
|
||||
#endif
|
||||
xw = 0xFFC00000U;
|
||||
__builtin_memcpy(&x, &xw, sizeof xw);
|
||||
return x;
|
||||
}
|
||||
yh = 0.5f * y;
|
||||
if (v > yh)
|
||||
{
|
||||
v -= y;
|
||||
if (v >= yh)
|
||||
{
|
||||
v -= y;
|
||||
}
|
||||
else if (v == 0.0f)
|
||||
{
|
||||
v = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sx)
|
||||
{
|
||||
v = -v;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
* The x86 80-bit extended format: 64-bit significand m in bytes 0..7 (the
|
||||
* integer bit is explicit) and a sign/exponent word se in bytes 8..9 with
|
||||
* the sign in bit 15 and the exponent biased by 16383 in bits 14..0.
|
||||
*/
|
||||
struct remainder_ld_word
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
};
|
||||
|
||||
static long double
|
||||
remainder_l(long double x, long double y)
|
||||
{
|
||||
struct remainder_ld_word p;
|
||||
struct remainder_ld_word q;
|
||||
int sx;
|
||||
int ex;
|
||||
int ey;
|
||||
long double v;
|
||||
long double yh;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
__builtin_memcpy(&q, &y, sizeof q);
|
||||
sx = (int)(p.se >> 15);
|
||||
ex = p.se & 0x7fff;
|
||||
ey = q.se & 0x7fff;
|
||||
|
||||
v = fabsl(x);
|
||||
y = fabsl(y);
|
||||
if (ey < 0x7ffe)
|
||||
{
|
||||
v = fmodl(v, y + y); /* now v < 2y */
|
||||
if (v + v > y)
|
||||
{
|
||||
v -= y;
|
||||
if (v + v >= y)
|
||||
{
|
||||
v -= y;
|
||||
}
|
||||
else if (v == 0.0L)
|
||||
{
|
||||
v = 0.0L;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* x not finite or y a NaN */
|
||||
if (ex == 0x7fff || (ey == 0x7fff && (q.m & 0x7FFFFFFFFFFFFFFFULL) != 0))
|
||||
{
|
||||
#ifdef HAVE_CONFIG_H
|
||||
errno = EDOM;
|
||||
#endif
|
||||
p.m = 0xC000000000000000ULL;
|
||||
p.se = 0xFFFF;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
yh = 0.5L * y;
|
||||
if (v > yh)
|
||||
{
|
||||
v -= y;
|
||||
if (v >= yh)
|
||||
{
|
||||
v -= y;
|
||||
}
|
||||
else if (v == 0.0L)
|
||||
{
|
||||
v = 0.0L;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sx)
|
||||
{
|
||||
v = -v;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
* remainder for a float argument.
|
||||
*/
|
||||
float
|
||||
remainderf(float x, float y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return remainder_f(x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
* remainder for a double argument.
|
||||
*/
|
||||
double
|
||||
remainder(double x, double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return remainder_d(x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
* remainder for a long double argument.
|
||||
*/
|
||||
long double
|
||||
remainderl(long double x, long double y) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return remainder_l(x, y);
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* The IEEE remainder x - n*y with n = x/y rounded to nearest, ties to
|
||||
* even (C23 7.12.10.2), plus the signed low bits of the integer quotient
|
||||
* n stored through quo (C23 7.12.10.3), all three precisions.
|
||||
*
|
||||
* The structure mirrors the host glibc remainder/remquo implementation
|
||||
* (glibc 2.44, measured byte-for-byte), because remquo's quotient is not
|
||||
* the full n: glibc tracks only the three lowest quotient bits and still
|
||||
* returns a remainder in the exact IEEE rounding, so the two functions
|
||||
* share one reduce-then-round shape. x is first reduced by fmod(x, 8y)
|
||||
* whenever |y| is small enough for 8y to be finite, which makes |x| < 8y
|
||||
* and therefore bounds x/y below 8; the tracked quotient cquo collects
|
||||
* the one 4y subtraction, the one 2y subtraction and the final rounding's
|
||||
* up-to-two y subtractions, which together hold the three lowest bits of
|
||||
* n. The final compare against y/2 (using doubled compares when y is so
|
||||
* small that halving could lose precision) rounds x to the nearest
|
||||
* multiple of y, ties to even via the natural 0.5 boundary, and each
|
||||
* subtraction that fires is exact (Sterbenz), so the returned remainder
|
||||
* is exact.
|
||||
*
|
||||
* The x86-64 host collapses the remainder and quotient signs the same
|
||||
* way the code below does: the magnitude result is computed from |x| and
|
||||
* |y| and then negated when x < 0, and *quo carries the sign of x/y.
|
||||
* Domain errors -- |y| == 0, x not finite, y a NaN -- return a NaN (the
|
||||
* classic indefinite pattern) and leave *quo untouched, as glibc does.
|
||||
* Like glibc, remquo never touches errno.
|
||||
*/
|
||||
|
||||
/* The double format: bit 63 the sign, bits 62..52 the exponent biased by
|
||||
* 1023, bits 51..0 the fraction. */
|
||||
static double
|
||||
remquo_d(double x, double y, int *quo)
|
||||
{
|
||||
const unsigned long long dbl_inf = 0x7FF0000000000000ULL;
|
||||
unsigned long long xw;
|
||||
unsigned long long yw;
|
||||
unsigned long long hx;
|
||||
unsigned long long hy;
|
||||
unsigned long long sx;
|
||||
unsigned long long sy;
|
||||
double ax;
|
||||
double ay;
|
||||
double yh;
|
||||
int cquo;
|
||||
int qneg;
|
||||
|
||||
__builtin_memcpy(&xw, &x, sizeof xw);
|
||||
__builtin_memcpy(&yw, &y, sizeof yw);
|
||||
sx = xw >> 63;
|
||||
sy = yw >> 63;
|
||||
qneg = (int)(sx ^ sy);
|
||||
hx = xw & 0x7FFFFFFFFFFFFFFFULL;
|
||||
hy = yw & 0x7FFFFFFFFFFFFFFFULL;
|
||||
|
||||
if (hy == 0 || hx >= dbl_inf || hy > dbl_inf)
|
||||
{
|
||||
xw = 0xFFF8000000000000ULL;
|
||||
__builtin_memcpy(&x, &xw, sizeof xw);
|
||||
return x;
|
||||
}
|
||||
|
||||
if (hx == hy)
|
||||
{
|
||||
*quo = qneg ? -1 : 1;
|
||||
return x * 0.0;
|
||||
}
|
||||
|
||||
ax = fabs(x);
|
||||
ay = fabs(y);
|
||||
if (hy <= 0x7FBFFFFFFFFFFFFFULL)
|
||||
{
|
||||
ax = fmod(ax, 8.0 * ay); /* now ax < 8 * ay */
|
||||
}
|
||||
|
||||
cquo = 0;
|
||||
if (hy <= 0x7FCFFFFFFFFFFFFFULL && ax >= 4.0 * ay)
|
||||
{
|
||||
ax -= 4.0 * ay;
|
||||
cquo += 4;
|
||||
}
|
||||
if (hy <= 0x7FDFFFFFFFFFFFFFULL && ax >= 2.0 * ay)
|
||||
{
|
||||
ax -= 2.0 * ay;
|
||||
cquo += 2;
|
||||
}
|
||||
|
||||
if (hy < 0x0020000000000000ULL)
|
||||
{
|
||||
if (ax + ax > ay)
|
||||
{
|
||||
ax -= ay;
|
||||
cquo++;
|
||||
if (ax + ax >= ay)
|
||||
{
|
||||
ax -= ay;
|
||||
cquo++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yh = 0.5 * ay;
|
||||
if (ax > yh)
|
||||
{
|
||||
ax -= ay;
|
||||
cquo++;
|
||||
if (ax >= yh)
|
||||
{
|
||||
ax -= ay;
|
||||
cquo++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*quo = qneg ? -cquo : cquo;
|
||||
if (ax == 0.0)
|
||||
{
|
||||
ax = 0.0;
|
||||
}
|
||||
if (sx)
|
||||
{
|
||||
ax = -ax;
|
||||
}
|
||||
return ax;
|
||||
}
|
||||
|
||||
/* The float format: bit 31 the sign, bits 30..23 the exponent biased by
|
||||
* 127, bits 22..0 the fraction. */
|
||||
static float
|
||||
remquo_f(float x, float y, int *quo)
|
||||
{
|
||||
const unsigned int flt_inf = 0x7F800000U;
|
||||
unsigned int xw;
|
||||
unsigned int yw;
|
||||
unsigned int hx;
|
||||
unsigned int hy;
|
||||
unsigned int sx;
|
||||
unsigned int sy;
|
||||
float ax;
|
||||
float ay;
|
||||
float yh;
|
||||
int cquo;
|
||||
int qneg;
|
||||
|
||||
__builtin_memcpy(&xw, &x, sizeof xw);
|
||||
__builtin_memcpy(&yw, &y, sizeof yw);
|
||||
sx = xw >> 31;
|
||||
sy = yw >> 31;
|
||||
qneg = (int)(sx ^ sy);
|
||||
hx = xw & 0x7FFFFFFFU;
|
||||
hy = yw & 0x7FFFFFFFU;
|
||||
|
||||
if (hy == 0 || hx >= flt_inf || hy > flt_inf)
|
||||
{
|
||||
xw = 0xFFC00000U;
|
||||
__builtin_memcpy(&x, &xw, sizeof xw);
|
||||
return x;
|
||||
}
|
||||
|
||||
if (hx == hy)
|
||||
{
|
||||
*quo = qneg ? -1 : 1;
|
||||
return x * 0.0f;
|
||||
}
|
||||
|
||||
ax = fabsf(x);
|
||||
ay = fabsf(y);
|
||||
if (hy <= 0x7DFFFFFFU)
|
||||
{
|
||||
ax = fmodf(ax, 8.0f * ay); /* now ax < 8 * ay */
|
||||
}
|
||||
|
||||
cquo = 0;
|
||||
if (hy <= 0x7E7FFFFFU && ax >= 4.0f * ay)
|
||||
{
|
||||
ax -= 4.0f * ay;
|
||||
cquo += 4;
|
||||
}
|
||||
if (hy <= 0x7EFFFFFFU && ax >= 2.0f * ay)
|
||||
{
|
||||
ax -= 2.0f * ay;
|
||||
cquo += 2;
|
||||
}
|
||||
|
||||
if (hy < 0x01000000U)
|
||||
{
|
||||
if (ax + ax > ay)
|
||||
{
|
||||
ax -= ay;
|
||||
cquo++;
|
||||
if (ax + ax >= ay)
|
||||
{
|
||||
ax -= ay;
|
||||
cquo++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yh = 0.5f * ay;
|
||||
if (ax > yh)
|
||||
{
|
||||
ax -= ay;
|
||||
cquo++;
|
||||
if (ax >= yh)
|
||||
{
|
||||
ax -= ay;
|
||||
cquo++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*quo = qneg ? -cquo : cquo;
|
||||
if (ax == 0.0f)
|
||||
{
|
||||
ax = 0.0f;
|
||||
}
|
||||
if (sx)
|
||||
{
|
||||
ax = -ax;
|
||||
}
|
||||
return ax;
|
||||
}
|
||||
|
||||
/*
|
||||
* The x86 80-bit extended format: 64-bit significand m in bytes 0..7 (the
|
||||
* integer bit is explicit) and a sign/exponent word se in bytes 8..9 with
|
||||
* the sign in bit 15 and the exponent biased by 16383 in bits 14..0.
|
||||
*/
|
||||
struct remquo_ld_word
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
};
|
||||
|
||||
static long double
|
||||
remquo_l(long double x, long double y, int *quo)
|
||||
{
|
||||
struct remquo_ld_word p;
|
||||
struct remquo_ld_word q;
|
||||
int ex;
|
||||
int ey;
|
||||
int qneg;
|
||||
int sx;
|
||||
int sy;
|
||||
long double ax;
|
||||
long double ay;
|
||||
long double yh;
|
||||
int cquo;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
__builtin_memcpy(&q, &y, sizeof q);
|
||||
sx = (int)(p.se >> 15);
|
||||
sy = (int)(q.se >> 15);
|
||||
qneg = sx ^ sy;
|
||||
ex = p.se & 0x7fff;
|
||||
ey = q.se & 0x7fff;
|
||||
|
||||
if ((q.m == 0 && ey == 0) || ex == 0x7fff ||
|
||||
(ey == 0x7fff && (q.m & 0x7FFFFFFFFFFFFFFFULL) != 0))
|
||||
{
|
||||
p.m = 0xC000000000000000ULL;
|
||||
p.se = 0xFFFF;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
|
||||
if (ex == ey && p.m == q.m)
|
||||
{
|
||||
*quo = qneg ? -1 : 1;
|
||||
return x * 0.0L;
|
||||
}
|
||||
|
||||
ax = fabsl(x);
|
||||
ay = fabsl(y);
|
||||
if (ey <= 0x7ffb)
|
||||
{
|
||||
ax = fmodl(ax, 8.0L * ay); /* now ax < 8 * ay */
|
||||
}
|
||||
|
||||
cquo = 0;
|
||||
if (ey <= 0x7ffc && ax >= 4.0L * ay)
|
||||
{
|
||||
ax -= 4.0L * ay;
|
||||
cquo += 4;
|
||||
}
|
||||
if (ey <= 0x7ffd && ax >= 2.0L * ay)
|
||||
{
|
||||
ax -= 2.0L * ay;
|
||||
cquo += 2;
|
||||
}
|
||||
|
||||
if (ey < 0x0002)
|
||||
{
|
||||
if (ax + ax > ay)
|
||||
{
|
||||
ax -= ay;
|
||||
cquo++;
|
||||
if (ax + ax >= ay)
|
||||
{
|
||||
ax -= ay;
|
||||
cquo++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yh = 0.5L * ay;
|
||||
if (ax > yh)
|
||||
{
|
||||
ax -= ay;
|
||||
cquo++;
|
||||
if (ax >= yh)
|
||||
{
|
||||
ax -= ay;
|
||||
cquo++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*quo = qneg ? -cquo : cquo;
|
||||
if (ax == 0.0L)
|
||||
{
|
||||
ax = 0.0L;
|
||||
}
|
||||
if (sx)
|
||||
{
|
||||
ax = -ax;
|
||||
}
|
||||
return ax;
|
||||
}
|
||||
|
||||
/*
|
||||
* remquo for a float argument.
|
||||
*/
|
||||
float
|
||||
remquof(float x, float y, int *quo) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return remquo_f(x, y, quo);
|
||||
}
|
||||
|
||||
/*
|
||||
* remquo for a double argument.
|
||||
*/
|
||||
double
|
||||
remquo(double x, double y, int *quo) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return remquo_d(x, y, quo);
|
||||
}
|
||||
|
||||
/*
|
||||
* remquo for a long double argument.
|
||||
*/
|
||||
long double
|
||||
remquol(long double x, long double y, int *quo) // NOLINT(bugprone-easily-swappable-parameters)
|
||||
{
|
||||
return remquo_l(x, y, quo);
|
||||
}
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* Integral value nearest to x in the current rounding direction (C23
|
||||
* 7.12.9.4), all three precisions. rint differs from nearbyint only in
|
||||
* that it may raise the inexact exception; never raising it is also
|
||||
* conforming, and the const attribute promises no errno path.
|
||||
*
|
||||
* The __builtin_rint forms are tempting (they fold to in-line code on
|
||||
* this target), but GCC warns -Winfinite-recursion when the enclosing
|
||||
* function carries the same name as the library symbol the builtin would
|
||||
* fall back to (a function named rint whose body is __builtin_rint),
|
||||
* which the -Wall -Wextra -pedantic build gate forbids. Each function is
|
||||
* therefore implemented directly on the IEEE 754 bit pattern with
|
||||
* round-to-nearest-even, exactly like nearbyint (see nearbyint.c): no
|
||||
* <fenv.h> exists in vlibc yet, so the hardware default round-to-nearest-
|
||||
* even is the only reachable rounding mode. rint(±0) is ±0, rint(-0.5)
|
||||
* is -0.0 (tie to even zero), and ±Inf/NaN pass through unchanged.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The double format: bit 63 is the sign, bits 62..52 the exponent biased
|
||||
* by 1023, bits 51..0 the fraction. For e in [1023, 1074] the low
|
||||
* (1075 - e) bits of the fraction word are the fractional part; the
|
||||
* significand is 53 bits wide, so in the e == 1023 binade the tie-even
|
||||
* test looks at the implicit bit (the only half-way value there, 1.5,
|
||||
* rounds up to 2).
|
||||
*/
|
||||
static double
|
||||
rint_d(double x)
|
||||
{
|
||||
unsigned long long bits;
|
||||
unsigned long long kept;
|
||||
unsigned long long frac;
|
||||
unsigned long long half;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
e = (int)((bits >> 52) & 0x7ff);
|
||||
|
||||
if (e >= 1075)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 1023)
|
||||
{
|
||||
if ((bits & ~(1ULL << 63)) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e == 1022)
|
||||
{
|
||||
/* [1/2, 1): 0.5 itself is a tie toward even zero; anything
|
||||
* above it rounds to ±1. */
|
||||
if ((bits & 0xFFFFFFFFFFFFFULL) == 0)
|
||||
{
|
||||
bits &= 1ULL << 63;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
bits = (bits & (1ULL << 63)) | 0x3FF0000000000000ULL;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
bits &= 1ULL << 63;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
shift = 1075 - e;
|
||||
half = 1ULL << (shift - 1);
|
||||
frac = bits & ((1ULL << shift) - 1ULL);
|
||||
kept = bits & ~((1ULL << shift) - 1ULL);
|
||||
if (frac > half || (frac == half && (shift == 52 || ((kept >> shift) & 1ULL) != 0)))
|
||||
{
|
||||
kept += 1ULL << shift;
|
||||
}
|
||||
__builtin_memcpy(&x, &kept, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The float format: bit 31 is the sign, bits 30..23 the exponent biased
|
||||
* by 127, bits 22..0 the fraction; the significand is 24 bits wide. For
|
||||
* e in [127, 149] the low (150 - e) fraction bits are fractional, and in
|
||||
* the e == 127 binade the tie-even test looks at the implicit bit.
|
||||
*/
|
||||
static float
|
||||
rint_f(float x)
|
||||
{
|
||||
unsigned int bits;
|
||||
unsigned int kept;
|
||||
unsigned int frac;
|
||||
unsigned int half;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
e = (int)((bits >> 23) & 0xff);
|
||||
|
||||
if (e >= 150)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 127)
|
||||
{
|
||||
if ((bits & ~(1U << 31)) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e == 126)
|
||||
{
|
||||
if ((bits & 0x7FFFFFU) == 0)
|
||||
{
|
||||
bits &= 1U << 31;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
bits = (bits & (1U << 31)) | 0x3F800000U;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
bits &= 1U << 31;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
shift = 150 - e;
|
||||
half = 1U << (shift - 1);
|
||||
frac = bits & ((1U << shift) - 1U);
|
||||
kept = bits & ~((1U << shift) - 1U);
|
||||
if (frac > half || (frac == half && (shift == 23 || ((kept >> shift) & 1U) != 0)))
|
||||
{
|
||||
kept += 1U << shift;
|
||||
}
|
||||
__builtin_memcpy(&x, &kept, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The x86 80-bit extended format: 64 significand bits m (the integer bit
|
||||
* is explicit, so the tie-even test is always m's kept LSB) and a
|
||||
* sign/exponent word se. For e in [16383, 16445] the low (16446 - e)
|
||||
* bits of m are fractional. The step may overflow m when the kept
|
||||
* significand is all ones; the carry then moves the value to the next
|
||||
* binade.
|
||||
*/
|
||||
static long double
|
||||
rint_ld(long double x)
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
} p;
|
||||
unsigned long long frac;
|
||||
unsigned long long half;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
e = p.se & 0x7fff;
|
||||
|
||||
if (e >= 16446)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 16383)
|
||||
{
|
||||
if (p.m == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e == 16382)
|
||||
{
|
||||
if (p.m == 0x8000000000000000ULL)
|
||||
{
|
||||
/* Exactly 0.5: tie toward even zero. */
|
||||
p.m = 0;
|
||||
p.se &= 0x8000;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
p.m = 0x8000000000000000ULL;
|
||||
p.se = (p.se & 0x8000) | 16383;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
p.m = 0;
|
||||
p.se &= 0x8000;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
|
||||
shift = 16446 - e;
|
||||
half = 1ULL << (shift - 1);
|
||||
frac = p.m & ((1ULL << shift) - 1ULL);
|
||||
p.m &= ~((1ULL << shift) - 1ULL);
|
||||
if (frac > half || (frac == half && ((p.m >> shift) & 1ULL) != 0))
|
||||
{
|
||||
p.m += 1ULL << shift;
|
||||
if (p.m == 0)
|
||||
{
|
||||
/* Kept significand was all ones: carry to the next binade. */
|
||||
p.m = 0x8000000000000000ULL;
|
||||
p.se = (p.se & 0x8000) | (unsigned short)(e + 1);
|
||||
}
|
||||
}
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* As rint, for a float argument.
|
||||
*/
|
||||
float
|
||||
rintf(float x)
|
||||
{
|
||||
return rint_f(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As rint, for a double argument.
|
||||
*/
|
||||
double
|
||||
rint(double x)
|
||||
{
|
||||
return rint_d(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As rint, for a long double argument.
|
||||
*/
|
||||
long double
|
||||
rintl(long double x)
|
||||
{
|
||||
return rint_ld(x);
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* Integral value nearest to x, halfway cases rounded away from zero
|
||||
* (C23 7.12.9.6), all three precisions.
|
||||
*
|
||||
* GCC never folds the __builtin_round forms on this target (no SSE4.1 in
|
||||
* the default -march, so the roundsd expansion is unavailable and every
|
||||
* __builtin_round call becomes an external round@PLT call at every
|
||||
* optimization level), so each function below rounds directly on the
|
||||
* IEEE 754 bit pattern. A negative argument with a nonzero dropped
|
||||
* fraction must round away from zero, so the rounding is applied to the
|
||||
* magnitude (sign bit untouched): drop the fractional bits, and when the
|
||||
* dropped part is >= half an ulp step the kept significand up by one.
|
||||
* The step is a plain integer add that carries into the exponent field
|
||||
* when the kept fraction is all ones, which renormalizes exactly.
|
||||
* round(±0) is ±0, round(-0.5) is -1.0 (half away from zero), and ±Inf
|
||||
* and NaN pass through unchanged. Pure: no rounding mode consulted and no
|
||||
* exception raised.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The double format: bit 63 is the sign, bits 62..52 the exponent biased
|
||||
* by 1023, bits 51..0 the fraction. A finite value with exponent e has
|
||||
* fractional bits only when e - 1023 < 52, i.e. e < 1075; for e in
|
||||
* [1023, 1074] exactly the low (1075 - e) bits of the fraction word are
|
||||
* the fractional part.
|
||||
*/
|
||||
static double
|
||||
round_d(double x)
|
||||
{
|
||||
unsigned long long bits;
|
||||
unsigned long long kept;
|
||||
unsigned long long frac;
|
||||
unsigned long long half;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
e = (int)((bits >> 52) & 0x7ff);
|
||||
|
||||
/* |x| >= 2^52 is already integral; Inf (e == 0x7ff) and NaN pass
|
||||
* through unchanged as well. */
|
||||
if (e >= 1075)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
/* |x| < 1: round(±0) is ±0 and any other value with |x| >= 1/2 goes
|
||||
* to ±1 while smaller magnitudes collapse to ±0, keeping the sign. */
|
||||
if (e < 1023)
|
||||
{
|
||||
if ((bits & ~(1ULL << 63)) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e == 1022)
|
||||
{
|
||||
bits = (bits & (1ULL << 63)) | 0x3FF0000000000000ULL;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
bits &= 1ULL << 63;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
shift = 1075 - e;
|
||||
half = 1ULL << (shift - 1);
|
||||
frac = bits & ((1ULL << shift) - 1ULL);
|
||||
kept = bits & ~((1ULL << shift) - 1ULL);
|
||||
if (frac >= half)
|
||||
{
|
||||
kept += 1ULL << shift;
|
||||
}
|
||||
__builtin_memcpy(&x, &kept, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The float format: bit 31 is the sign, bits 30..23 the exponent biased
|
||||
* by 127, bits 22..0 the fraction. Fraction bits exist exactly when the
|
||||
* exponent e is in [127, 149]; the low (150 - e) bits are fractional.
|
||||
*/
|
||||
static float
|
||||
round_f(float x)
|
||||
{
|
||||
unsigned int bits;
|
||||
unsigned int kept;
|
||||
unsigned int frac;
|
||||
unsigned int half;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
e = (int)((bits >> 23) & 0xff);
|
||||
|
||||
if (e >= 150)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 127)
|
||||
{
|
||||
if ((bits & ~(1U << 31)) == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e == 126)
|
||||
{
|
||||
bits = (bits & (1U << 31)) | 0x3F800000U;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
bits &= 1U << 31;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
shift = 150 - e;
|
||||
half = 1U << (shift - 1);
|
||||
frac = bits & ((1U << shift) - 1U);
|
||||
kept = bits & ~((1U << shift) - 1U);
|
||||
if (frac >= half)
|
||||
{
|
||||
kept += 1U << shift;
|
||||
}
|
||||
__builtin_memcpy(&x, &kept, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* The x86 80-bit extended format: 64 significand bits m (the integer bit
|
||||
* is explicit) in bytes 0..7 and a sign/exponent word se in bytes 8..9,
|
||||
* with the sign in bit 15 and the exponent (biased by 16383) in bits
|
||||
* 14..0. A value m * 2^(e - 16446) has fractional bits only when
|
||||
* e - 16383 < 63, i.e. e < 16446. The half-away step may overflow the
|
||||
* 64-bit m when the kept significand is all ones; the carry then moves
|
||||
* the value to the next binade (e + 1, integer bit alone).
|
||||
*/
|
||||
static long double
|
||||
round_ld(long double x)
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
} p;
|
||||
unsigned long long frac;
|
||||
unsigned long long half;
|
||||
int e;
|
||||
int shift;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
e = p.se & 0x7fff;
|
||||
|
||||
if (e >= 16446)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 16383)
|
||||
{
|
||||
if (p.m == 0)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e == 16382)
|
||||
{
|
||||
p.m = 0x8000000000000000ULL;
|
||||
p.se = (p.se & 0x8000) | 16383;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
p.m = 0;
|
||||
p.se &= 0x8000;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
|
||||
shift = 16446 - e;
|
||||
half = 1ULL << (shift - 1);
|
||||
frac = p.m & ((1ULL << shift) - 1ULL);
|
||||
p.m &= ~((1ULL << shift) - 1ULL);
|
||||
if (frac >= half)
|
||||
{
|
||||
p.m += 1ULL << shift;
|
||||
if (p.m == 0)
|
||||
{
|
||||
/* Kept significand was all ones: carry to the next binade. */
|
||||
p.m = 0x8000000000000000ULL;
|
||||
p.se = (p.se & 0x8000) | (unsigned short)(e + 1);
|
||||
}
|
||||
}
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* As round, for a float argument.
|
||||
*/
|
||||
float
|
||||
roundf(float x)
|
||||
{
|
||||
return round_f(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As round, for a double argument.
|
||||
*/
|
||||
double
|
||||
round(double x)
|
||||
{
|
||||
return round_d(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As round, for a long double argument.
|
||||
*/
|
||||
long double
|
||||
roundl(long double x)
|
||||
{
|
||||
return round_ld(x);
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "math_impl.h"
|
||||
|
||||
/*
|
||||
* x * FLT_RADIX^n with FLT_RADIX 2 (C23 7.12.6.6), all three precisions
|
||||
* and both exponent-argument types. scalbn takes an int n, scalbln a long
|
||||
* n; otherwise the two families are semantically identical to ldexp (they
|
||||
* share the exact same scale cores and overflow-to-+-Inf-with-ERANGE
|
||||
* behavior, and subnormal inputs are handled exactly like subnormal
|
||||
* outputs). The scalbln functions clamp the long exponent to +-20000
|
||||
* first: any magnitude beyond that saturates every result to +-Inf or +-0
|
||||
* in all three formats, and clamping keeps the arithmetic inside int range
|
||||
* with no shift by a huge count.
|
||||
*/
|
||||
|
||||
/*
|
||||
* As ldexp (see ldexp.c) for a double x and an int n.
|
||||
*/
|
||||
double
|
||||
scalbn(double x, int n)
|
||||
{
|
||||
int overflowed = 0;
|
||||
double r = vl_scale2_d(x, n, &overflowed);
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
if (overflowed)
|
||||
{
|
||||
errno = ERANGE;
|
||||
}
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
float
|
||||
scalbnf(float x, int n)
|
||||
{
|
||||
int overflowed = 0;
|
||||
float r = vl_scale2_f(x, n, &overflowed);
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
if (overflowed)
|
||||
{
|
||||
errno = ERANGE;
|
||||
}
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
long double
|
||||
scalbnl(long double x, int n)
|
||||
{
|
||||
int overflowed = 0;
|
||||
long double r = vl_scale2_ld(x, n, &overflowed);
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
if (overflowed)
|
||||
{
|
||||
errno = ERANGE;
|
||||
}
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* The scalbln family: as scalbn with the exponent given as a long.
|
||||
* n is first clamped into [-20000, 20000]; anything beyond saturates every
|
||||
* precision's range (the largest meaningful long-double exponent is below
|
||||
* 16446 in magnitude), so no precision is lost by the clamp.
|
||||
*/
|
||||
double
|
||||
scalbln(double x, long n)
|
||||
{
|
||||
if (n > 20000)
|
||||
{
|
||||
n = 20000;
|
||||
}
|
||||
else if (n < -20000)
|
||||
{
|
||||
n = -20000;
|
||||
}
|
||||
return scalbn(x, (int)n);
|
||||
}
|
||||
|
||||
float
|
||||
scalblnf(float x, long n)
|
||||
{
|
||||
if (n > 20000)
|
||||
{
|
||||
n = 20000;
|
||||
}
|
||||
else if (n < -20000)
|
||||
{
|
||||
n = -20000;
|
||||
}
|
||||
return scalbnf(x, (int)n);
|
||||
}
|
||||
|
||||
long double
|
||||
scalblnl(long double x, long n)
|
||||
{
|
||||
if (n > 20000)
|
||||
{
|
||||
n = 20000;
|
||||
}
|
||||
else if (n < -20000)
|
||||
{
|
||||
n = -20000;
|
||||
}
|
||||
return scalbnl(x, (int)n);
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
* Integral value nearest to x in the direction of zero (C23 7.12.9.3),
|
||||
* all three precisions.
|
||||
*
|
||||
* GCC does not fold the __builtin_trunc forms on this target (see
|
||||
* floor.c), so each function below simply clears the fractional mantissa
|
||||
* bits on the IEEE 754 bit pattern. Rounding toward zero never rounds, so
|
||||
* no rounding mode or exception is involved; trunc(-0.3) is -0.0 (the
|
||||
* sign bit survives), and ±Inf/NaN pass through unchanged.
|
||||
*/
|
||||
|
||||
static double
|
||||
trunc_d(double x)
|
||||
{
|
||||
unsigned long long bits;
|
||||
int e;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
e = (int)((bits >> 52) & 0x7ff);
|
||||
|
||||
/* |x| >= 2^52 is already integral; Inf (e == 0x7ff) and NaN pass
|
||||
* through unchanged as well. */
|
||||
if (e >= 1075)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 1023)
|
||||
{
|
||||
/* |x| < 1: truncation is ±0, keeping the sign bit. */
|
||||
bits &= 1ULL << 63;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
bits &= ~((1ULL << (1075 - e)) - 1ULL);
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
static float
|
||||
trunc_f(float x)
|
||||
{
|
||||
unsigned int bits;
|
||||
int e;
|
||||
|
||||
__builtin_memcpy(&bits, &x, sizeof bits);
|
||||
e = (int)((bits >> 23) & 0xff);
|
||||
|
||||
if (e >= 150)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 127)
|
||||
{
|
||||
bits &= 1U << 31;
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
bits &= ~((1U << (150 - e)) - 1U);
|
||||
__builtin_memcpy(&x, &bits, sizeof x);
|
||||
return x;
|
||||
}
|
||||
|
||||
static long double
|
||||
trunc_ld(long double x)
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned long long m;
|
||||
unsigned short se;
|
||||
} p;
|
||||
int e;
|
||||
|
||||
__builtin_memcpy(&p, &x, sizeof p);
|
||||
e = p.se & 0x7fff;
|
||||
|
||||
if (e >= 16446)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
if (e < 16383)
|
||||
{
|
||||
/* |x| < 1: truncation is ±0, keeping the sign bit. */
|
||||
p.m = 0;
|
||||
p.se &= 0x8000;
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
|
||||
p.m &= ~((1ULL << (63 - (e - 16383))) - 1ULL);
|
||||
__builtin_memcpy(&x, &p, sizeof p);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* As trunc, for a float argument.
|
||||
*/
|
||||
float
|
||||
truncf(float x)
|
||||
{
|
||||
return trunc_f(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As trunc, for a double argument.
|
||||
*/
|
||||
double
|
||||
trunc(double x)
|
||||
{
|
||||
return trunc_d(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* As trunc, for a long double argument.
|
||||
*/
|
||||
long double
|
||||
truncl(long double x)
|
||||
{
|
||||
return trunc_ld(x);
|
||||
}
|
||||
Reference in New Issue
Block a user