mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 00:22:57 -05:00
fmin, fmax and their f and l forms tested their operands with std::isnan, which GCC compiles to a compare that raises FE_INVALID for a signalling NaN. FreeBSD's s_fmax.c and s_fmin.c read the exponent and significand bits instead, "to avoid raising spurious exceptions", and return the other operand. The NaN test now reads the bits of float, double and the 80-bit long double. GuestFminf checks that a signalling NaN on either side returns the other operand and leaves FE_INVALID clear, for all three types. The failure was first caught by the numeric helper test of boykopovar/AnyPS5#2280 (Привалов Александр Владимирович). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
3.2 KiB
C++
80 lines
3.2 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <cfenv>
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <limits>
|
|
|
|
extern "C" {
|
|
double APS5_VABI fmin_nid_postfix(double, double);
|
|
float APS5_VABI fminf_nid_postfix(float, float);
|
|
long double APS5_VABI fminl_nid_postfix(long double, long double);
|
|
double APS5_VABI fmax_nid_postfix(double, double);
|
|
float APS5_VABI fmaxf_nid_postfix(float, float);
|
|
long double APS5_VABI fmaxl_nid_postfix(long double, long double);
|
|
}
|
|
|
|
static void Check(bool condition, const char* name, int line) {
|
|
if (!condition) {
|
|
std::fprintf(stderr, "%s check failed at line %d\n", name, line);
|
|
std::abort();
|
|
}
|
|
}
|
|
#define Require(value) Check((value), name, __LINE__)
|
|
|
|
template <typename T>
|
|
static void CheckMinAndMax(T (APS5_VABI *minimum)(T, T), T (APS5_VABI *maximum)(T, T), const char* name) {
|
|
const auto nan = std::numeric_limits<T>::quiet_NaN();
|
|
const auto infinity = std::numeric_limits<T>::infinity();
|
|
|
|
Require(minimum(T(3.0), T(-2.0)) == T(-2.0));
|
|
Require(minimum(T(-2.0), T(3.0)) == T(-2.0));
|
|
Require(minimum(T(1.5), T(2.5)) == T(1.5));
|
|
Require(maximum(T(3.0), T(-2.0)) == T(3.0));
|
|
Require(maximum(T(-2.0), T(3.0)) == T(3.0));
|
|
Require(maximum(T(1.5), T(2.5)) == T(2.5));
|
|
|
|
Require(minimum(nan, T(4.0)) == T(4.0));
|
|
Require(minimum(T(4.0), nan) == T(4.0));
|
|
Require(std::isnan(minimum(nan, nan)));
|
|
Require(maximum(nan, T(4.0)) == T(4.0));
|
|
Require(maximum(T(4.0), nan) == T(4.0));
|
|
Require(std::isnan(maximum(nan, nan)));
|
|
|
|
const auto signaling = std::numeric_limits<T>::signaling_NaN();
|
|
std::feclearexcept(FE_ALL_EXCEPT);
|
|
Require(minimum(signaling, T(4.0)) == T(4.0) && minimum(T(4.0), signaling) == T(4.0));
|
|
Require(maximum(signaling, T(4.0)) == T(4.0) && maximum(T(4.0), signaling) == T(4.0));
|
|
Require(std::fetestexcept(FE_INVALID) == 0);
|
|
|
|
Require(std::signbit(minimum(T(-0.0), T(+0.0))));
|
|
Require(std::signbit(minimum(T(+0.0), T(-0.0))));
|
|
Require(std::signbit(minimum(T(-0.0), T(-0.0))));
|
|
Require(!std::signbit(minimum(T(+0.0), T(+0.0))));
|
|
Require(!std::signbit(maximum(T(-0.0), T(+0.0))));
|
|
Require(!std::signbit(maximum(T(+0.0), T(-0.0))));
|
|
Require(std::signbit(maximum(T(-0.0), T(-0.0))));
|
|
Require(!std::signbit(maximum(T(+0.0), T(+0.0))));
|
|
|
|
Require(minimum(infinity, -infinity) == -infinity);
|
|
Require(minimum(-infinity, infinity) == -infinity);
|
|
Require(minimum(infinity, T(5.0)) == T(5.0));
|
|
Require(minimum(T(5.0), infinity) == T(5.0));
|
|
Require(minimum(-infinity, T(5.0)) == -infinity);
|
|
Require(minimum(T(5.0), -infinity) == -infinity);
|
|
Require(maximum(infinity, -infinity) == infinity);
|
|
Require(maximum(-infinity, infinity) == infinity);
|
|
Require(maximum(infinity, T(5.0)) == infinity);
|
|
Require(maximum(T(5.0), infinity) == infinity);
|
|
Require(maximum(-infinity, T(5.0)) == T(5.0));
|
|
Require(maximum(T(5.0), -infinity) == T(5.0));
|
|
}
|
|
|
|
int main() {
|
|
CheckMinAndMax<double>(fmin_nid_postfix, fmax_nid_postfix, "fmin/fmax");
|
|
CheckMinAndMax<float>(fminf_nid_postfix, fmaxf_nid_postfix, "fminf/fmaxf");
|
|
CheckMinAndMax<long double>(fminl_nid_postfix, fmaxl_nid_postfix, "fminl/fmaxl");
|
|
|
|
return 0;
|
|
}
|