diff --git a/core/libs/prx/libc/src/Math.cpp b/core/libs/prx/libc/src/Math.cpp index 1720c1e278..7e91356869 100644 --- a/core/libs/prx/libc/src/Math.cpp +++ b/core/libs/prx/libc/src/Math.cpp @@ -302,7 +302,11 @@ float APS5_VABI log1pf_nid_postfix(float x) { return std::log1p(x); } double APS5_VABI expm1_nid_postfix(double x) { return std::expm1(x); } float APS5_VABI expm1f_nid_postfix(float x) { return std::expm1(x); } float APS5_VABI erff_nid_postfix(float x) { return std::erf(x); } -double APS5_VABI lgamma_nid_postfix(double x) { return std::lgamma(x); } +double APS5_VABI lgamma_nid_postfix(double x) { + const std::uint64_t magnitude = std::bit_cast(x) & 0x7fffffffffffffffull; + if (magnitude != 0 && magnitude < 0x3c70000000000000ull) return -std::log(std::fabs(x)); + return std::lgamma(x); +} float APS5_VABI sinf_nid_postfix(float x) { return std::sin(x); } float APS5_VABI cosf_nid_postfix(float x) { return std::cos(x); } diff --git a/core/libs/tests/GuestMath.cpp b/core/libs/tests/GuestMath.cpp index 25b5bc592f..ed422b3b41 100644 --- a/core/libs/tests/GuestMath.cpp +++ b/core/libs/tests/GuestMath.cpp @@ -924,6 +924,14 @@ int main() { 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::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); + } 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}) {