From 1aa8489402c38621daee9a193f19e39814eb9199 Mon Sep 17 00:00:00 2001 From: Alex Dewar Date: Thu, 2 May 2024 14:46:57 +0100 Subject: [PATCH 1/2] Fix: isnan() shouldn't cause FP exceptions Fixes #3948. --- include/fmt/format.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index f4b2c53d13b3..95df0ad00d3b 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -2695,7 +2695,7 @@ FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& f, } template constexpr auto isnan(T value) -> bool { - return !(value >= value); // std::isnan doesn't support __float128. + return value != value; // std::isnan doesn't support __float128. } template From 41e75ee9d5aef98f55e094e19331153fdfd125e1 Mon Sep 17 00:00:00 2001 From: Alex Dewar Date: Thu, 2 May 2024 14:54:23 +0100 Subject: [PATCH 2/2] Add tests to check that isnan doesn't cause FP errors --- test/format-test.cc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/format-test.cc b/test/format-test.cc index 3f5e191ce577..257b6ead7a8f 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -15,6 +15,7 @@ #include // uint32_t +#include // fegetexceptflag and FE_ALL_EXCEPT #include // INT_MAX #include // std::signbit #include // std::condition_variable @@ -109,6 +110,14 @@ TEST(float_test, isfinite) { #endif } +void check_no_fp_exception() { + fexcept_t fe; + fegetexceptflag(&fe, FE_ALL_EXCEPT); + + // No exception flags should have been set + EXPECT_TRUE(fe == 0); +} + template void check_isnan() { using fmt::detail::isnan; EXPECT_FALSE(isnan(Float(0.0))); @@ -121,6 +130,17 @@ template void check_isnan() { EXPECT_FALSE(isnan(Float(-limits::infinity()))); EXPECT_TRUE(isnan(Float(limits::quiet_NaN()))); EXPECT_TRUE(isnan(Float(-limits::quiet_NaN()))); + + // Sanity check: make sure no error has occurred before we start + check_no_fp_exception(); + + // Check that no exception is raised for the non-NaN case + isnan(Float(42.0)); + check_no_fp_exception(); + + // Check that no exception is raised for the NaN case + isnan(Float(limits::quiet_NaN())); + check_no_fp_exception(); } TEST(float_test, isnan) {