feat(math): abs/round/trunc/frexp/ldexp/scalbn/copysign/fmin/fmax/fmod

This commit is contained in:
2026-09-06 01:07:31 -04:00
parent c4c64a4eb5
commit b731a02db4
30 changed files with 5912 additions and 7 deletions
+173
View File
@@ -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);
}
+74
View File
@@ -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;
}
+41
View File
@@ -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);
}
+71
View File
@@ -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;
}
+207
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+173
View File
@@ -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;
}
+126
View File
@@ -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;
}
+76
View File
@@ -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;
}
+45
View File
@@ -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);
}
+73
View File
@@ -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
View File
@@ -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);
}
+49
View File
@@ -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);
}
+64
View File
@@ -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;
}
+341
View File
@@ -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
View File
@@ -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;
}
+248
View File
@@ -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);
}
+284
View File
@@ -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);
}
+364
View File
@@ -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
View File
@@ -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);
}
+226
View File
@@ -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);
}
+121
View File
@@ -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);
}
+127
View File
@@ -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);
}