Files
AnyPS5/core/libs/tests/GuestMath.cpp
T
Jota f8545e961e fix(tests): compare the Bessel exports with fixed reference values
libc++ does not provide std::cyl_bessel_j or std::cyl_neumann, so
GuestMath.cpp stopped compiling on macOS after the Bessel exports were
added. The three checks now compare against the values of J0(2.5),
J3(4.0) and Y2(3.0), which glibc and macOS libm agree on to 1e-16.
2026-10-19 15:24:58 -03:00

1269 lines
75 KiB
C++

#include "prx/libc/include/general/VabiMacros.hpp"
#include <bit>
#include <cerrno>
#include <cfenv>
#include <climits>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <initializer_list>
#include <xmmintrin.h>
struct GuestFloatingPointEnvironment {
std::uint32_t control;
std::uint32_t status;
std::uint32_t tag;
unsigned char other[16];
std::uint32_t mxcsr;
};
static_assert(sizeof(GuestFloatingPointEnvironment) == 32);
extern "C" {
int APS5_VABI fegetenv_nid_postfix(GuestFloatingPointEnvironment*);
double APS5_VABI atof_nid_postfix(const char*);
double APS5_VABI strtod_nid_postfix(const char*, char**);
double APS5_VABI wcstod_nid_postfix(const char16_t*, char16_t**);
float APS5_VABI wcstof_nid_postfix(const char16_t*, char16_t**);
long double APS5_VABI wcstold_nid_postfix(const char16_t*, char16_t**);
float APS5_VABI strtof_nid_postfix(const char*, char**);
long double APS5_VABI strtold_nid_postfix(const char*, char**);
std::int64_t APS5_VABI strtol_nid_postfix(const char*, char**, int);
std::uint64_t APS5_VABI strtoul_nid_postfix(const char*, char**, int);
std::intmax_t APS5_VABI strtoimax_nid_postfix(const char*, char**, int);
long long APS5_VABI strtoll_nid_postfix(const char*, char**, int);
unsigned long long APS5_VABI strtoull_nid_postfix(const char*, char**, int);
std::uintmax_t APS5_VABI strtoumax_nid_postfix(const char*, char**, int);
unsigned long long APS5_VABI _Stoull_nid_postfix(const char*, char**, int);
std::uint64_t APS5_VABI _Stoul_nid_postfix(const char*, char**, int);
std::int64_t APS5_VABI atol_nid_postfix(const char*);
long long APS5_VABI atoll_nid_postfix(const char*);
int* APS5_VABI __error_nid_postfix();
double APS5_VABI sqrt_nid_postfix(double);
float APS5_VABI sqrtf_nid_postfix(float);
double APS5_VABI fabs_nid_postfix(double);
int APS5_VABI abs_nid_postfix(int);
double APS5_VABI trunc_nid_postfix(double);
double APS5_VABI ceil_nid_postfix(double);
double APS5_VABI floor_nid_postfix(double);
float APS5_VABI truncf_nid_postfix(float);
float APS5_VABI ceilf_nid_postfix(float);
float APS5_VABI floorf_nid_postfix(float);
double APS5_VABI nearbyint_nid_postfix(double);
double APS5_VABI fma_nid_postfix(double, double, double);
long double APS5_VABI acosl_nid_postfix(long double);
long double APS5_VABI asinl_nid_postfix(long double);
long double APS5_VABI frexpl_nid_postfix(long double, int*);
struct LibcFloatConstant { std::uint32_t bits[4]; };
extern LibcFloatConstant _FInf_nid_postfix;
extern LibcFloatConstant _FNan_nid_postfix;
short APS5_VABI _FDtest_nid_postfix(const float*);
short APS5_VABI _Dtest_nid_postfix(const double*);
int APS5_VABI __fpclassifyf_nid_postfix(float);
int APS5_VABI isnanf_nid_postfix(float);
int APS5_VABI __signbitl_nid_postfix(long double);
float APS5_VABI fmodf_nid_postfix(float, float);
double APS5_VABI fmod_nid_postfix(double, double);
float APS5_VABI asinf_nid_postfix(float);
float APS5_VABI acosf_nid_postfix(float);
double APS5_VABI asin_nid_postfix(double);
float APS5_VABI atan2f_nid_postfix(float, float);
float APS5_VABI hypotf_nid_postfix(float, float);
double APS5_VABI hypot_nid_postfix(double, double);
double APS5_VABI fdim_nid_postfix(double, double);
float APS5_VABI fdimf_nid_postfix(float, float);
float APS5_VABI fabsf_nid_postfix(float);
long double APS5_VABI fabsl_nid_postfix(long double);
double APS5_VABI copysign_nid_postfix(double, double);
float APS5_VABI copysignf_nid_postfix(float, float);
double APS5_VABI remquo_nid_postfix(double, double, int*);
float APS5_VABI remquof_nid_postfix(float, float, int*);
float APS5_VABI fmaf_nid_postfix(float, float, float);
long double APS5_VABI ceill_nid_postfix(long double);
long double APS5_VABI floorl_nid_postfix(long double);
float APS5_VABI tanf_nid_postfix(float);
int APS5_VABI rand_nid_postfix();
void APS5_VABI srand_nid_postfix(unsigned int);
int APS5_VABI rand_r_nid_postfix(unsigned int*);
float APS5_VABI log10f_nid_postfix(float);
float APS5_VABI powf_nid_postfix(float, float);
double APS5_VABI log1p_nid_postfix(double);
float APS5_VABI log1pf_nid_postfix(float);
double APS5_VABI expm1_nid_postfix(double);
float APS5_VABI expm1f_nid_postfix(float);
float APS5_VABI erff_nid_postfix(float);
double APS5_VABI erf_nid_postfix(double);
double APS5_VABI erfc_nid_postfix(double);
float APS5_VABI erfcf_nid_postfix(float);
double APS5_VABI lgamma_nid_postfix(double);
extern int signgam_nid_postfix;
float APS5_VABI logbf_nid_postfix(float);
int APS5_VABI ilogb_nid_postfix(double);
int APS5_VABI ilogbf_nid_postfix(float);
double APS5_VABI exp2_nid_postfix(double);
float APS5_VABI __powisf2_nid_postfix(float, int);
double APS5_VABI __powidf2_nid_postfix(double, int);
double APS5_VABI ldexp_nid_postfix(double, int);
double APS5_VABI scalbn_nid_postfix(double, int);
float APS5_VABI scalbnf_nid_postfix(float, int);
float APS5_VABI nextafterf_nid_postfix(float, float);
double APS5_VABI nextafter_nid_postfix(double, double);
double APS5_VABI frexp_nid_postfix(double, int*);
float APS5_VABI frexpf_nid_postfix(float, int*);
std::int64_t APS5_VABI lround_nid_postfix(double);
std::div_t APS5_VABI div_nid_postfix(int, int);
double APS5_VABI sinh_nid_postfix(double);
double APS5_VABI cosh_nid_postfix(double);
float APS5_VABI coshf_nid_postfix(float);
float APS5_VABI sinhf_nid_postfix(float);
double APS5_VABI asinh_nid_postfix(double);
float APS5_VABI asinhf_nid_postfix(float);
double APS5_VABI acosh_nid_postfix(double);
float APS5_VABI acoshf_nid_postfix(float);
double APS5_VABI atanh_nid_postfix(double);
float APS5_VABI atanhf_nid_postfix(float);
std::int64_t APS5_VABI lroundf_nid_postfix(float);
std::int64_t APS5_VABI llround_nid_postfix(double);
std::int64_t APS5_VABI llroundf_nid_postfix(float);
std::int64_t APS5_VABI llroundl_nid_postfix(long double);
int APS5_VABI __isfinitef_nid_postfix(float);
int APS5_VABI __isfinitel_nid_postfix(long double);
int APS5_VABI __isnormal_nid_postfix(double);
int APS5_VABI __isnormalf_nid_postfix(float);
int APS5_VABI __isinff_nid_postfix(float);
int APS5_VABI __isinf_nid_postfix(double);
int APS5_VABI isnan_nid_postfix(double);
int APS5_VABI isinf_nid_postfix(double);
std::lldiv_t APS5_VABI lldiv_nid_postfix(long long, long long);
std::lldiv_t APS5_VABI imaxdiv_nid_postfix(std::int64_t, std::int64_t);
std::int64_t APS5_VABI labs_nid_postfix(std::int64_t);
std::int64_t APS5_VABI llabs_nid_postfix(std::int64_t);
std::int64_t APS5_VABI imaxabs_nid_postfix(std::int64_t);
long double APS5_VABI scalbnl_nid_postfix(long double, int);
float APS5_VABI significandf_nid_postfix(float);
long double APS5_VABI acoshl_nid_postfix(long double);
long double APS5_VABI asinhl_nid_postfix(long double);
long double APS5_VABI atanhl_nid_postfix(long double);
long double APS5_VABI atan2l_nid_postfix(long double, long double);
long double APS5_VABI cbrtl_nid_postfix(long double);
long double APS5_VABI erfl_nid_postfix(long double);
long double APS5_VABI erfcl_nid_postfix(long double);
long double APS5_VABI expm1l_nid_postfix(long double);
long double APS5_VABI log1pl_nid_postfix(long double);
long double APS5_VABI log2l_nid_postfix(long double);
long double APS5_VABI lgammal_nid_postfix(long double);
long double APS5_VABI tgammal_nid_postfix(long double);
long double APS5_VABI hypotl_nid_postfix(long double, long double);
float APS5_VABI hypot3f_nid_postfix(float, float, float);
double APS5_VABI hypot3_nid_postfix(double, double, double);
long double APS5_VABI hypot3l_nid_postfix(long double, long double, long double);
float APS5_VABI j0f_nid_postfix(float);
float APS5_VABI j1f_nid_postfix(float);
float APS5_VABI jnf_nid_postfix(int, float);
float APS5_VABI y0f_nid_postfix(float);
float APS5_VABI y1f_nid_postfix(float);
float APS5_VABI ynf_nid_postfix(int, float);
std::lldiv_t APS5_VABI ldiv_nid_postfix(std::int64_t, std::int64_t);
float APS5_VABI nanf_nid_postfix(const char*);
double APS5_VABI nan_nid_postfix(const char*);
long double APS5_VABI atanl_nid_postfix(long double);
long double APS5_VABI sinl_nid_postfix(long double);
long double APS5_VABI cosl_nid_postfix(long double);
long double APS5_VABI tanl_nid_postfix(long double);
long double APS5_VABI sinhl_nid_postfix(long double);
long double APS5_VABI coshl_nid_postfix(long double);
long double APS5_VABI tanhl_nid_postfix(long double);
long double APS5_VABI expl_nid_postfix(long double);
long double APS5_VABI exp2l_nid_postfix(long double);
long double APS5_VABI logl_nid_postfix(long double);
long double APS5_VABI log10l_nid_postfix(long double);
long double APS5_VABI powl_nid_postfix(long double, long double);
long double APS5_VABI ldexpl_nid_postfix(long double, int);
long double APS5_VABI truncl_nid_postfix(long double);
long double APS5_VABI nearbyintl_nid_postfix(long double);
double APS5_VABI logb_nid_postfix(double);
double APS5_VABI remainder_nid_postfix(double, double);
}
static void Require(bool value) { if (!value) std::abort(); }
static void CheckSquareRoot() {
Require(sqrt_nid_postfix(4.) == 2. && sqrtf_nid_postfix(6.25f) == 2.5f);
Require(std::bit_cast<std::uint64_t>(sqrt_nid_postfix(2.)) == 0x3ff6a09e667f3bcdull);
Require(std::bit_cast<std::uint32_t>(sqrtf_nid_postfix(2.f)) == 0x3fb504f3u);
Require(std::bit_cast<std::uint64_t>(sqrt_nid_postfix(0x1p-1074)) == 0x1e60000000000000ull);
Require(std::bit_cast<std::uint64_t>(sqrt_nid_postfix(-0.)) == 0x8000000000000000ull);
Require(std::bit_cast<std::uint32_t>(sqrtf_nid_postfix(-0.f)) == 0x80000000u);
Require(sqrt_nid_postfix(INFINITY) == INFINITY && sqrtf_nid_postfix(INFINITY) == INFINITY);
Require(std::isnan(sqrt_nid_postfix(-1.)) && std::isnan(sqrtf_nid_postfix(-1.f)));
}
static void CheckExactOperations() {
const double nan = std::numeric_limits<double>::quiet_NaN();
Require(fabs_nid_postfix(-3.5) == 3.5 && fabs_nid_postfix(-INFINITY) == INFINITY);
Require(std::bit_cast<std::uint64_t>(fabs_nid_postfix(-0.)) == 0);
Require(std::isnan(fabs_nid_postfix(-nan)) && !std::signbit(fabs_nid_postfix(-nan)));
Require(fabsf_nid_postfix(-3.5f) == 3.5f && fabsf_nid_postfix(-INFINITY) == INFINITY);
Require(std::bit_cast<std::uint32_t>(fabsf_nid_postfix(-0.f)) == 0);
Require(std::isnan(fabsf_nid_postfix(-static_cast<float>(nan))) && !std::signbit(fabsf_nid_postfix(-static_cast<float>(nan))));
Require(fabsl_nid_postfix(-3.5L) == 3.5L && fabsl_nid_postfix(-INFINITY) == INFINITY);
Require(std::isnan(fabsl_nid_postfix(-static_cast<long double>(nan))) && !std::signbit(fabsl_nid_postfix(-static_cast<long double>(nan))));
Require(trunc_nid_postfix(2.7) == 2. && trunc_nid_postfix(-2.7) == -2.);
Require(std::bit_cast<std::uint64_t>(trunc_nid_postfix(-0.5)) == 0x8000000000000000ull);
Require(trunc_nid_postfix(4503599627370497.) == 4503599627370497. && trunc_nid_postfix(-1e300) == -1e300);
Require(trunc_nid_postfix(-INFINITY) == -INFINITY && std::isnan(trunc_nid_postfix(nan)));
Require(ceil_nid_postfix(2.2) == 3. && ceil_nid_postfix(-2.7) == -2. && ceil_nid_postfix(5.) == 5.);
Require(std::bit_cast<std::uint64_t>(ceil_nid_postfix(-0.5)) == 0x8000000000000000ull);
Require(std::bit_cast<std::uint64_t>(ceil_nid_postfix(-0.)) == 0x8000000000000000ull && ceil_nid_postfix(0x1p-1074) == 1.);
Require(ceil_nid_postfix(4503599627370495.5) == 4503599627370496. && ceil_nid_postfix(-1e300) == -1e300);
Require(ceil_nid_postfix(INFINITY) == INFINITY && ceil_nid_postfix(-INFINITY) == -INFINITY && std::isnan(ceil_nid_postfix(nan)));
Require(std::fesetround(FE_DOWNWARD) == 0);
const bool ceilIgnoresRounding = ceil_nid_postfix(2.2) == 3. && ceil_nid_postfix(-2.7) == -2.;
Require(std::fesetround(FE_TONEAREST) == 0 && ceilIgnoresRounding);
Require(floor_nid_postfix(2.7) == 2. && floor_nid_postfix(-2.2) == -3. && floor_nid_postfix(5.) == 5.);
Require(std::bit_cast<std::uint64_t>(floor_nid_postfix(-0.5)) == 0xbff0000000000000ull);
Require(std::bit_cast<std::uint64_t>(floor_nid_postfix(-0.)) == 0x8000000000000000ull && floor_nid_postfix(-0x1p-1074) == -1.);
Require(std::bit_cast<std::uint64_t>(floor_nid_postfix(0.5)) == 0);
Require(floor_nid_postfix(4503599627370495.5) == 4503599627370495. && floor_nid_postfix(-1e300) == -1e300);
Require(floor_nid_postfix(INFINITY) == INFINITY && floor_nid_postfix(-INFINITY) == -INFINITY && std::isnan(floor_nid_postfix(nan)));
Require(std::fesetround(FE_UPWARD) == 0);
const bool floorIgnoresRounding = floor_nid_postfix(2.7) == 2. && floor_nid_postfix(-2.2) == -3.;
Require(std::fesetround(FE_TONEAREST) == 0 && floorIgnoresRounding);
Require(fma_nid_postfix(2., 3., 4.) == 10.);
volatile double tenth = 0.1;
Require(fma_nid_postfix(tenth, 10., -1.) == 0x1p-54);
Require(fma_nid_postfix(0x1p1023, 2., -0x1p1023) == 0x1p1023);
Require(std::isnan(fma_nid_postfix(INFINITY, 0., 1.)));
Require(fdim_nid_postfix(4.0, 1.0) == 3.0 && fdim_nid_postfix(1.0, 4.0) == 0.0);
Require(fdim_nid_postfix(4.0, 4.0) == 0.0 && !std::signbit(fdim_nid_postfix(1.0, 4.0)));
Require(std::isnan(fdim_nid_postfix(std::numeric_limits<double>::quiet_NaN(), 1.0)));
Require(std::isnan(fdim_nid_postfix(1.0, std::numeric_limits<double>::quiet_NaN())));
Require(fdimf_nid_postfix(4.0f, 1.0f) == 3.0f && fdimf_nid_postfix(1.0f, 4.0f) == 0.0f);
Require(fdimf_nid_postfix(4.0f, 4.0f) == 0.0f && !std::signbit(fdimf_nid_postfix(1.0f, 4.0f)));
Require(std::isnan(fdimf_nid_postfix(std::numeric_limits<float>::quiet_NaN(), 1.0f)));
Require(fmaf_nid_postfix(2.f, 3.f, 4.f) == 10.f);
volatile float tenthFloat = 0.1f;
Require(fmaf_nid_postfix(tenthFloat, 10.f, -1.f) != 0.f);
Require(std::isnan(fmaf_nid_postfix(INFINITY, 0.f, 1.f)));
}
static void CheckNearbyint() {
std::feclearexcept(FE_ALL_EXCEPT);
const double zero = nearbyint_nid_postfix(0.5);
Require(zero == 0.0 && !std::signbit(zero));
Require(nearbyint_nid_postfix(1.5) == 2.0 && nearbyint_nid_postfix(2.5) == 2.0);
Require(nearbyint_nid_postfix(2.7) == 3.0 && nearbyint_nid_postfix(-2.7) == -3.0);
Require(std::bit_cast<std::uint64_t>(nearbyint_nid_postfix(-0.5)) == 0x8000000000000000ull);
Require(nearbyint_nid_postfix(0x1p53) == 0x1p53);
Require(nearbyint_nid_postfix(INFINITY) == INFINITY && nearbyint_nid_postfix(-INFINITY) == -INFINITY);
Require(std::isnan(nearbyint_nid_postfix(NAN)));
Require(std::fetestexcept(FE_INEXACT) == 0);
}
static std::uint16_t X87ControlWord() {
std::uint16_t control;
asm volatile("fnstcw %0" : "=m"(control));
return control;
}
static std::uint16_t X87StatusWord() {
std::uint16_t status;
asm volatile("fnstsw %0" : "=m"(status));
return status;
}
static void CheckFegetenv() {
const std::uint16_t savedControl = X87ControlWord();
const unsigned savedCsr = _mm_getcsr();
const std::uint16_t control = 0x0f7e;
const unsigned csr = 0x7fa0;
asm volatile("fnclex");
asm volatile("fldcw %0" : : "m"(control));
_mm_setcsr(csr);
volatile long double zero = 0.0L;
volatile long double quotient = 1.0L / zero;
(void)quotient;
const std::uint16_t status = X87StatusWord();
Require((status & 0x04) != 0 && (status & 0x01) == 0);
GuestFloatingPointEnvironment environment;
std::memset(&environment, 0xcc, sizeof(environment));
Require(fegetenv_nid_postfix(&environment) == 0);
const std::uint16_t controlAfter = X87ControlWord();
const unsigned csrAfter = _mm_getcsr();
asm volatile("fnclex");
asm volatile("fldcw %0" : : "m"(savedControl));
_mm_setcsr(savedCsr);
Require((environment.control & 0xffff) == control);
Require((environment.status & 0xffff) == status);
Require(environment.mxcsr == csr);
Require(controlAfter == control);
Require(csrAfter == csr);
bool threw = false;
try { fegetenv_nid_postfix(nullptr); } catch (...) { threw = true; }
Require(threw);
}
static bool ExtendedBits(long double value, std::uint64_t mantissa, std::uint16_t signExponent) {
unsigned char bytes[sizeof(long double)]{};
std::memcpy(bytes, &value, sizeof(value));
std::uint64_t actualMantissa = 0;
std::uint16_t actualSignExponent = 0;
std::memcpy(&actualMantissa, bytes, 8);
std::memcpy(&actualSignExponent, bytes + 8, 2);
return actualMantissa == mantissa && actualSignExponent == signExponent;
}
static void CheckNanConversions() {
const struct { const char* text; std::size_t consumed; bool negative; } cases[] = {
{"nan(0x123)", 10, false}, {" -NaN(1)!", 8, true}, {"nan(0x800000)", 13, false},
{"nan(0x10000000000000)", 21, false}, {"nan(0x8000000000000000)", 23, false},
};
bool correct = true;
for (const auto& test : cases) {
const char* expectedEnd = test.text + test.consumed;
const std::uint64_t expectedDouble = test.negative ? 0xfff8000000000000ull : 0x7ff8000000000000ull;
char* end = nullptr;
const auto value = std::bit_cast<std::uint64_t>(strtod_nid_postfix(test.text, &end));
if (value != expectedDouble || end != expectedEnd) {
std::fprintf(stderr, "strtod(\"%s\") = 0x%016llx\n", test.text, static_cast<unsigned long long>(value));
correct = false;
}
const auto ascii = std::bit_cast<std::uint64_t>(atof_nid_postfix(test.text));
if (ascii != expectedDouble) {
std::fprintf(stderr, "atof(\"%s\") = 0x%016llx\n", test.text, static_cast<unsigned long long>(ascii));
correct = false;
}
const auto single = std::bit_cast<std::uint32_t>(strtof_nid_postfix(test.text, &end));
if (single != (test.negative ? 0xffc00000u : 0x7fc00000u) || end != expectedEnd) {
std::fprintf(stderr, "strtof(\"%s\") = 0x%08x\n", test.text, static_cast<unsigned>(single));
correct = false;
}
const long double extended = strtold_nid_postfix(test.text, &end);
if (!ExtendedBits(extended, 0xc000000000000000ull, test.negative ? 0xffff : 0x7fff) || end != expectedEnd) {
std::uint64_t significand = 0;
std::uint16_t signExponent = 0;
std::memcpy(&significand, &extended, sizeof(significand));
std::memcpy(&signExponent, reinterpret_cast<const unsigned char*>(&extended) + sizeof(significand), sizeof(signExponent));
std::fprintf(stderr, "strtold(\"%s\") = 0x%04x'%016llx\n", test.text, static_cast<unsigned>(signExponent),
static_cast<unsigned long long>(significand));
correct = false;
}
}
Require(correct);
}
static void CheckHypotSpecialValue() {
Require(std::bit_cast<std::uint64_t>(hypot_nid_postfix(INFINITY, std::bit_cast<double>(0x7ff0000000000001ull))) == 0x7ff0000000000000ull);
Require(std::bit_cast<std::uint64_t>(hypot_nid_postfix(std::bit_cast<double>(0x7ff0000000000001ull), INFINITY)) == 0x7ff0000000000000ull);
Require(std::bit_cast<std::uint64_t>(hypot_nid_postfix(-INFINITY, std::bit_cast<double>(0x7ff0000000000001ull))) == 0x7ff0000000000000ull);
Require(std::bit_cast<std::uint64_t>(hypot_nid_postfix(std::bit_cast<double>(0x7ff0000000000001ull), -INFINITY)) == 0x7ff0000000000000ull);
}
static void CheckAsinfErrno() {
errno = 0;
(void)asinf_nid_postfix(2.0f);
Require(errno == 0);
}
static void CheckExp2Errno() {
errno = 0;
std::feclearexcept(FE_ALL_EXCEPT);
double result = exp2_nid_postfix(1024.0);
Require(errno == 0);
Require(std::isinf(result) && result > 0);
Require(std::fetestexcept(FE_OVERFLOW | FE_INEXACT) == (FE_OVERFLOW | FE_INEXACT));
}
static void CheckPowfSpecialValue() {
Require(std::bit_cast<std::uint32_t>(powf_nid_postfix(1.0f, std::bit_cast<float>(0x7f800001u))) == 0x3f800000u);
}
static void CheckAcosfErrno() {
errno = 0;
Require(std::bit_cast<std::uint32_t>(acosf_nid_postfix(2.0f)) == 0xffc00000u);
Require(errno == 0);
Require(std::bit_cast<std::uint32_t>(acosf_nid_postfix(-2.0f)) == 0xffc00000u);
Require(errno == 0);
Require(std::bit_cast<std::uint32_t>(acosf_nid_postfix(0.5f)) == 0x3f860a92u);
Require(errno == 0);
}
static void CheckLongDouble() {
Require(ExtendedBits(acosl_nid_postfix(-1.0L), 0xc90fdaa22168c235ull, 0x4000));
Require(ExtendedBits(acosl_nid_postfix(0.0L), 0xc90fdaa22168c235ull, 0x3fff));
Require(ExtendedBits(acosl_nid_postfix(1.0L), 0, 0));
Require(std::isnan(acosl_nid_postfix(1.5L)) && std::isnan(acosl_nid_postfix(-2.0L)));
int exponent = 77;
Require(frexpl_nid_postfix(8.0L, &exponent) == 0.5L && exponent == 4);
Require(frexpl_nid_postfix(-3.0L, &exponent) == -0.75L && exponent == 2);
Require(frexpl_nid_postfix(0.375L, &exponent) == 0.75L && exponent == -1);
long double smallest = 0;
const std::uint64_t one = 1;
std::memcpy(&smallest, &one, sizeof(one));
Require(ExtendedBits(frexpl_nid_postfix(smallest, &exponent), 0x8000000000000000ull, 0x3ffe) && exponent == -16444);
exponent = 77;
Require(ExtendedBits(frexpl_nid_postfix(-0.0L, &exponent), 0, 0x8000) && exponent == 0);
exponent = 77;
Require(frexpl_nid_postfix(INFINITY, &exponent) == INFINITY && exponent == 77);
Require(frexpl_nid_postfix(-INFINITY, &exponent) == -INFINITY && exponent == 77);
Require(std::isnan(frexpl_nid_postfix(NAN, &exponent)) && exponent == 77);
Require(ceill_nid_postfix(2.2L) == 3.0L && ceill_nid_postfix(-2.7L) == -2.0L);
Require(floorl_nid_postfix(2.7L) == 2.0L && floorl_nid_postfix(-2.2L) == -3.0L);
Require(ceill_nid_postfix(2.0L) == 2.0L && floorl_nid_postfix(-2.0L) == -2.0L);
Require(std::isnan(ceill_nid_postfix(NAN)) && std::isnan(floorl_nid_postfix(NAN)));
}
static void CheckNearbyintl() {
std::feclearexcept(FE_ALL_EXCEPT);
const long double zero = nearbyintl_nid_postfix(0.5L);
Require(zero == 0.0L && !std::signbit(zero));
Require(nearbyintl_nid_postfix(1.5L) == 2.0L && nearbyintl_nid_postfix(2.5L) == 2.0L);
Require(nearbyintl_nid_postfix(2.7L) == 3.0L && nearbyintl_nid_postfix(-2.7L) == -3.0L);
Require(ExtendedBits(nearbyintl_nid_postfix(-0.5L), 0, 0x8000));
Require(nearbyintl_nid_postfix(0x1p200L) == 0x1p200L);
Require(nearbyintl_nid_postfix(INFINITY) == INFINITY && nearbyintl_nid_postfix(-INFINITY) == -INFINITY);
Require(std::isnan(nearbyintl_nid_postfix(NAN)));
Require(std::fetestexcept(FE_INEXACT) == 0);
}
static void CheckFmodErrno() {
errno = 0;
(void)fmod_nid_postfix(1.0, 0.0);
Require(errno == 0);
Require(fmod_nid_postfix(1e300, 3.0) == std::fmod(1e300, 3.0));
}
static long double MakeExtended(std::uint64_t mantissa, std::uint16_t signExponent) {
unsigned char bytes[sizeof(long double)]{};
std::memcpy(bytes, &mantissa, 8);
std::memcpy(bytes + 8, &signExponent, 2);
long double value = 0;
std::memcpy(&value, bytes, sizeof(value));
return value;
}
static void CheckAsinl() {
const struct { std::uint64_t inputMantissa; std::uint16_t inputSignExponent; std::uint64_t outputMantissa; std::uint16_t outputSignExponent; } cases[] = {
{0, 0x0000, 0, 0x0000}, {0, 0x8000, 0, 0x8000},
{0x8000000000000000ull, 0x3fd7, 0x8000000000000000ull, 0x3fd7}, {0x8000000000000000ull, 0xbfd7, 0x8000000000000000ull, 0xbfd7},
{0x8000000000000000ull, 0x3ffd, 0x815f4e705c3e68f3ull, 0x3ffd}, {0x8000000000000000ull, 0xbffd, 0x815f4e705c3e68f3ull, 0xbffd},
{0xcccccccccccccccdull, 0x3ffb, 0xcd2493b01bc41e02ull, 0x3ffb},
{0x8000000000000000ull, 0x3ffe, 0x860a91c16b9b2c23ull, 0x3ffe}, {0x8000000000000000ull, 0xbffe, 0x860a91c16b9b2c23ull, 0xbffe},
{0xc000000000000000ull, 0xbffe, 0xd91a98ae3406e041ull, 0xbffe}, {0xe666666666666666ull, 0x3ffe, 0x8f549b82fd0b8fa3ull, 0x3fff},
{0xf333333333333333ull, 0x3ffe, 0xa06a08acf9a04f78ull, 0x3fff}, {0xfd70a3d70a3d70a4ull, 0xbffe, 0xb6f1e3799ea8ecc3ull, 0xbfff},
{0xffffffffffffffffull, 0x3ffe, 0xc90fdaa16c63cf01ull, 0x3fff},
{0x8000000000000000ull, 0x3fff, 0xc90fdaa22168c235ull, 0x3fff}, {0x8000000000000000ull, 0xbfff, 0xc90fdaa22168c235ull, 0xbfff},
};
for (const auto& test : cases) {
*__error_nid_postfix() = 12345;
const long double result = asinl_nid_postfix(MakeExtended(test.inputMantissa, test.inputSignExponent));
if (!ExtendedBits(result, test.outputMantissa, test.outputSignExponent) || *__error_nid_postfix() != 12345) {
std::fprintf(stderr, "Guest asinl failed for %016llx:%04x\n", static_cast<unsigned long long>(test.inputMantissa), test.inputSignExponent);
std::abort();
}
}
Require(std::fabs(asinl_nid_postfix(0.5L) - 0.523598775598298873077107230547L) <= 0x1p-64L);
const long double domainErrors[] = {
1.5L, -2.0L, MakeExtended(0x8000000000000001ull, 0x3fff), MakeExtended(0x8000000000000001ull, 0xbfff),
std::numeric_limits<long double>::max(), std::numeric_limits<long double>::infinity(), -std::numeric_limits<long double>::infinity(),
std::numeric_limits<long double>::quiet_NaN(),
};
for (const long double input : domainErrors) {
std::feclearexcept(FE_ALL_EXCEPT);
*__error_nid_postfix() = 0;
Require(std::isnan(asinl_nid_postfix(input)) && *__error_nid_postfix() == EDOM && std::fetestexcept(FE_INVALID) != 0);
}
*__error_nid_postfix() = 0;
}
static void CheckIntegerConversions() {
for (const long long numerator : {4294967301LL, -4294967301LL}) {
for (const long long denominator : {3LL, -3LL}) {
const auto result = lldiv_nid_postfix(numerator, denominator);
Require(result.quot == numerator / denominator && result.rem == numerator % denominator);
Require(result.quot * denominator + result.rem == numerator);
const auto wide = ldiv_nid_postfix(numerator, denominator);
Require(wide.quot == result.quot && wide.rem == result.rem);
}
}
const auto extreme = ldiv_nid_postfix(INT64_MIN, 2);
Require(extreme.quot == INT64_MIN / 2 && extreme.rem == 0);
struct SignedCase {
const char* text;
int base;
std::int64_t value;
std::size_t consumed;
int error;
};
const SignedCase signedCases[] = {
{"-42tail", 10, -42, 3, 0},
{"2147483648!", 10, INT64_C(2147483648), 10, 0},
{"-2147483649!", 10, -INT64_C(2147483649), 11, 0},
{"4294967296!", 10, INT64_C(4294967296), 10, 0},
{"9223372036854775807!", 10, INT64_MAX, 19, 0},
{"-9223372036854775808!", 10, INT64_MIN, 20, 0},
{"9223372036854775808!", 10, INT64_MAX, 19, 34},
{"-9223372036854775809!", 10, INT64_MIN, 20, 34},
{"18446744073709551616000!", 10, INT64_MAX, 23, 34},
{" \t+0x100000000z", 0, INT64_C(4294967296), 14, 0},
{"-0x8000000000000000!", 0, INT64_MIN, 19, 0},
{"0x8000000000000000!", 16, INT64_MAX, 18, 34},
{"0100000000000!", 0, INT64_C(8589934592), 13, 0},
{"100000000000000000000000000000000!", 2, INT64_C(4294967296), 33, 0},
{"0b101", 0, 0, 1, 0},
{"0b101", 2, 0, 1, 0},
{" -0B1!", 0, 0, 3, 0},
{"0b2", 0, 0, 1, 0},
{"0b101", 16, 0xb101, 5, 0},
{" -0xz!", 0, 0, 3, 0},
{"0xg", 16, 0, 1, 0},
{"0x", 16, 0, 1, 0},
{"z!", 36, 35, 1, 0},
{"", 10, 0, 0, 0},
{" \t+!", 10, 0, 0, 0},
{"123!", 10, 123, 3, 0}
};
for (const auto& test : signedCases) {
char* end = nullptr;
*__error_nid_postfix() = 0;
const auto value = strtol_nid_postfix(test.text, &end, test.base);
if (value != test.value || end != test.text + test.consumed || *__error_nid_postfix() != test.error) {
std::fprintf(stderr, "Guest strtol failed for '%s' in base %d\n", test.text, test.base);
std::abort();
}
*__error_nid_postfix() = 0;
const auto maxValue = strtoimax_nid_postfix(test.text, &end, test.base);
if (maxValue != test.value || end != test.text + test.consumed || *__error_nid_postfix() != test.error) {
std::fprintf(stderr, "Guest strtoimax failed for '%s' in base %d\n", test.text, test.base);
std::abort();
}
}
struct UnsignedCase {
const char* text;
int base;
std::uint64_t value;
std::size_t consumed;
int error;
};
const UnsignedCase unsignedCases[] = {
{"4294967296!", 10, UINT64_C(4294967296), 10, 0},
{"9223372036854775808!", 10, UINT64_C(9223372036854775808), 19, 0},
{"18446744073709551615!", 10, UINT64_MAX, 20, 0},
{"18446744073709551616!", 10, UINT64_MAX, 20, 34},
{"18446744073709551616000!", 10, UINT64_MAX, 23, 34},
{"-1!", 10, UINT64_MAX, 2, 0},
{"-4294967296!", 10, UINT64_MAX - UINT64_C(4294967295), 11, 0},
{"-18446744073709551615!", 10, 1, 21, 0},
{"-18446744073709551616!", 10, UINT64_MAX, 21, 34},
{" \t+0xffffffffffffffffz", 0, UINT64_MAX, 21, 0},
{"0x10000000000000000!", 16, UINT64_MAX, 19, 34},
{"0100000000000!", 0, UINT64_C(8589934592), 13, 0},
{"100000000000000000000000000000000!", 2, UINT64_C(4294967296), 33, 0},
{"0b101", 0, 0, 1, 0},
{"0B11", 2, 0, 1, 0},
{" +0b1!", 2, 0, 3, 0},
{"0b101", 16, 0xb101, 5, 0},
{" +0Xg!", 0, 0, 3, 0},
{"0x!", 16, 0, 1, 0},
{"z!", 36, 35, 1, 0},
{"", 10, 0, 0, 0},
{" \t-!", 10, 0, 0, 0},
{"123!", 10, 123, 3, 0}
};
for (const auto& test : unsignedCases) {
char* end = nullptr;
*__error_nid_postfix() = 0;
const auto value = strtoul_nid_postfix(test.text, &end, test.base);
if (value != test.value || end != test.text + test.consumed || *__error_nid_postfix() != test.error) {
std::fprintf(stderr, "Guest strtoul failed for '%s' in base %d\n", test.text, test.base);
std::abort();
}
}
for (const int base : {0, 2}) {
const char text[] = " -0B11";
char* end = nullptr;
Require(strtoll_nid_postfix(text, &end, base) == 0 && end == text + 3);
Require(strtoull_nid_postfix(text, &end, base) == 0 && end == text + 3);
Require(strtoumax_nid_postfix(text, &end, base) == 0 && end == text + 3);
Require(_Stoull_nid_postfix(text, &end, base) == 0 && end == text + 3);
Require(_Stoul_nid_postfix(text, &end, base) == 0 && end == text + 3);
}
Require(atol_nid_postfix(" \t-4294967296tail") == -INT64_C(4294967296));
Require(atol_nid_postfix("9223372036854775807") == INT64_MAX && atol_nid_postfix("+12") == 12);
Require(atol_nid_postfix("0x10") == 0 && atol_nid_postfix("010") == 10 && atol_nid_postfix("") == 0);
Require(atoll_nid_postfix("-9223372036854775808") == INT64_MIN && atoll_nid_postfix("4294967297x") == 4294967297LL);
Require(atoll_nid_postfix(" -0012") == -12 && atoll_nid_postfix("z1") == 0);
*__error_nid_postfix() = 13;
Require(strtol_nid_postfix("-4294967296", nullptr, 10) == -INT64_C(4294967296));
Require(*__error_nid_postfix() == 13);
Require(strtoul_nid_postfix("4294967296", nullptr, 10) == UINT64_C(4294967296));
Require(*__error_nid_postfix() == 13);
Require(_Stoul_nid_postfix("4294967296", nullptr, 10) == UINT64_C(4294967296));
Require(*__error_nid_postfix() == 13);
Require(_Stoul_nid_postfix("18446744073709551615", nullptr, 10) == UINT64_MAX);
Require(_Stoul_nid_postfix("-1", nullptr, 10) == UINT64_MAX && *__error_nid_postfix() == 13);
*__error_nid_postfix() = 0;
}
static bool Near(double value, double expected, double tolerance) { return std::abs(value - expected) <= tolerance * std::abs(expected); }
static void CheckAsin() {
const double pi = 3.14159265358979323846;
const double pi_2 = pi / 2;
const double nan = std::numeric_limits<double>::quiet_NaN();
const double infinity = std::numeric_limits<double>::infinity();
Require(asin_nid_postfix(0.) == 0.);
Require(std::signbit(asin_nid_postfix(-0.)));
Require(Near(asin_nid_postfix(1.), pi_2, 1e-15));
Require(Near(asin_nid_postfix(-1.), -pi_2, 1e-15));
Require(std::isnan(asin_nid_postfix(2.0)) && std::signbit(asin_nid_postfix(2.0)));
Require(std::isnan(asin_nid_postfix(-2.0)) && std::signbit(asin_nid_postfix(-2.0)));
Require(std::isnan(asin_nid_postfix(infinity)) && std::signbit(asin_nid_postfix(infinity)));
Require(std::isnan(asin_nid_postfix(-infinity)) && std::signbit(asin_nid_postfix(-infinity)));
Require(std::isnan(asin_nid_postfix(nan)));
Require(Near(asin_nid_postfix(0.5), pi/6, 1e-15));
Require(Near(asin_nid_postfix(-0.5), -pi/6, 1e-15));
Require(Near(asin_nid_postfix(1./std::sqrt(2)), pi/4, 1e-15));
Require(asin_nid_postfix(1e-300) == 1e-300);
Require(asin_nid_postfix(-1e-300) == -1e-300);
std::feclearexcept(FE_ALL_EXCEPT);
errno = 0;
asin_nid_postfix(2.0);
Require(std::fetestexcept(FE_INVALID));
Require(errno == 0);
std::feclearexcept(FE_ALL_EXCEPT);
asin_nid_postfix(nan);
Require(!std::fetestexcept(FE_INVALID));
}
static void CheckExtendedMath() {
Require(ExtendedBits(atanl_nid_postfix(INFINITY), 0xc90fdaa22168c235ull, 0x3fff));
Require(std::fabs(atanl_nid_postfix(1.0L) - 0.785398163397448309616L) < 1e-18L);
Require(std::fabs(sinl_nid_postfix(0.5L) - 0.479425538604203000273L) < 1e-18L);
Require(std::fabs(cosl_nid_postfix(0.5L) - 0.877582561890372716116L) < 1e-18L);
Require(std::fabs(tanl_nid_postfix(0.5L) - 0.546302489843790513255L) < 1e-18L);
Require(std::fabs(sinhl_nid_postfix(1.0L) - 1.17520119364380145688L) < 1e-18L);
Require(std::fabs(coshl_nid_postfix(1.0L) - 1.54308063481524377848L) < 1e-18L);
Require(std::fabs(tanhl_nid_postfix(0.5L) - 0.462117157260009758502L) < 1e-18L);
Require(std::fabs(expl_nid_postfix(1.0L) - 2.71828182845904523536L) < 1e-18L);
Require(std::fabs(logl_nid_postfix(2.0L) - 0.693147180559945309417L) < 1e-18L);
Require(sinl_nid_postfix(0.0L) == 0.0L && std::signbit(sinl_nid_postfix(-0.0L)) && cosl_nid_postfix(0.0L) == 1.0L);
Require(std::isnan(sinl_nid_postfix(INFINITY)) && std::isnan(cosl_nid_postfix(-INFINITY)) && std::isnan(tanl_nid_postfix(INFINITY)));
Require(sinhl_nid_postfix(-INFINITY) == -INFINITY && coshl_nid_postfix(-INFINITY) == INFINITY && tanhl_nid_postfix(INFINITY) == 1.0L);
Require(sinhl_nid_postfix(11358.0L) == INFINITY && std::isfinite(sinhl_nid_postfix(11356.0L)) && std::isfinite(coshl_nid_postfix(11356.0L)));
Require(expl_nid_postfix(0.0L) == 1.0L && expl_nid_postfix(-INFINITY) == 0.0L && expl_nid_postfix(11357.0L) == INFINITY);
Require(exp2l_nid_postfix(10.0L) == 1024.0L && exp2l_nid_postfix(-16446.0L) == 0.0L && exp2l_nid_postfix(16384.0L) == INFINITY);
Require(ExtendedBits(exp2l_nid_postfix(-16445.0L), 1, 0) && ExtendedBits(exp2l_nid_postfix(-16444.0L), 2, 0));
Require(logl_nid_postfix(1.0L) == 0.0L && logl_nid_postfix(0.0L) == -INFINITY && std::isnan(logl_nid_postfix(-1.0L)));
Require(std::fabs(log10l_nid_postfix(1000.0L) - 3.0L) < 1e-18L && log10l_nid_postfix(1.0L) == 0.0L);
Require(log10l_nid_postfix(0.0L) == -INFINITY && std::isnan(log10l_nid_postfix(-1.0L)));
Require(powl_nid_postfix(2.0L, 64.0L) == 18446744073709551616.0L && powl_nid_postfix(-2.0L, 3.0L) == -8.0L);
Require(powl_nid_postfix(0.0L, -1.0L) == INFINITY && powl_nid_postfix(1.0L, NAN) == 1.0L && std::isnan(powl_nid_postfix(-2.0L, 0.5L)));
Require(ldexpl_nid_postfix(1.0L, 16383) == 0x1p16383L && ldexpl_nid_postfix(1.0L, 16384) == INFINITY && ldexpl_nid_postfix(3.0L, -2) == 0.75L);
Require(ExtendedBits(ldexpl_nid_postfix(1.0L, -16445), 1, 0) && ldexpl_nid_postfix(1.0L, -16446) == 0.0L);
Require(truncl_nid_postfix(2.7L) == 2.0L && truncl_nid_postfix(-2.7L) == -2.0L && ExtendedBits(truncl_nid_postfix(-0.5L), 0, 0x8000));
Require(truncl_nid_postfix(9223372036854775807.5L) == 9223372036854775807.0L && truncl_nid_postfix(-INFINITY) == -INFINITY);
Require(logb_nid_postfix(8.0) == 3.0 && logb_nid_postfix(0.75) == -1.0 && logb_nid_postfix(0x1p-1074) == -1074.0);
Require(logb_nid_postfix(0.0) == -INFINITY && logb_nid_postfix(-INFINITY) == INFINITY && std::isnan(logb_nid_postfix(NAN)));
Require(remainder_nid_postfix(5.0, 3.0) == -1.0 && remainder_nid_postfix(7.0, 2.0) == -1.0 && remainder_nid_postfix(5.0, 2.0) == 1.0);
Require(std::signbit(remainder_nid_postfix(-4.0, 2.0)) && remainder_nid_postfix(1.0, INFINITY) == 1.0);
Require(std::isnan(remainder_nid_postfix(1.0, 0.0)) && std::isnan(remainder_nid_postfix(INFINITY, 1.0)));
}
static void CheckHyperbolic() {
const double infinity = std::numeric_limits<double>::infinity();
Require(sinh_nid_postfix(0.) == 0. && std::signbit(sinh_nid_postfix(-0.)));
Require(cosh_nid_postfix(0.) == 1. && coshf_nid_postfix(0.f) == 1.f);
Require(asinh_nid_postfix(0.) == 0. && std::signbit(asinh_nid_postfix(-0.)) && std::signbit(asinhf_nid_postfix(-0.f)));
Require(acosh_nid_postfix(1.) == 0. && acoshf_nid_postfix(1.f) == 0.f);
Require(atanh_nid_postfix(0.) == 0. && atanh_nid_postfix(1.) == infinity && atanh_nid_postfix(-1.) == -infinity);
Require(std::isnan(acosh_nid_postfix(0.5)) && std::isnan(acoshf_nid_postfix(0.5f)) && std::isnan(atanh_nid_postfix(2.)));
Require(Near(sinh_nid_postfix(1.), 1.1752011936438014, 1e-15));
Require(Near(cosh_nid_postfix(1.), 1.5430806348152437, 1e-15));
Require(Near(coshf_nid_postfix(1.f), 1.5430806348152437, 1e-6));
Require(Near(asinh_nid_postfix(1.), 0.881373587019543, 1e-15));
Require(Near(asinhf_nid_postfix(1.f), 0.881373587019543, 1e-6));
Require(Near(acosh_nid_postfix(2.), 1.3169578969248166, 1e-15));
Require(Near(acoshf_nid_postfix(2.f), 1.3169578969248166, 1e-6));
Require(Near(atanh_nid_postfix(0.5), 0.5493061443340549, 1e-15));
Require(sinh_nid_postfix(1e-300) == 1e-300 && asinh_nid_postfix(1e-300) == 1e-300 && atanh_nid_postfix(1e-300) == 1e-300);
Require(std::isfinite(cosh_nid_postfix(710.4)) && std::isfinite(sinh_nid_postfix(-710.4)) && sinh_nid_postfix(-710.4) < 0.);
Require(Near(asinh_nid_postfix(-1e300), -691.4686750787736, 1e-15));
Require(Near(acosh_nid_postfix(1e300), 691.4686750787736, 1e-15));
}
static void CheckSinhf() {
const float infinity = std::numeric_limits<float>::infinity();
const struct { std::uint32_t input; std::uint32_t output; } cases[] = {
{0x00000000u, 0x00000000u}, {0x80000000u, 0x80000000u}, {0x00000001u, 0x00000001u}, {0x39000000u, 0x39000000u},
{0x3e800000u, 0x3e815667u}, {0xbf000000u, 0xbf056680u}, {0x3f800000u, 0x3f966cfeu}, {0xbf800000u, 0xbf966cfeu},
{0x40000000u, 0x40681e7bu}, {0x41100000u, 0x457d38acu}, {0xc1a00000u, 0xcd675844u}, {0x42b17217u, 0x7effff84u},
{0x42b20000u, 0x7f28e166u}, {0xc2b20000u, 0xff28e166u}, {0x42b2d4fcu, 0x7f7fffecu},
{0x7f800000u, 0x7f800000u}, {0xff800000u, 0xff800000u},
};
for (const auto& test : cases) {
*__error_nid_postfix() = 12345;
const float result = sinhf_nid_postfix(std::bit_cast<float>(test.input));
if (std::bit_cast<std::uint32_t>(result) != test.output || *__error_nid_postfix() != 12345) {
std::fprintf(stderr, "Guest sinhf failed for %08x\n", test.input);
std::abort();
}
}
Require(std::isnan(sinhf_nid_postfix(std::numeric_limits<float>::quiet_NaN())) && *__error_nid_postfix() == 12345);
Require(Near(sinhf_nid_postfix(1.f), 1.1752011936438014, 1e-6) && Near(sinhf_nid_postfix(-2.f), -3.626860407847019, 1e-6));
Require(Near(sinhf_nid_postfix(0.25f), 0.25261231680816831, 1e-6) && Near(sinhf_nid_postfix(20.f), 242582597.70489514, 1e-6));
for (const std::uint32_t input : {0x42b2d4fdu, 0x42c80000u, 0x7f7fffffu}) {
for (const std::uint32_t sign : {0u, 0x80000000u}) {
std::feclearexcept(FE_ALL_EXCEPT);
*__error_nid_postfix() = 0;
const float result = sinhf_nid_postfix(std::bit_cast<float>(input | sign));
Require(result == (sign != 0 ? -infinity : infinity) && *__error_nid_postfix() == ERANGE);
Require(std::fetestexcept(FE_OVERFLOW) != 0);
}
}
*__error_nid_postfix() = 0;
}
static void CheckAtanhf() {
const struct { std::uint32_t input; std::uint32_t output; } cases[] = {
{0x00000000u, 0x00000000u}, {0x80000000u, 0x80000000u}, {0x00000001u, 0x00000001u}, {0x0da24260u, 0x0da24260u},
{0x31000000u, 0x31000000u}, {0xb1000000u, 0xb1000000u}, {0x31800000u, 0x31800000u}, {0x35800000u, 0x35800000u},
{0x3dcccccdu, 0x3dcd7c9eu}, {0x3e800000u, 0x3e82c578u}, {0xbe800000u, 0xbe82c578u}, {0x3eaaaaaau, 0x3eb17217u},
{0x3eaaaaabu, 0x3eb17218u}, {0x3effffffu, 0x3f0c9f53u}, {0x3f000000u, 0x3f0c9f54u}, {0xbf000000u, 0xbf0c9f54u},
{0x3f199999u, 0x3f317217u}, {0x3f19999au, 0x3f317218u}, {0x3f400000u, 0x3f791396u}, {0xbf400000u, 0xbf791396u},
{0x3f666666u, 0x3fbc71afu}, {0x3f7fffffu, 0x410aa123u}, {0xbf7fffffu, 0xc10aa123u},
};
for (const auto& test : cases) {
*__error_nid_postfix() = 12345;
const float result = atanhf_nid_postfix(std::bit_cast<float>(test.input));
if (std::bit_cast<std::uint32_t>(result) != test.output || *__error_nid_postfix() != 12345) {
std::fprintf(stderr, "Guest atanhf failed for %08x\n", test.input);
std::abort();
}
}
for (const std::uint32_t input : {0x3f800000u, 0xbf800000u}) {
std::feclearexcept(FE_ALL_EXCEPT);
*__error_nid_postfix() = 0;
const float result = atanhf_nid_postfix(std::bit_cast<float>(input));
Require(std::bit_cast<std::uint32_t>(result) == (input | 0x7f800000u) && *__error_nid_postfix() == ERANGE);
Require(std::fetestexcept(FE_DIVBYZERO) != 0);
}
for (const std::uint32_t input : {0x3f800001u, 0xbf800001u, 0x3fc00000u, 0xbfc00000u, 0x7f7fffffu, 0x7f800000u, 0xff800000u, 0x7fc00000u, 0xffc00000u}) {
std::feclearexcept(FE_ALL_EXCEPT);
*__error_nid_postfix() = 0;
Require(std::isnan(atanhf_nid_postfix(std::bit_cast<float>(input))) && *__error_nid_postfix() == EDOM);
Require(std::fetestexcept(FE_INVALID) != 0);
}
*__error_nid_postfix() = 0;
}
static void CheckFloatClassification() {
Require(_FInf_nid_postfix.bits[0] == 0x7f800000u && _FNan_nid_postfix.bits[0] == 0x7fc00000u);
for (int word = 1; word < 4; ++word) Require(_FInf_nid_postfix.bits[word] == 0 && _FNan_nid_postfix.bits[word] == 0);
const struct { std::uint32_t bits; short code; } cases[] = {
{0x00000000u, 0}, {0x80000000u, 0}, {0x00000001u, -2}, {0x807fffffu, -2}, {0x00800000u, -1},
{0xbf800000u, -1}, {0x7f7fffffu, -1}, {0x7f800000u, 1}, {0xff800000u, 1}, {0x7f800001u, 2},
{0x7fc00000u, 2}, {0xff810000u, 2}, {0x7f810000u, 2},
};
for (const auto& test : cases) {
float value;
std::memcpy(&value, &test.bits, sizeof(value));
if (_FDtest_nid_postfix(&value) != test.code) {
std::fprintf(stderr, "Guest _FDtest failed for %08x\n", test.bits);
std::abort();
}
const int fpclass = test.code == 0 ? 0x10 : test.code == -2 ? 0x08 : test.code == -1 ? 0x04 : test.code == 1 ? 0x01 : 0x02;
if (__fpclassifyf_nid_postfix(value) != fpclass) {
std::fprintf(stderr, "Guest __fpclassifyf failed for %08x\n", test.bits);
std::abort();
}
}
Require(_FDtest_nid_postfix(reinterpret_cast<const float*>(&_FInf_nid_postfix)) == 1);
Require(_FDtest_nid_postfix(reinterpret_cast<const float*>(&_FNan_nid_postfix)) == 2);
}
static void CheckMissingClassificationExports() {
const float infinity = std::numeric_limits<float>::infinity();
const float nan = std::numeric_limits<float>::quiet_NaN();
Require(isnanf_nid_postfix(nan) == 1);
Require(isnanf_nid_postfix(infinity) == 0 && isnanf_nid_postfix(-infinity) == 0);
Require(isnanf_nid_postfix(0.f) == 0 && isnanf_nid_postfix(-1.f) == 0);
const long double negativeNan = std::copysign(std::numeric_limits<long double>::quiet_NaN(), -1.L);
Require(__signbitl_nid_postfix(0.L) == 0 && __signbitl_nid_postfix(-0.L) == 1);
Require(__signbitl_nid_postfix(1.L) == 0 && __signbitl_nid_postfix(-1.L) == 1);
Require(__signbitl_nid_postfix(std::numeric_limits<long double>::infinity()) == 0);
Require(__signbitl_nid_postfix(-std::numeric_limits<long double>::infinity()) == 1);
Require(__signbitl_nid_postfix(negativeNan) == 1);
}
static void CheckFloatMathExports() {
Require(ceilf_nid_postfix(2.25f) == 3.f && ceilf_nid_postfix(-2.25f) == -2.f);
Require(floorf_nid_postfix(2.75f) == 2.f && floorf_nid_postfix(-2.25f) == -3.f);
Require(truncf_nid_postfix(2.75f) == 2.f && truncf_nid_postfix(-2.75f) == -2.f);
Require(ceilf_nid_postfix(2.f) == 2.f && floorf_nid_postfix(-2.f) == -2.f && truncf_nid_postfix(2.f) == 2.f);
Require(std::bit_cast<std::uint32_t>(ceilf_nid_postfix(-0.f)) == 0x80000000u);
Require(std::bit_cast<std::uint32_t>(floorf_nid_postfix(-0.f)) == 0x80000000u);
Require(std::bit_cast<std::uint32_t>(truncf_nid_postfix(-0.f)) == 0x80000000u);
Require(ceilf_nid_postfix(std::numeric_limits<float>::infinity()) == std::numeric_limits<float>::infinity());
Require(floorf_nid_postfix(-std::numeric_limits<float>::infinity()) == -std::numeric_limits<float>::infinity());
Require(std::isnan(ceilf_nid_postfix(std::numeric_limits<float>::quiet_NaN())));
const double nan = std::numeric_limits<double>::quiet_NaN();
const double infinity = std::numeric_limits<double>::infinity();
Require(isnan_nid_postfix(nan) == 1 && isnan_nid_postfix(infinity) == 0 && isnan_nid_postfix(0.0) == 0);
Require(isnan_nid_postfix(-nan) == 1 && isnan_nid_postfix(-1.0) == 0);
Require(isinf_nid_postfix(infinity) == 1 && isinf_nid_postfix(-infinity) == 1);
Require(isinf_nid_postfix(nan) == 0 && isinf_nid_postfix(1.0) == 0);
}
static void CheckIntegerAbsAndDivision() {
for (auto function : {labs_nid_postfix, llabs_nid_postfix, imaxabs_nid_postfix}) {
Require(function(-5) == 5 && function(7) == 7 && function(0) == 0);
Require(function(-0x100000000ll) == 0x100000000ll);
Require(function(INT64_MAX) == INT64_MAX && function(INT64_MIN) == INT64_MIN);
}
const auto small = imaxdiv_nid_postfix(-7, 2);
Require(small.quot == -3 && small.rem == -1);
const auto large = imaxdiv_nid_postfix(0x123456789abll, -0x1000);
Require(large.quot == -0x12345678ll && large.rem == 0x9abll);
}
static void CheckScaling() {
Require(scalbnl_nid_postfix(3.0L, 4) == 48.0L && scalbnl_nid_postfix(1.0L, -16445) == 0x1p-16445L);
Require(scalbnl_nid_postfix(1.0L, 16384) == std::numeric_limits<long double>::infinity());
Require(significandf_nid_postfix(12.0f) == 1.5f && significandf_nid_postfix(-0.375f) == -1.5f);
Require(significandf_nid_postfix(0x1p-149f) == 1.0f);
Require(std::signbit(significandf_nid_postfix(-0.0f)) && significandf_nid_postfix(-0.0f) == 0.0f);
Require(significandf_nid_postfix(std::numeric_limits<float>::infinity()) == std::numeric_limits<float>::infinity());
Require(std::isnan(significandf_nid_postfix(std::numeric_limits<float>::quiet_NaN())));
}
static bool Near(long double actual, long double expected) {
return std::fabs(actual - expected) <= std::fabs(expected) * 1e-17L;
}
static void CheckLongDoubleFunctions() {
const long double infinity = std::numeric_limits<long double>::infinity();
const long double nan = std::numeric_limits<long double>::quiet_NaN();
Require(acoshl_nid_postfix(1.0L) == 0.0L && std::isnan(acoshl_nid_postfix(0.5L)));
Require(asinhl_nid_postfix(-0.0L) == 0.0L && std::signbit(asinhl_nid_postfix(-0.0L)));
Require(atanhl_nid_postfix(1.0L) == infinity && Near(atanhl_nid_postfix(0.5L), 0.5493061443340548456976226L));
Require(Near(atan2l_nid_postfix(1.0L, 1.0L), 0.7853981633974483096156608L) && Near(atan2l_nid_postfix(0.0L, -1.0L), 3.1415926535897932384626434L));
Require(cbrtl_nid_postfix(-27.0L) == -3.0L && Near(cbrtl_nid_postfix(0x1p-16443L) * cbrtl_nid_postfix(0x1p-16443L) * cbrtl_nid_postfix(0x1p-16443L), 0x1p-16443L));
Require(erfl_nid_postfix(0.0L) == 0.0L && erfl_nid_postfix(infinity) == 1.0L && erfcl_nid_postfix(0.0L) == 1.0L);
Require(erfcl_nid_postfix(infinity) == 0.0L && erfcl_nid_postfix(-infinity) == 2.0L);
Require(expm1l_nid_postfix(0.0L) == 0.0L && expm1l_nid_postfix(-infinity) == -1.0L);
Require(log1pl_nid_postfix(0.0L) == 0.0L && log1pl_nid_postfix(-1.0L) == -infinity);
Require(log2l_nid_postfix(8.0L) == 3.0L && log2l_nid_postfix(0x1p-16445L) == -16445.0L);
Require(lgammal_nid_postfix(1.0L) == 0.0L && lgammal_nid_postfix(2.0L) == 0.0L && lgammal_nid_postfix(0.0L) == infinity);
Require(tgammal_nid_postfix(5.0L) == 24.0L && Near(tgammal_nid_postfix(0.5L), 1.7724538509055160272981675L));
Require(hypotl_nid_postfix(3.0L, -4.0L) == 5.0L && hypotl_nid_postfix(nan, -infinity) == infinity);
Require(hypot3f_nid_postfix(3.0f, -4.0f, 12.0f) == 13.0f && hypot3f_nid_postfix(0.0f, 3.0f, -4.0f) == 5.0f);
Require(hypot3f_nid_postfix(2.0f, 0.0f, 0.0f) == 2.0f && hypot3f_nid_postfix(-2.0f, 3.0f, 6.0f) == 7.0f);
Require(hypot3_nid_postfix(1.0, 2.0, 2.0) == 3.0 && hypot3_nid_postfix(12.0, 3.0, 4.0) == 13.0);
Require(hypot3l_nid_postfix(2.0L, -3.0L, 6.0L) == 7.0L);
const double payload = std::bit_cast<double>(0x7ff8000000000123ull);
Require(std::bit_cast<std::uint64_t>(hypot3_nid_postfix(1.0, payload, std::numeric_limits<double>::infinity())) == 0x7ff8000000000123ull);
Require(std::isnan(hypot3f_nid_postfix(std::numeric_limits<float>::infinity(), 1.0f, std::numeric_limits<float>::quiet_NaN())));
Require(hypot3l_nid_postfix(-infinity, 1.0L, 2.0L) == infinity && hypot3_nid_postfix(1.0, -std::numeric_limits<double>::infinity(), 0.0) == std::numeric_limits<double>::infinity());
Require(hypot3_nid_postfix(0x1p1000, 0x1p1000, 0x1p1000) == std::hypot(0x1p1000, std::hypot(0x1p1000, 0x1p1000)));
Require(j0f_nid_postfix(0.0f) == 1.0f && j1f_nid_postfix(0.0f) == 0.0f && jnf_nid_postfix(2, 0.0f) == 0.0f);
Require(std::fabs(j0f_nid_postfix(2.5f) - static_cast<float>(-0.048383776468198)) < 1e-6f);
Require(std::fabs(jnf_nid_postfix(3, 4.0f) - static_cast<float>(0.430171473875622)) < 1e-6f);
Require(y0f_nid_postfix(0.0f) == -std::numeric_limits<float>::infinity() && y1f_nid_postfix(0.0f) == -std::numeric_limits<float>::infinity());
Require(ynf_nid_postfix(2, 0.0f) == -std::numeric_limits<float>::infinity());
Require(std::fabs(ynf_nid_postfix(2, 3.0f) - static_cast<float>(-0.160400393484924)) < 1e-6f);
Require(std::isnan(y0f_nid_postfix(-1.0f)));
}
static void CheckDoubleClassification() {
const struct { std::uint64_t bits; short code; } cases[] = {
{0x0000000000000000ull, 0}, {0x8000000000000000ull, 0},
{0x0000000000000001ull, -2}, {0x800fffffffffffffull, -2},
{0x0010000000000000ull, -1}, {0xbff0000000000000ull, -1}, {0x7fefffffffffffffull, -1},
{0x7ff0000000000000ull, 1}, {0xfff0000000000000ull, 1},
{0x7ff0000000000001ull, 2}, {0x7ff8000000000000ull, 2}, {0xfff8000000000000ull, 2},
};
for (const auto& test : cases) {
double value;
std::memcpy(&value, &test.bits, sizeof(value));
if (_Dtest_nid_postfix(&value) != test.code) {
std::fprintf(stderr, "Guest _Dtest failed for %016llx\n", static_cast<unsigned long long>(test.bits));
std::abort();
}
}
}
static void CheckDoubleRounding(double value, std::int64_t expected, bool invalid) {
for (const bool useLlround : {false, true}) {
std::feclearexcept(FE_ALL_EXCEPT);
errno = 12345;
const std::int64_t result = useLlround ? llround_nid_postfix(value) : lround_nid_postfix(value);
Require(result == expected);
Require((std::fetestexcept(FE_INVALID) != 0) == invalid);
Require(errno == 12345);
}
}
static void CheckFloatRounding(float value, std::int64_t expected, bool invalid) {
for (const bool useLlround : {false, true}) {
std::feclearexcept(FE_ALL_EXCEPT);
errno = 12345;
const std::int64_t result = useLlround ? llroundf_nid_postfix(value) : lroundf_nid_postfix(value);
Require(result == expected);
Require((std::fetestexcept(FE_INVALID) != 0) == invalid);
Require(errno == 12345);
}
}
static void CheckLongDoubleRounding(long double value, std::int64_t expected, bool invalid) {
std::feclearexcept(FE_ALL_EXCEPT);
errno = 12345;
const std::int64_t result = llroundl_nid_postfix(value);
if (result != expected || (std::fetestexcept(FE_INVALID) != 0) != invalid || errno != 12345) {
std::fprintf(stderr, "llroundl failed for %La: expected %lld, got %lld\n", value,
static_cast<long long>(expected), static_cast<long long>(result));
std::abort();
}
}
static void CheckNoConversionIsPositiveZero() {
for (const char* text : {"", " ", "-", "+", "-.", "+.", "-x", "-.e1", "-e5", "- 1", " -."}) {
char* end = nullptr;
const double parsed = strtod_nid_postfix(text, &end);
Require(parsed == 0. && !std::signbit(parsed) && end == text);
const float parsedFloat = strtof_nid_postfix(text, &end);
Require(parsedFloat == 0.f && !std::signbit(parsedFloat) && end == text);
const long double parsedLong = strtold_nid_postfix(text, &end);
Require(parsedLong == 0.L && !std::signbit(parsedLong) && end == text);
Require(!std::signbit(atof_nid_postfix(text)));
}
char* end = nullptr;
const char negativeZero[] = "-0.0x";
const double parsed = strtod_nid_postfix(negativeZero, &end);
Require(parsed == 0. && std::signbit(parsed) && end == negativeZero + 4);
for (const char* text : {"-0", "-.0", "-0e5", "-0x0p0", "-0x"}) {
const double keptDouble = strtod_nid_postfix(text, &end);
Require(keptDouble == 0. && std::signbit(keptDouble) && end != text);
const float keptFloat = strtof_nid_postfix(text, &end);
Require(keptFloat == 0.f && std::signbit(keptFloat) && end != text);
const long double keptLong = strtold_nid_postfix(text, nullptr);
Require(keptLong == 0.L && std::signbit(keptLong));
}
Require(strtod_nid_postfix("-inf", nullptr) == -std::numeric_limits<double>::infinity());
Require(std::isnan(atof_nid_postfix("nan")));
const double noEndPointer = strtod_nid_postfix("-.", nullptr);
Require(noEndPointer == 0. && !std::signbit(noEndPointer));
const char16_t wide[] = u"-.";
char16_t* wideEnd = nullptr;
const char16_t wideKept[] = u" -0.0x";
const double keptWide = wcstod_nid_postfix(wideKept, &wideEnd);
Require(keptWide == 0. && std::signbit(keptWide) && wideEnd == wideKept + 5);
const double parsedWide = wcstod_nid_postfix(wide, &wideEnd);
Require(parsedWide == 0. && !std::signbit(parsedWide) && wideEnd == wide);
const float parsedWideFloat = wcstof_nid_postfix(wide, &wideEnd);
Require(parsedWideFloat == 0.f && !std::signbit(parsedWideFloat) && wideEnd == wide);
const long double parsedWideLong = wcstold_nid_postfix(wide, &wideEnd);
Require(parsedWideLong == 0.L && !std::signbit(parsedWideLong) && wideEnd == wide);
}
int main() {
CheckFloatClassification();
CheckNoConversionIsPositiveZero();
CheckMissingClassificationExports();
CheckFloatMathExports();
CheckIntegerConversions();
CheckExtendedMath();
Require(atof_nid_postfix(" -12.5tail") == -12.5);
char* end = nullptr;
const char input[] = "0x1.8p+2 remainder";
Require(strtof_nid_postfix(input, &end) == 6.f && end == input + 8);
const char invalid[] = "invalid";
Require(strtof_nid_postfix(invalid, &end) == 0.f && end == invalid);
*__error_nid_postfix() = 0;
Require(std::isinf(strtof_nid_postfix("1e1000", nullptr)));
Require(*__error_nid_postfix() == 34);
Require(strtold_nid_postfix("1.0000000000000000001!", &end) > 1.L && *end == '!');
CheckNanConversions();
Require(fmodf_nid_postfix(5.5f, 2.f) == 1.5f);
Require(fmodf_nid_postfix(-5.5f, 2.f) == -1.5f);
Require(std::signbit(fmodf_nid_postfix(-4.f, 2.f)));
Require(std::isnan(fmodf_nid_postfix(1.f, 0.f)));
int quo = 0;
Require(remquo_nid_postfix(7.0, 3.0, &quo) == 1.0 && (quo & 7) == 2);
Require(remquo_nid_postfix(-7.0, 3.0, &quo) == -1.0 && (quo & 7) == ((-2) & 7));
int quof = 0;
Require(remquof_nid_postfix(7.0f, 3.0f, &quof) == 1.0f && (quof & 7) == 2);
Require(remquof_nid_postfix(-7.0f, 3.0f, &quof) == -1.0f && (quof & 7) == ((-2) & 7));
Require(std::bit_cast<std::uint32_t>(nanf_nid_postfix(nullptr)) == 0x7fc00000u);
Require(std::bit_cast<std::uint32_t>(nanf_nid_postfix("")) == 0x7fc00000u);
Require(std::bit_cast<std::uint32_t>(nanf_nid_postfix("123")) == 0x7fc00000u);
Require(!std::signbit(nanf_nid_postfix("")));
Require(std::bit_cast<std::uint64_t>(nan_nid_postfix(nullptr)) == 0x7ff8000000000000ull);
Require(std::bit_cast<std::uint64_t>(nan_nid_postfix("")) == 0x7ff8000000000000ull);
Require(std::bit_cast<std::uint64_t>(nan_nid_postfix("123")) == 0x7ff8000000000000ull);
Require(!std::signbit(nan_nid_postfix("")));
Require(std::abs(asinf_nid_postfix(0.5f) - 0.5235988f) < 0.000001f);
Require(std::abs(acosf_nid_postfix(0.5f) - 1.0471976f) < 0.000001f);
Require(std::abs(atan2f_nid_postfix(1.f, -1.f) - 2.3561945f) < 0.000001f);
Require(tanf_nid_postfix(0.f) == 0.f);
unsigned int randomState = 1;
Require(rand_r_nid_postfix(&randomState) == 33613 && randomState == 33613u);
randomState = 0;
Require(rand_r_nid_postfix(&randomState) == 16806 && randomState == 16806u);
for (const unsigned int seed : {0u, 1u, 12345u, 0x7ffffffeu, 0xffffffffu}) {
srand_nid_postfix(seed);
randomState = seed;
for (int step = 0; step < 8; ++step) Require(rand_r_nid_postfix(&randomState) == rand_nid_postfix());
}
bool threw = false;
try { rand_r_nid_postfix(nullptr); } catch (...) { threw = true; }
Require(threw);
Require(hypot_nid_postfix(3.0, 4.0) == 5.0 && hypot_nid_postfix(-3.0, -4.0) == 5.0 && hypotf_nid_postfix(3.f, -4.f) == 5.f);
Require(copysign_nid_postfix(1.0, 2.0) == 1.0 && copysign_nid_postfix(1.0, -2.0) == -1.0);
Require(copysign_nid_postfix(-1.0, 2.0) == 1.0 && copysign_nid_postfix(-1.0, -2.0) == -1.0);
Require(std::bit_cast<std::uint64_t>(copysign_nid_postfix(0.0, -1.0)) == 0x8000000000000000ull);
Require(std::bit_cast<std::uint64_t>(copysign_nid_postfix(-0.0, 1.0)) == 0);
Require(copysign_nid_postfix(INFINITY, -1.0) == -INFINITY && copysign_nid_postfix(-INFINITY, 1.0) == INFINITY);
Require(std::isnan(copysign_nid_postfix(std::numeric_limits<double>::quiet_NaN(), -1.0)) && std::signbit(copysign_nid_postfix(std::numeric_limits<double>::quiet_NaN(), -1.0)));
Require(std::isnan(copysign_nid_postfix(std::numeric_limits<double>::quiet_NaN(), 1.0)) && !std::signbit(copysign_nid_postfix(std::numeric_limits<double>::quiet_NaN(), 1.0)));
Require(copysignf_nid_postfix(1.0f, 2.0f) == 1.0f && copysignf_nid_postfix(1.0f, -2.0f) == -1.0f);
Require(std::bit_cast<std::uint32_t>(copysignf_nid_postfix(0.0f, -1.0f)) == 0x80000000u);
Require(std::bit_cast<std::uint32_t>(copysignf_nid_postfix(-0.0f, 1.0f)) == 0);
Require(std::abs(hypot_nid_postfix(1e308, 1e308) / 1.4142135623730951e308 - 1.0) < 1e-15);
Require(std::abs(hypotf_nid_postfix(2e38f, 2e38f) / 2.8284271e38f - 1.f) < 1e-6f);
Require(std::isinf(hypot_nid_postfix(std::numeric_limits<double>::infinity(), std::numeric_limits<double>::quiet_NaN())));
Require(std::isinf(hypotf_nid_postfix(std::numeric_limits<float>::quiet_NaN(), -std::numeric_limits<float>::infinity())));
Require(std::isnan(hypot_nid_postfix(1.0, std::numeric_limits<double>::quiet_NaN())));
for (const bool signalingFirst : {true, false}) {
const float signaling = std::bit_cast<float>(std::uint32_t{0x7f800001});
const float infinity = std::numeric_limits<float>::infinity();
std::feclearexcept(FE_ALL_EXCEPT);
const float result = signalingFirst ? hypotf_nid_postfix(signaling, infinity) : hypotf_nid_postfix(infinity, signaling);
Require(std::isinf(result) && result > 0.f && std::fetestexcept(FE_INVALID) != 0);
}
Require(log10f_nid_postfix(100.f) == 2.f);
Require(log1p_nid_postfix(0.) == 0. && std::signbit(log1p_nid_postfix(-0.)));
Require(log1p_nid_postfix(-1.) == -std::numeric_limits<double>::infinity() && std::isnan(log1p_nid_postfix(-2.)));
Require(log1p_nid_postfix(std::numeric_limits<double>::infinity()) == std::numeric_limits<double>::infinity());
Require(log1p_nid_postfix(1e-300) == 1e-300 && log1pf_nid_postfix(1e-30f) == 1e-30f);
Require(std::abs(log1p_nid_postfix(1.) - 0.6931471805599453) < 1e-16);
Require(std::abs(log1p_nid_postfix(1e-10) - 9.9999999995e-11) < 1e-25);
Require(std::abs(log1pf_nid_postfix(1.f) - 0.6931472f) < 1e-7f && std::isnan(log1pf_nid_postfix(-2.f)));
Require(expm1_nid_postfix(0.) == 0. && std::signbit(expm1_nid_postfix(-0.)));
Require(expm1_nid_postfix(1e-300) == 1e-300 && expm1_nid_postfix(-1000.) == -1.);
Require(expm1_nid_postfix(-std::numeric_limits<double>::infinity()) == -1.);
Require(std::abs(expm1_nid_postfix(1.) - 1.718281828459045) < 1e-15);
Require(std::abs(expm1_nid_postfix(1e-10) - 1.00000000005e-10) < 1e-25);
Require(expm1f_nid_postfix(0.f) == 0.f && std::signbit(expm1f_nid_postfix(-0.f)) && expm1f_nid_postfix(-1000.f) == -1.f);
Require(std::abs(expm1f_nid_postfix(1.f) - 1.7182818f) < 1e-6f && std::isinf(expm1f_nid_postfix(std::numeric_limits<float>::infinity())));
Require(erff_nid_postfix(0.f) == 0.f && std::signbit(erff_nid_postfix(-0.f)) && erff_nid_postfix(10.f) == 1.f && erff_nid_postfix(-10.f) == -1.f);
Require(std::abs(erff_nid_postfix(0.5f) - 0.5204999f) < 1e-6f && std::isnan(erff_nid_postfix(std::numeric_limits<float>::quiet_NaN())));
Require(erf_nid_postfix(0.) == 0. && std::signbit(erf_nid_postfix(-0.)) && erf_nid_postfix(10.) == 1. && erf_nid_postfix(-10.) == -1.);
Require(std::abs(erf_nid_postfix(0.5) - 0.5204998778130465) < 1e-15 && std::isnan(erf_nid_postfix(std::numeric_limits<double>::quiet_NaN())));
Require(erfc_nid_postfix(0.) == 1. && erfc_nid_postfix(100.) == 0. && erfc_nid_postfix(-100.) == 2.);
Require(std::abs(erfc_nid_postfix(0.5) - 0.47950012218695346) < 1e-15 && std::isnan(erfc_nid_postfix(std::numeric_limits<double>::quiet_NaN())));
Require(erfcf_nid_postfix(0.f) == 1.f && erfcf_nid_postfix(100.f) == 0.f && erfcf_nid_postfix(-100.f) == 2.f);
Require(std::abs(erfcf_nid_postfix(0.5f) - 0.47950012f) < 1e-6f && std::isnan(erfcf_nid_postfix(std::numeric_limits<float>::quiet_NaN())));
Require(lgamma_nid_postfix(1.) == 0. && lgamma_nid_postfix(2.) == 0. && std::isinf(lgamma_nid_postfix(0.)));
Require(std::abs(lgamma_nid_postfix(0.5) - 0.5723649429247001) < 1e-15 && std::abs(lgamma_nid_postfix(10.) - 12.801827480081469) < 1e-13);
Require(std::abs(lgamma_nid_postfix(-0.5) - 1.2655121234846454) < 1e-15);
for (const double sign : {1.0, -1.0}) {
std::feclearexcept(FE_ALL_EXCEPT);
Require(std::abs(lgamma_nid_postfix(sign * std::numeric_limits<double>::denorm_min()) - 744.44007192138122) < 1e-12);
Require(std::abs(lgamma_nid_postfix(sign * 0x1p-1025) - 710.47586007394398) < 1e-12);
Require(std::abs(lgamma_nid_postfix(sign * 0x1p-1022) - 708.39641853226408) < 1e-12);
Require(std::abs(lgamma_nid_postfix(sign * 0x1p-57) - 39.509389291916882) < 1e-13);
Require(std::fetestexcept(FE_OVERFLOW | FE_DIVBYZERO | FE_INVALID) == 0);
}
const auto gammaSign = [](double x) {
signgam_nid_postfix = 7;
lgamma_nid_postfix(x);
return signgam_nid_postfix;
};
Require(gammaSign(0.5) == 1 && gammaSign(10.) == 1 && gammaSign(0.) == 1 && gammaSign(-0.) == -1);
Require(gammaSign(-0.5) == -1 && gammaSign(-1.5) == 1 && gammaSign(-2.5) == -1 && gammaSign(-0x1p-80) == -1);
Require(gammaSign(-1.) == 1 && gammaSign(-2.) == 1 && gammaSign(-0x1p60) == 1 && gammaSign(-4503599627370495.5) == 1);
Require(gammaSign(INFINITY) == 1 && gammaSign(-INFINITY) == 1 && gammaSign(NAN) == 1);
Require(llroundl_nid_postfix(2.5L) == 3 && llroundl_nid_postfix(-2.5L) == -3 && llroundl_nid_postfix(0.49999999999999999L) == 0);
Require(llroundl_nid_postfix(9007199254740993.0L) == 9007199254740993LL && llroundl_nid_postfix(-1e30L) == INT64_MIN);
for (const int mode : {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO}) {
Require(std::fesetround(mode) == 0);
CheckLongDoubleRounding(9223372036854775807.0L, INT64_MAX, false);
CheckLongDoubleRounding(9223372036854775806.5L, INT64_MAX, false);
CheckLongDoubleRounding(9223372036854775806.0L, INT64_MAX - 1, false);
CheckLongDoubleRounding(-0x1p63L, INT64_MIN, false);
CheckLongDoubleRounding(-9223372036854775807.5L, INT64_MIN, false);
CheckLongDoubleRounding(-9223372036854775807.0L, INT64_MIN + 1, false);
for (const long double value : {9223372036854775807.5L, 0x1p63L, -9223372036854775809.0L,
std::numeric_limits<long double>::infinity(), -std::numeric_limits<long double>::infinity(),
std::numeric_limits<long double>::quiet_NaN()}) {
CheckLongDoubleRounding(value, INT64_MIN, true);
}
}
Require(std::fesetround(FE_TONEAREST) == 0);
Require(logbf_nid_postfix(8.f) == 3.f && logbf_nid_postfix(-0.75f) == -1.f);
Require(logbf_nid_postfix(std::numeric_limits<float>::denorm_min()) == -149.f);
Require(logbf_nid_postfix(0.f) == -std::numeric_limits<float>::infinity());
Require(logbf_nid_postfix(-std::numeric_limits<float>::infinity()) == std::numeric_limits<float>::infinity());
Require(std::isnan(logbf_nid_postfix(std::numeric_limits<float>::quiet_NaN())));
Require(ilogb_nid_postfix(8.0) == 3 && ilogb_nid_postfix(-0.75) == -1 && ilogb_nid_postfix(1.0) == 0);
Require(ilogb_nid_postfix(1024.0) == 10 && ilogb_nid_postfix(0.125) == -3);
Require(ilogbf_nid_postfix(8.f) == 3 && ilogbf_nid_postfix(-0.75f) == -1 && ilogbf_nid_postfix(1.f) == 0);
Require(ilogbf_nid_postfix(1024.f) == 10 && ilogbf_nid_postfix(0.125f) == -3);
Require(ilogb_nid_postfix(0.0) == INT_MIN && ilogb_nid_postfix(-0.0) == INT_MIN);
Require(ilogb_nid_postfix(std::numeric_limits<double>::infinity()) == INT_MAX);
Require(ilogb_nid_postfix(-std::numeric_limits<double>::infinity()) == INT_MAX);
Require(ilogb_nid_postfix(std::numeric_limits<double>::quiet_NaN()) == INT_MAX);
Require(ilogbf_nid_postfix(0.f) == INT_MIN && ilogbf_nid_postfix(-0.f) == INT_MIN);
Require(ilogbf_nid_postfix(std::numeric_limits<float>::infinity()) == INT_MAX);
Require(ilogbf_nid_postfix(std::numeric_limits<float>::quiet_NaN()) == INT_MAX);
Require(ilogbf_nid_postfix(std::numeric_limits<float>::denorm_min()) == -149);
Require(exp2_nid_postfix(-3.) == 0.125);
Require(ldexp_nid_postfix(0.75, 4) == 12.);
CheckSquareRoot();
CheckExp2Errno();
CheckExactOperations();
CheckNearbyint();
CheckFegetenv();
CheckLongDouble();
CheckNearbyintl();
CheckAsinl();
Require(scalbn_nid_postfix(0.75, -2) == 0.1875);
Require(scalbnf_nid_postfix(0.75f, 4) == 12.f);
Require(nextafterf_nid_postfix(1.f, 2.f) == 0x1.000002p0f && nextafterf_nid_postfix(1.f, 0.f) == 0x1.fffffep-1f);
Require(nextafterf_nid_postfix(0.f, 1.f) == std::numeric_limits<float>::denorm_min());
Require(nextafterf_nid_postfix(0.f, -1.f) == -std::numeric_limits<float>::denorm_min());
Require(nextafterf_nid_postfix(std::numeric_limits<float>::denorm_min(), -1.f) == 0.f);
Require(nextafterf_nid_postfix(1.f, 1.f) == 1.f && !std::signbit(nextafterf_nid_postfix(-0.f, 0.f)));
Require(nextafterf_nid_postfix(std::numeric_limits<float>::max(), std::numeric_limits<float>::infinity()) == std::numeric_limits<float>::infinity());
Require(std::isnan(nextafterf_nid_postfix(std::numeric_limits<float>::quiet_NaN(), 1.f)) && std::isnan(nextafterf_nid_postfix(1.f, std::numeric_limits<float>::quiet_NaN())));
Require(nextafter_nid_postfix(1.0, 2.0) == 0x1.0000000000001p0 && nextafter_nid_postfix(1.0, 0.0) == 0x1.fffffffffffffp-1);
Require(nextafter_nid_postfix(0.0, 1.0) == std::numeric_limits<double>::denorm_min());
Require(nextafter_nid_postfix(0.0, -1.0) == -std::numeric_limits<double>::denorm_min());
Require(nextafter_nid_postfix(std::numeric_limits<double>::denorm_min(), -1.0) == 0.0);
Require(nextafter_nid_postfix(1.0, 1.0) == 1.0 && !std::signbit(nextafter_nid_postfix(-0.0, 0.0)));
Require(nextafter_nid_postfix(std::numeric_limits<double>::max(), std::numeric_limits<double>::infinity()) == std::numeric_limits<double>::infinity());
Require(std::isnan(nextafter_nid_postfix(std::numeric_limits<double>::quiet_NaN(), 1.0)) && std::isnan(nextafter_nid_postfix(1.0, std::numeric_limits<double>::quiet_NaN())));
int exponent = 0;
Require(frexp_nid_postfix(12., &exponent) == 0.75 && exponent == 4);
Require(frexpf_nid_postfix(-12.f, &exponent) == -0.75f && exponent == 4);
Require(lround_nid_postfix(4294967296.5) == INT64_C(4294967297));
Require(lround_nid_postfix(-2.5) == -3);
Require(lroundf_nid_postfix(4294967296.f) == INT64_C(4294967296));
Require(lroundf_nid_postfix(2.5f) == 3);
Require(llround_nid_postfix(-4294967296.5) == -INT64_C(4294967297));
Require(llroundf_nid_postfix(2.5f) == 3 && llroundf_nid_postfix(-2.5f) == -3 && llroundf_nid_postfix(-0.4f) == 0);
Require(llroundf_nid_postfix(8589934592.f) == INT64_C(8589934592) && llroundf_nid_postfix(-0x1p62f) == -(INT64_C(1) << 62));
Require(llroundf_nid_postfix(0.49999997f) == 0 && llroundf_nid_postfix(16777215.f) == 16777215);
Require(lround_nid_postfix(0.49999999999999994) == 0 && lround_nid_postfix(-0.49999999999999994) == 0);
constexpr double kTwo63 = 9223372036854775808.0;
constexpr double kTwo63Below = 9223372036854774784.0;
constexpr float kTwo63f = 9223372036854775808.f;
constexpr float kTwo63fBelow = 9223371487098961920.f;
CheckDoubleRounding(-kTwo63, INT64_MIN, false);
CheckDoubleRounding(kTwo63Below, INT64_C(9223372036854774784), false);
CheckDoubleRounding(-kTwo63Below, -INT64_C(9223372036854774784), false);
CheckDoubleRounding(4503599627370497.0, INT64_C(4503599627370497), false);
CheckFloatRounding(-kTwo63f, INT64_MIN, false);
CheckFloatRounding(kTwo63fBelow, INT64_C(9223371487098961920), false);
CheckFloatRounding(-kTwo63fBelow, -INT64_C(9223371487098961920), false);
for (const double value : {kTwo63, -9223374235878031360.0, 1e30, -1e30, std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity(), std::numeric_limits<double>::quiet_NaN()}) {
CheckDoubleRounding(value, INT64_MIN, true);
CheckFloatRounding(static_cast<float>(value), INT64_MIN, true);
}
CheckFloatRounding(kTwo63f, INT64_MIN, true);
std::feclearexcept(FE_ALL_EXCEPT);
const auto infinity = std::numeric_limits<float>::infinity();
const auto nan = std::numeric_limits<float>::quiet_NaN();
Require(__isinff_nid_postfix(infinity) == 1 && __isinff_nid_postfix(-infinity) == 1);
Require(__isinff_nid_postfix(nan) == 0 && __isinff_nid_postfix(1.f) == 0);
Require(__isinf_nid_postfix(std::numeric_limits<double>::infinity()) == 1 && __isinf_nid_postfix(-std::numeric_limits<double>::infinity()) == 1);
Require(__isinf_nid_postfix(std::numeric_limits<double>::quiet_NaN()) == 0 && __isinf_nid_postfix(std::numeric_limits<double>::max()) == 0);
Require(__isinf_nid_postfix(0.) == 0 && __isinf_nid_postfix(1e308 * 10) == 1);
Require(__isfinitef_nid_postfix(0.f) == 1 && __isfinitef_nid_postfix(infinity) == 0);
Require(__isfinitef_nid_postfix(nan) == 0);
std::feclearexcept(FE_ALL_EXCEPT);
std::feraiseexcept(FE_DIVBYZERO);
for (const long double value : {0.0L, -0.0L, 1.0L, -1.0L, std::numeric_limits<long double>::denorm_min(),
-std::numeric_limits<long double>::denorm_min(), std::numeric_limits<long double>::min(),
std::numeric_limits<long double>::max(), std::numeric_limits<long double>::lowest(),
0x1p1024L, -0x1p1024L, 0x1p-16382L}) {
Require(__isfinitel_nid_postfix(value) == 1);
}
for (const long double value : {std::numeric_limits<long double>::infinity(), -std::numeric_limits<long double>::infinity(),
std::numeric_limits<long double>::quiet_NaN(), -std::numeric_limits<long double>::quiet_NaN(),
std::numeric_limits<long double>::signaling_NaN(), -std::numeric_limits<long double>::signaling_NaN()}) {
Require(__isfinitel_nid_postfix(value) == 0);
}
Require(std::fetestexcept(FE_ALL_EXCEPT) == FE_DIVBYZERO);
std::feclearexcept(FE_ALL_EXCEPT);
Require(__isnormalf_nid_postfix(1.f) == 1 && __isnormalf_nid_postfix(0.f) == 0);
Require(__isnormalf_nid_postfix(std::numeric_limits<float>::denorm_min()) == 0);
Require(__isnormal_nid_postfix(1.) == 1 && __isnormal_nid_postfix(0.) == 0);
Require(__isnormal_nid_postfix(std::numeric_limits<double>::denorm_min()) == 0);
CheckAsin();
const auto quotient = div_nid_postfix(7, 2);
CheckAsinfErrno();
Require(quotient.quot == 3 && quotient.rem == 1);
const auto negativeNumerator = div_nid_postfix(-7, 2);
Require(negativeNumerator.quot == -3 && negativeNumerator.rem == -1);
const auto negativeDenominator = div_nid_postfix(7, -2);
Require(negativeDenominator.quot == -3 && negativeDenominator.rem == 1);
const auto minimum = div_nid_postfix(std::numeric_limits<int>::min(), 10);
Require(minimum.quot == -214748364 && minimum.rem == -8);
CheckPowfSpecialValue();
Require(abs_nid_postfix(0) == 0);
CheckAcosfErrno();
Require(abs_nid_postfix(42) == 42);
Require(abs_nid_postfix(-42) == 42);
Require(abs_nid_postfix(std::numeric_limits<int>::max()) == std::numeric_limits<int>::max());
Require(abs_nid_postfix(std::numeric_limits<int>::min()) == std::numeric_limits<int>::min());
Require(__powisf2_nid_postfix(2.0f, 10) == 1024.0f);
Require(__powisf2_nid_postfix(2.0f, -10) == 0.0009765625f);
Require(__powisf2_nid_postfix(-2.0f, 3) == -8.0f);
Require(__powisf2_nid_postfix(-2.0f, -3) == -0.125f);
Require(__powisf2_nid_postfix(-2.0f, 4) == 16.0f);
Require(__powisf2_nid_postfix(0.0f, 0) == 1.0f);
Require(__powisf2_nid_postfix(std::numeric_limits<float>::quiet_NaN(), 0) == 1.0f);
Require(std::isnan(__powisf2_nid_postfix(std::numeric_limits<float>::quiet_NaN(), 1)));
Require(__powisf2_nid_postfix(-1.0f, std::numeric_limits<int>::min()) == 1.0f);
Require(__powisf2_nid_postfix(-1.0f, std::numeric_limits<int>::max()) == -1.0f);
Require(__powisf2_nid_postfix(2.0f, std::numeric_limits<int>::min()) == 0.0f);
Require(std::isinf(__powisf2_nid_postfix(0.0f, -1)));
Require(std::signbit(__powisf2_nid_postfix(-0.0f, 3)));
Require(std::isinf(__powisf2_nid_postfix(-0.0f, -3)) && std::signbit(__powisf2_nid_postfix(-0.0f, -3)));
Require(__powisf2_nid_postfix(2.0f, -127) == 0x1p-127f);
Require(__powidf2_nid_postfix(2.0, 10) == 1024.0);
Require(__powidf2_nid_postfix(2.0, -10) == 0.0009765625);
Require(__powidf2_nid_postfix(-2.0, 3) == -8.0);
Require(__powidf2_nid_postfix(-2.0, -3) == -0.125);
Require(__powidf2_nid_postfix(-2.0, 4) == 16.0);
Require(__powidf2_nid_postfix(0.0, 0) == 1.0);
Require(__powidf2_nid_postfix(std::numeric_limits<double>::quiet_NaN(), 0) == 1.0);
Require(std::isnan(__powidf2_nid_postfix(std::numeric_limits<double>::quiet_NaN(), 1)));
Require(__powidf2_nid_postfix(-1.0, std::numeric_limits<int>::min()) == 1.0);
Require(__powidf2_nid_postfix(-1.0, std::numeric_limits<int>::max()) == -1.0);
Require(__powidf2_nid_postfix(2.0, std::numeric_limits<int>::min()) == 0.0);
Require(std::isinf(__powidf2_nid_postfix(0.0, -1)));
Require(std::signbit(__powidf2_nid_postfix(-0.0, 3)));
Require(std::isinf(__powidf2_nid_postfix(-0.0, -3)) && std::signbit(__powidf2_nid_postfix(-0.0, -3)));
Require(__powidf2_nid_postfix(2.0, -127) == 0x1p-127);
CheckHyperbolic();
CheckSinhf();
CheckAtanhf();
CheckHypotSpecialValue();
CheckFmodErrno();
CheckDoubleClassification();
CheckIntegerAbsAndDivision();
CheckScaling();
CheckLongDoubleFunctions();
}