mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-28 12:05:06 +00:00
strtof and wcstof now set ERANGE for a decimal input whose nonzero subnormal result is inexact, never for a hexadecimal nonzero subnormal, and keep it for underflow to zero and overflow. This is what the libc.prx bundled with PPSA08427 (J03547016) and PPSA03671 (J03848509) do when run side by side with this libc. The earlier commit followed libSceLibcInternal's _Stof, which leaves errno alone for hexadecimal under- and overflow, but titles import these NIDs from their own libc.prx. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01RbLgECLQ2bpDM7oe2urGZK
1621 lines
96 KiB
C++
1621 lines
96 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <bit>
|
|
#include <cerrno>
|
|
#include <cfenv>
|
|
#include <cfloat>
|
|
#include <climits>
|
|
#include <cmath>
|
|
#include <cstddef>
|
|
#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);
|
|
int APS5_VABI atoi_nid_postfix(const char*);
|
|
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;
|
|
extern LibcFloatConstant _FDenorm_nid_postfix;
|
|
extern LibcFloatConstant _FSnan_nid_postfix;
|
|
union SonyDconst { unsigned short _Word[8]; float _Float; double _Double; long double _Long_double; };
|
|
extern SonyDconst _Inf_nid_postfix;
|
|
extern SonyDconst _Denorm_nid_postfix;
|
|
extern SonyDconst _Hugeval_nid_postfix;
|
|
extern SonyDconst _Nan_nid_postfix;
|
|
extern SonyDconst _Snan_nid_postfix;
|
|
extern SonyDconst _LDenorm_nid_postfix;
|
|
extern SonyDconst _LInf_nid_postfix;
|
|
extern SonyDconst _LNan_nid_postfix;
|
|
extern SonyDconst _LSnan_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);
|
|
float APS5_VABI _FSinh_nid_postfix(float, float);
|
|
float APS5_VABI _FCosh_nid_postfix(float, 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);
|
|
double APS5_VABI significand_nid_postfix(double);
|
|
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);
|
|
float APS5_VABI tgammaf_nid_postfix(float);
|
|
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);
|
|
struct DinkumwareFloatCharacteristics {
|
|
int digits;
|
|
int mantissaDigits;
|
|
int maxExponent10;
|
|
int maxExponent;
|
|
int minExponent10;
|
|
int minExponent;
|
|
alignas(16) unsigned char epsilon[16];
|
|
alignas(16) unsigned char max[16];
|
|
alignas(16) unsigned char min[16];
|
|
};
|
|
extern DinkumwareFloatCharacteristics _Flt_nid_postfix;
|
|
extern DinkumwareFloatCharacteristics _Dbl_nid_postfix;
|
|
extern DinkumwareFloatCharacteristics _Ldbl_nid_postfix;
|
|
}
|
|
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() {
|
|
struct MeasuredNan {
|
|
const char* text;
|
|
std::uint64_t bits;
|
|
std::size_t used;
|
|
std::size_t sequenceUsed;
|
|
bool extendedMeasured;
|
|
bool wideDoubleMeasured;
|
|
bool wideOtherMeasured;
|
|
};
|
|
static constexpr MeasuredNan cases[] = {
|
|
{"nan", 0x7ff8000000000000ull, 3, 3, true, true, true},
|
|
{"NAN", 0x7ff8000000000000ull, 3, 3, false, false, false},
|
|
{"nan()", 0x7ff8000000000000ull, 5, 5, false, false, false},
|
|
{"nan(1)", 0x7ff8000000000001ull, 6, 6, true, true, true},
|
|
{"nan(0x10)", 0x7ff8000000000010ull, 9, 9, false, false, false},
|
|
{"nan(abc)", 0x7ff8000000000abcull, 8, 8, false, false, false},
|
|
{"nan(", 0x7ff8000000000000ull, 3, 3, true, true, true},
|
|
{"-nan", 0xfff8000000000000ull, 4, 4, true, true, true},
|
|
{"+nan(5)", 0x7ff8000000000005ull, 7, 7, false, false, false},
|
|
{"nan(10)", 0x7ff8000000000010ull, 7, 7, false, false, false},
|
|
{"nan(xyz)", 0x7ff8000000000000ull, 8, 8, false, false, false},
|
|
{"nan(_)", 0x7ff8000000000000ull, 6, 6, false, false, false},
|
|
{"nan(12", 0x7ff8000000000012ull, 3, 3, false, false, false},
|
|
{"-nan(5)", 0xfff8000000000005ull, 7, 7, false, false, false},
|
|
{"nan(0x8000000000000)", 0x7ff8000000000000ull, 20, 20, false, false, false},
|
|
{"nan(0x10000000000000)", 0x7ff8000000000001ull, 21, 21, true, true, false},
|
|
{"nan(0x400000)", 0x7ff8000000400000ull, 13, 13, false, false, false},
|
|
{"NaN(0X1F)", 0x7ff800000000001full, 9, 9, false, false, false},
|
|
{"nan(0x)", 0x7ff8000000000000ull, 7, 7, false, false, false},
|
|
{"nan(123abc)", 0x7ff8000000123abcull, 11, 11, true, true, false},
|
|
{"nan(1x2)", 0x7ff8000000000000ull, 8, 8, true, true, false},
|
|
{"nan(0x1g)", 0x7ff8000000000000ull, 9, 9, true, true, false},
|
|
{"nan(g1)", 0x7ff8000000000000ull, 7, 7, true, true, false},
|
|
{"nan(0x0x1)", 0x7ff8000000000000ull, 10, 10, true, true, false},
|
|
{"nan(fffffffffffff)", 0x7fffffffffffffffull, 18, 18, true, true, false},
|
|
{"nan(1fffffffffffff)", 0x7fffffffffffffffull, 19, 19, true, true, false},
|
|
{"nan(10000000000000)", 0x7ff8000000000001ull, 19, 19, true, true, false},
|
|
{"nan(20000000000000)", 0x7ff8000000000001ull, 19, 19, true, true, false},
|
|
{"nan(0x20000000000000)", 0x7ff8000000000001ull, 21, 21, true, true, false},
|
|
{"nan(ffffffffffffffff)", 0x7fffffffffffffffull, 21, 21, true, true, false},
|
|
{"nan(10000000000000000)", 0x7ff8000000000001ull, 22, 22, true, true, false},
|
|
{"nan(0X)", 0x7ff8000000000000ull, 7, 7, true, true, false},
|
|
{"nan(-1)", 0x7ff8000000000000ull, 7, 3, true, true, false},
|
|
{"nan(+1)", 0x7ff8000000000000ull, 7, 3, true, true, false},
|
|
{"nan( 1)", 0x7ff8000000000001ull, 7, 3, true, true, false},
|
|
{"nan(1 )", 0x7ff8000100000000ull, 7, 3, true, true, false},
|
|
{"nan(0)", 0x7ff8000000000001ull, 6, 6, true, true, false},
|
|
{"nan(00001)", 0x7ff8000000000001ull, 10, 10, true, true, false},
|
|
{"nan(0x0001)", 0x7ff8000000000001ull, 11, 11, true, true, false},
|
|
{"nan(8000000000000)", 0x7ff8000000000000ull, 18, 18, true, true, false},
|
|
{"nan(7ffffffffffff)", 0x7fffffffffffffffull, 18, 18, true, true, false},
|
|
{"nan(123", 0x7ff8000000000123ull, 3, 3, true, true, false},
|
|
{"nan(1)x", 0x7ff8000000000001ull, 6, 6, true, true, false},
|
|
{"-nan(1)", 0xfff8000000000001ull, 7, 7, true, true, false},
|
|
{"nan(abcdefABCDEF)", 0x7ff8abcdefabcdefull, 17, 17, true, true, false},
|
|
{"nan(0xABCDEF)", 0x7ff8000000abcdefull, 13, 13, true, true, false},
|
|
{"nan(9)", 0x7ff8000000000009ull, 6, 6, true, true, false},
|
|
{"nan(1_2)", 0x7ff8000000000000ull, 8, 8, true, true, false},
|
|
{"nan(_1)", 0x7ff8000000000000ull, 7, 7, true, true, false},
|
|
{"nan(1)(2)", 0x7ff8000000000001ull, 6, 6, true, true, false},
|
|
{"+nan", 0x7ff8000000000000ull, 4, 4, true, true, true},
|
|
{"NaN", 0x7ff8000000000000ull, 3, 3, true, true, true},
|
|
{"-NAN(5)", 0xfff8000000000005ull, 7, 7, true, true, true},
|
|
{"nan(5)", 0x7ff8000000000005ull, 6, 6, true, true, true},
|
|
{"-nan(abc)", 0xfff8000000000abcull, 9, 9, true, true, true},
|
|
{" -nan", 0xfff8000000000000ull, 6, 6, true, true, true},
|
|
{"nan(12 x", 0x7ff8000000000000ull, 3, 3, true, true, true},
|
|
{"nan(12x", 0x7ff8000000000000ull, 3, 3, true, true, true},
|
|
{"nan(1", 0x7ff8000000000001ull, 3, 3, true, true, true},
|
|
{"nan(a b)", 0x7ff8000a0000000bull, 8, 3, true, true, true},
|
|
{"nan(ab)", 0x7ff80000000000abull, 7, 7, true, true, true},
|
|
{"nanx", 0x7ff8000000000000ull, 3, 3, true, true, true},
|
|
{"-nan()", 0xfff8000000000000ull, 6, 6, true, true, true},
|
|
{"nan(0x8000000000001)", 0x7ff8000000000001ull, 20, 20, true, true, true},
|
|
};
|
|
bool correct = true;
|
|
for (const auto& test : cases) {
|
|
char* end = nullptr;
|
|
const auto value = std::bit_cast<std::uint64_t>(strtod_nid_postfix(test.text, &end));
|
|
if (value != test.bits || end != test.text + test.used) {
|
|
std::fprintf(stderr, "strtod(\"%s\") = 0x%016llx\n", test.text, static_cast<unsigned long long>(value));
|
|
correct = false;
|
|
}
|
|
if (std::bit_cast<std::uint64_t>(atof_nid_postfix(test.text)) != test.bits) {
|
|
std::fprintf(stderr, "atof(\"%s\")\n", test.text);
|
|
correct = false;
|
|
}
|
|
const auto single = std::bit_cast<std::uint32_t>(strtof_nid_postfix(test.text, &end));
|
|
if (single != 0x7fc00000u || end != test.text + test.sequenceUsed) {
|
|
std::fprintf(stderr, "strtof(\"%s\") = 0x%08x\n", test.text, static_cast<unsigned>(single));
|
|
correct = false;
|
|
}
|
|
if (test.extendedMeasured) {
|
|
const long double extended = strtold_nid_postfix(test.text, &end);
|
|
if (!ExtendedBits(extended, 0xc000000000000000ull, 0x7fff) || end != test.text + test.sequenceUsed) {
|
|
std::fprintf(stderr, "strtold(\"%s\")\n", test.text);
|
|
correct = false;
|
|
}
|
|
}
|
|
char16_t wide[64] = {};
|
|
for (std::size_t i = 0; test.text[i] != 0; ++i) wide[i] = static_cast<unsigned char>(test.text[i]);
|
|
char16_t* wideEnd = nullptr;
|
|
if (test.wideDoubleMeasured) {
|
|
const auto wideValue = std::bit_cast<std::uint64_t>(wcstod_nid_postfix(wide, &wideEnd));
|
|
if (wideValue != test.bits || wideEnd != wide + test.used) {
|
|
std::fprintf(stderr, "wcstod(\"%s\") = 0x%016llx\n", test.text, static_cast<unsigned long long>(wideValue));
|
|
correct = false;
|
|
}
|
|
}
|
|
if (test.wideOtherMeasured) {
|
|
const auto wideSingle = std::bit_cast<std::uint32_t>(wcstof_nid_postfix(wide, &wideEnd));
|
|
const bool singleOk = wideSingle == 0x7fc00000u && wideEnd == wide + test.sequenceUsed;
|
|
const long double wideExtended = wcstold_nid_postfix(wide, &wideEnd);
|
|
if (!singleOk || !ExtendedBits(wideExtended, 0xc000000000000000ull, 0x7fff) || wideEnd != wide + test.sequenceUsed) {
|
|
std::fprintf(stderr, "wcstof/wcstold(\"%s\")\n", test.text);
|
|
correct = false;
|
|
}
|
|
}
|
|
}
|
|
Require(correct);
|
|
for (const char* text : {"nan(1 ", "nan(12 \t"}) {
|
|
bool threw = false;
|
|
try { strtod_nid_postfix(text, nullptr); } catch (...) { threw = true; }
|
|
Require(threw);
|
|
}
|
|
struct PlainNan { const char* text; std::uint64_t bits; std::size_t used; };
|
|
for (const PlainNan& plain : {PlainNan{"nan(1 2)", 0x7ff8000100000002ull, 8}, PlainNan{"nan( \0)", 0x7ff8000000000000ull, 3}}) {
|
|
char* end = nullptr;
|
|
Require(std::bit_cast<std::uint64_t>(strtod_nid_postfix(plain.text, &end)) == plain.bits && end == plain.text + plain.used);
|
|
}
|
|
}
|
|
|
|
static void CheckFloatUnderflowErrno() {
|
|
char* end = nullptr;
|
|
errno = 7;
|
|
Require(strtod_nid_postfix("1e-310", &end) == 1e-310 && errno == 7);
|
|
Require(strtod_nid_postfix("-4.9406564584124654e-324", &end) == -0x1p-1074 && errno == 7);
|
|
Require(strtold_nid_postfix("1e-4940", &end) == 1e-4940L && errno == 7);
|
|
Require(strtod_nid_postfix("1e-330", &end) == 0.0 && errno == ERANGE);
|
|
errno = 0;
|
|
Require(strtof_nid_postfix("1e-46", &end) == 0.0f && errno == ERANGE);
|
|
errno = 0;
|
|
Require(strtod_nid_postfix("1e400", &end) == HUGE_VAL && errno == ERANGE);
|
|
errno = 0;
|
|
Require(strtod_nid_postfix("2.2250738585072014e-308", &end) == 0x1p-1022 && errno == 0);
|
|
Require(strtod_nid_postfix("0x1.8p-1075", &end) == 0x1p-1074 && errno == ERANGE);
|
|
errno = 0;
|
|
Require(strtod_nid_postfix("-0x1.000001p-1075", &end) == -0x1p-1074 && errno == ERANGE);
|
|
errno = 0;
|
|
Require(strtod_nid_postfix("0x1p-1074", &end) == 0x1p-1074 && strtod_nid_postfix("0x1.8p-1074", &end) == 0x1p-1073 && errno == 0);
|
|
Require(strtod_nid_postfix("0x1p-1076", &end) == 0.0 && errno == ERANGE);
|
|
errno = 0;
|
|
Require(strtod_nid_postfix("0x1p+1100", &end) == HUGE_VAL && errno == ERANGE);
|
|
errno = 7;
|
|
Require(strtold_nid_postfix("0x1p-16446", &end) == 0.0L && strtold_nid_postfix("0x1p+20000", &end) == HUGE_VALL && errno == 7);
|
|
Require(strtof_nid_postfix("0x1p-149", &end) == 0x1p-149f && strtof_nid_postfix("0x1.8p-149", &end) == 0x1p-148f && strtof_nid_postfix("0x1.000001p-149", &end) == 0x1p-149f && errno == 7);
|
|
Require(strtof_nid_postfix("1.40129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125e-45", &end) == 0x1p-149f && strtof_nid_postfix("1.17549435e-38", &end) == 0x1p-126f && errno == 7);
|
|
Require(strtof_nid_postfix("0x1p-150", &end) == 0.0f && errno == ERANGE);
|
|
errno = 7;
|
|
Require(strtof_nid_postfix("0x1p+200", &end) == HUGE_VALF && errno == ERANGE);
|
|
errno = 7;
|
|
Require(strtof_nid_postfix("1e-40", &end) == 1e-40f && errno == ERANGE);
|
|
errno = 7;
|
|
Require(strtof_nid_postfix("-1e-45", &end) == -0x1p-149f && errno == ERANGE);
|
|
errno = 7;
|
|
Require(strtof_nid_postfix("3e-45", &end) == 0x1p-148f && errno == ERANGE);
|
|
Require(strtof_nid_postfix("1e39", &end) == HUGE_VALF && errno == ERANGE);
|
|
errno = 0;
|
|
}
|
|
|
|
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, 0, 0},
|
|
{"0xg", 16, 0, 0, 0},
|
|
{"0x", 16, 0, 0, 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, 0, 0},
|
|
{"0x!", 16, 0, 0, 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);
|
|
for (const int base : {-1, 1, 37}) {
|
|
const char text[] = " 12";
|
|
const auto rejects = [&](auto parse, int error) {
|
|
char* end = nullptr;
|
|
*__error_nid_postfix() = 0;
|
|
Require(parse(text, &end, base) == 0 && end == text && *__error_nid_postfix() == error);
|
|
};
|
|
rejects(strtol_nid_postfix, EINVAL);
|
|
rejects(strtoul_nid_postfix, EINVAL);
|
|
rejects(strtoll_nid_postfix, EINVAL);
|
|
rejects(strtoull_nid_postfix, EINVAL);
|
|
rejects(strtoimax_nid_postfix, 0);
|
|
rejects(strtoumax_nid_postfix, 0);
|
|
rejects(_Stoull_nid_postfix, 0);
|
|
rejects(_Stoul_nid_postfix, 0);
|
|
}
|
|
*__error_nid_postfix() = 0;
|
|
Require(atoi_nid_postfix("9223372036854775808") == 0 && atoi_nid_postfix("4294967297") == 1 && atoi_nid_postfix("-9223372036854775809") == -1);
|
|
Require(atol_nid_postfix("9223372036854775808") == INT64_MIN && atoll_nid_postfix("-9223372036854775809") == INT64_MAX && *__error_nid_postfix() == 0);
|
|
Require(atol_nid_postfix("99999999999999999999") == -1 && *__error_nid_postfix() == ERANGE);
|
|
*__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 CheckScaledHyperbolic() {
|
|
const int rounding = std::fegetround();
|
|
Require(std::fesetround(FE_TONEAREST) == 0);
|
|
unsigned checks = 0;
|
|
for (bool sine : {true, false}) {
|
|
const auto function = sine ? _FSinh_nid_postfix : _FCosh_nid_postfix;
|
|
const char* name = sine ? "_FSinh" : "_FCosh";
|
|
const auto checkValue = [&](float x, float y) {
|
|
const long double value = sine ? std::sinh(static_cast<long double>(x)) : std::cosh(static_cast<long double>(x));
|
|
const float expected = static_cast<float>(value * static_cast<long double>(y));
|
|
std::feclearexcept(FE_ALL_EXCEPT);
|
|
errno = 12345;
|
|
const float result = function(x, y);
|
|
const auto actualBits = std::bit_cast<std::uint32_t>(result);
|
|
const auto expectedBits = std::bit_cast<std::uint32_t>(expected);
|
|
const auto distance = actualBits > expectedBits ? actualBits - expectedBits : expectedBits - actualBits;
|
|
const bool exact = expected == 0.0f || std::isinf(expected);
|
|
if ((exact ? actualBits != expectedBits : !std::isfinite(result) || distance > 2) ||
|
|
(std::isfinite(expected) && (std::fetestexcept(FE_OVERFLOW | FE_INVALID) != 0 || errno != 12345))) {
|
|
std::fprintf(stderr, "%s(%a, %a): got %08x, expected %08x, errno %d, flags %x\n",
|
|
name, static_cast<double>(x), static_cast<double>(y), actualBits, expectedBits, errno, std::fetestexcept(FE_ALL_EXCEPT));
|
|
std::abort();
|
|
}
|
|
++checks;
|
|
};
|
|
checkValue(90.0f, 1e-20f);
|
|
checkValue(100.0f, 1e-40f);
|
|
const float magnitudes[] = {0.0f, 0x1p-126f, 0.001f, 0.5f, 1.0f, 4.0f, 7.0f, 8.0f, 10.0f, 20.0f, 50.0f, 88.0f, 90.0f, 100.0f, 150.0f, 180.0f, 190.0f, 193.0f};
|
|
const float scales[] = {0.0f, 0x1p-149f, 0x1p-140f, 0x1p-126f, 1e-20f, 0.5f, 1.0f, 1e20f, std::numeric_limits<float>::max()};
|
|
for (float magnitude : magnitudes) {
|
|
for (float scale : scales) {
|
|
for (float xSign : {1.0f, -1.0f}) {
|
|
for (float ySign : {1.0f, -1.0f}) checkValue(magnitude * xSign, scale * ySign);
|
|
}
|
|
}
|
|
}
|
|
for (float scale : scales) {
|
|
if (scale == 0.0f) continue;
|
|
for (long double target : {static_cast<long double>(std::numeric_limits<float>::max()), 0x1p-150L}) {
|
|
if (!sine && target < scale) continue;
|
|
const long double ratio = target / static_cast<long double>(scale);
|
|
const float boundary = static_cast<float>(sine ? std::asinh(ratio) : std::acosh(ratio));
|
|
float magnitude = std::nextafter(std::nextafter(boundary, -INFINITY), -INFINITY);
|
|
for (unsigned neighbor = 0; neighbor != 5; ++neighbor) {
|
|
for (float xSign : {1.0f, -1.0f}) {
|
|
for (float ySign : {1.0f, -1.0f}) checkValue(magnitude * xSign, scale * ySign);
|
|
}
|
|
magnitude = std::nextafter(magnitude, INFINITY);
|
|
}
|
|
}
|
|
}
|
|
const auto checkSpecial = [&](float x, float y, std::uint32_t expectedBits, int error, int flags) {
|
|
std::feclearexcept(FE_ALL_EXCEPT);
|
|
std::feraiseexcept(FE_DIVBYZERO);
|
|
errno = 12345;
|
|
const float result = function(x, y);
|
|
const int raised = std::fetestexcept(FE_ALL_EXCEPT);
|
|
if (std::bit_cast<std::uint32_t>(result) != expectedBits || errno != error || raised != (FE_DIVBYZERO | flags)) {
|
|
std::fprintf(stderr, "%s special (%a, %a): got %08x, expected %08x, errno %d, flags %x\n",
|
|
name, static_cast<double>(x), static_cast<double>(y), std::bit_cast<std::uint32_t>(result), expectedBits, errno, raised);
|
|
std::abort();
|
|
}
|
|
++checks;
|
|
};
|
|
const float infinity = std::numeric_limits<float>::infinity();
|
|
for (float sign : {1.0f, -1.0f}) {
|
|
checkSpecial(sign * infinity, 0.0f, 0x7fc00000u, EDOM, FE_INVALID);
|
|
checkSpecial(sign * 100.0f, 0.0f, sine && sign < 0 ? 0x80000000u : 0u, 12345, 0);
|
|
checkSpecial(sign * 100.0f, -0.0f, sine && sign < 0 ? 0u : 0x80000000u, 12345, 0);
|
|
checkSpecial(sign * 1.0f, infinity, sine && sign < 0 ? 0xff800000u : 0x7f800000u, 12345, 0);
|
|
}
|
|
for (std::uint32_t bits : {0x7fc12345u, 0xffc54321u, 0x7fa12345u, 0xffa54321u}) {
|
|
const float nan = std::bit_cast<float>(bits);
|
|
checkSpecial(nan, 0.0f, bits, 12345, 0);
|
|
checkSpecial(infinity, nan, bits, 12345, 0);
|
|
checkSpecial(nan, std::bit_cast<float>(0x7fc99999u), bits, 12345, 0);
|
|
}
|
|
checkSpecial(0.0f, infinity, sine ? 0x7fc00000u : 0x7f800000u, sine ? EDOM : 12345, sine ? FE_INVALID : 0);
|
|
checkSpecial(1.0f, std::numeric_limits<float>::max(), 0x7f800000u, 12345, FE_OVERFLOW | FE_INEXACT);
|
|
checkSpecial(100.0f, 1.0f, 0x7f800000u, ERANGE, FE_OVERFLOW | FE_INEXACT);
|
|
for (int mode : {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO}) {
|
|
Require(std::fesetround(mode) == 0);
|
|
checkSpecial(std::numeric_limits<float>::max(), 0x1p-149f, 0x7f800000u, ERANGE, FE_OVERFLOW | FE_INEXACT);
|
|
}
|
|
Require(std::fesetround(FE_TONEAREST) == 0);
|
|
if (sine) checkSpecial(0x1p-126f, 0x1p-149f, 0u, 12345, FE_UNDERFLOW | FE_INEXACT);
|
|
}
|
|
std::feclearexcept(FE_ALL_EXCEPT);
|
|
Require(std::fesetround(rounding) == 0);
|
|
std::printf("Scaled hyperbolic checks: %u\n", checks);
|
|
}
|
|
|
|
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 RequireBytes(const void* constant, std::initializer_list<unsigned char> expected) {
|
|
unsigned char bytes[16];
|
|
std::memcpy(bytes, constant, sizeof(bytes));
|
|
int index = 0;
|
|
for (const unsigned char byte : expected) Require(bytes[index++] == byte);
|
|
while (index < 16) Require(bytes[index++] == 0);
|
|
}
|
|
|
|
static void CheckDinkumwareConstants() {
|
|
RequireBytes(&_Inf_nid_postfix, {0, 0, 0, 0, 0, 0, 0xf0, 0x7f});
|
|
RequireBytes(&_Denorm_nid_postfix, {1});
|
|
RequireBytes(&_Hugeval_nid_postfix, {0, 0, 0, 0, 0, 0, 0xf0, 0x7f});
|
|
RequireBytes(&_Nan_nid_postfix, {0, 0, 0, 0, 0, 0, 0xf8, 0x7f});
|
|
RequireBytes(&_Snan_nid_postfix, {1, 0, 0, 0, 0, 0, 0xf0, 0x7f});
|
|
RequireBytes(&_FDenorm_nid_postfix, {1});
|
|
RequireBytes(&_FSnan_nid_postfix, {1, 0, 0x80, 0x7f});
|
|
RequireBytes(&_LDenorm_nid_postfix, {1});
|
|
RequireBytes(&_LInf_nid_postfix, {0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f});
|
|
RequireBytes(&_LNan_nid_postfix, {0, 0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f});
|
|
RequireBytes(&_LSnan_nid_postfix, {1, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f});
|
|
Require(_Dtest_nid_postfix(&_Denorm_nid_postfix._Double) == -2 && _Denorm_nid_postfix._Double == std::numeric_limits<double>::denorm_min());
|
|
Require(_Dtest_nid_postfix(&_Hugeval_nid_postfix._Double) == 1 && _Hugeval_nid_postfix._Double == HUGE_VAL);
|
|
Require(_Dtest_nid_postfix(&_Nan_nid_postfix._Double) == 2 && _Dtest_nid_postfix(&_Snan_nid_postfix._Double) == 2);
|
|
Require(_FDtest_nid_postfix(reinterpret_cast<const float*>(&_FDenorm_nid_postfix)) == -2);
|
|
Require(_FDtest_nid_postfix(reinterpret_cast<const float*>(&_FSnan_nid_postfix)) == 2);
|
|
Require(_LDenorm_nid_postfix._Long_double == std::numeric_limits<long double>::denorm_min());
|
|
Require(_LInf_nid_postfix._Long_double == std::numeric_limits<long double>::infinity());
|
|
Require(std::isnan(_LNan_nid_postfix._Long_double) && std::isnan(_LSnan_nid_postfix._Long_double));
|
|
}
|
|
|
|
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())));
|
|
Require(significand_nid_postfix(12.0) == 1.5 && significand_nid_postfix(-0.375) == -1.5);
|
|
Require(significand_nid_postfix(0x1p-1074) == 1.0);
|
|
Require(std::signbit(significand_nid_postfix(-0.0)) && significand_nid_postfix(-0.0) == 0.0);
|
|
Require(significand_nid_postfix(std::numeric_limits<double>::infinity()) == std::numeric_limits<double>::infinity());
|
|
Require(std::isnan(significand_nid_postfix(std::numeric_limits<double>::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(tgammaf_nid_postfix(5.0f) == 24.0f && std::abs(tgammaf_nid_postfix(0.5f) - 1.77245385f) < 1e-6f);
|
|
Require(tgammaf_nid_postfix(1.0f) == 1.0f && tgammaf_nid_postfix(2.0f) == 1.0f && tgammaf_nid_postfix(3.0f) == 2.0f);
|
|
Require(std::isinf(tgammaf_nid_postfix(0.0f)) && std::isnan(tgammaf_nid_postfix(-1.0f)));
|
|
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 CheckNoConversionZero() {
|
|
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 bool negative = std::strchr(text, '-') != nullptr;
|
|
const float parsedFloat = strtof_nid_postfix(text, &end);
|
|
Require(parsedFloat == 0.f && std::signbit(parsedFloat) == negative && end == text);
|
|
const long double parsedLong = strtold_nid_postfix(text, &end);
|
|
Require(parsedLong == 0.L && std::signbit(parsedLong) == negative && end == text);
|
|
Require(!std::signbit(atof_nid_postfix(text)));
|
|
}
|
|
for (const char* text : {"-i", "-in", "-N", "-nax"}) {
|
|
char* end = nullptr;
|
|
const float parsedFloat = strtof_nid_postfix(text, &end);
|
|
Require(parsedFloat == 0.f && !std::signbit(parsedFloat) && end == text);
|
|
Require(!std::signbit(strtold_nid_postfix(text, nullptr)));
|
|
}
|
|
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);
|
|
}
|
|
|
|
template<typename TValue, std::size_t TBytes>
|
|
static void RequireCharacteristic(const unsigned char (&constant)[16], TValue expected) {
|
|
TValue value;
|
|
std::memcpy(&value, constant, sizeof(value));
|
|
Require(value == expected);
|
|
for (std::size_t index = TBytes; index < 16; ++index) Require(constant[index] == 0);
|
|
}
|
|
|
|
template<typename TValue, std::size_t TBytes>
|
|
static void RequireCharacteristics(const DinkumwareFloatCharacteristics& table, const int (&integers)[6]) {
|
|
const int fields[] = {table.digits, table.mantissaDigits, table.maxExponent10, table.maxExponent, table.minExponent10, table.minExponent};
|
|
for (int index = 0; index < 6; ++index) Require(fields[index] == integers[index]);
|
|
RequireCharacteristic<TValue, TBytes>(table.epsilon, std::numeric_limits<TValue>::epsilon());
|
|
RequireCharacteristic<TValue, TBytes>(table.max, std::numeric_limits<TValue>::max());
|
|
RequireCharacteristic<TValue, TBytes>(table.min, std::numeric_limits<TValue>::min());
|
|
}
|
|
|
|
static void CheckDinkumwareFloatCharacteristics() {
|
|
static_assert(sizeof(DinkumwareFloatCharacteristics) == 80 && offsetof(DinkumwareFloatCharacteristics, epsilon) == 32);
|
|
RequireCharacteristics<float, 4>(_Flt_nid_postfix, {FLT_DIG, FLT_MANT_DIG, FLT_MAX_10_EXP, FLT_MAX_EXP, FLT_MIN_10_EXP, FLT_MIN_EXP});
|
|
RequireCharacteristics<double, 8>(_Dbl_nid_postfix, {DBL_DIG, DBL_MANT_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, DBL_MIN_10_EXP, DBL_MIN_EXP});
|
|
RequireCharacteristics<long double, 10>(_Ldbl_nid_postfix, {18, 64, 4932, 16384, -4931, -16381});
|
|
for (const auto* table : {&_Flt_nid_postfix, &_Dbl_nid_postfix, &_Ldbl_nid_postfix})
|
|
for (std::size_t index = 24; index < 32; ++index) Require(reinterpret_cast<const unsigned char*>(table)[index] == 0);
|
|
}
|
|
|
|
int main() {
|
|
CheckFloatClassification();
|
|
CheckDinkumwareConstants();
|
|
CheckNoConversionZero();
|
|
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();
|
|
CheckScaledHyperbolic();
|
|
CheckSinhf();
|
|
CheckAtanhf();
|
|
CheckHypotSpecialValue();
|
|
CheckFloatUnderflowErrno();
|
|
CheckFmodErrno();
|
|
CheckDoubleClassification();
|
|
CheckIntegerAbsAndDivision();
|
|
CheckScaling();
|
|
CheckLongDoubleFunctions();
|
|
CheckDinkumwareFloatCharacteristics();
|
|
}
|