diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 8f51acf4..7872fb4b 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -1388,15 +1388,6 @@ struct chrono_format_checker : null_chrono_spec_handler { FMT_CONSTEXPR void on_duration_unit() {} }; -template ::value)> -inline bool isnan(T) { - return false; -} -template ::value)> -inline bool isnan(T value) { - return std::isnan(value); -} - template ::value)> inline bool isfinite(T) { return true; diff --git a/include/fmt/format.h b/include/fmt/format.h index eefc727d..051ae040 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1905,11 +1905,11 @@ FMT_CONSTEXPR auto write(OutputIt out, const Char* s, } template -FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isinf, +FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan, basic_format_specs specs, const float_specs& fspecs) -> OutputIt { auto str = - isinf ? (fspecs.upper ? "INF" : "inf") : (fspecs.upper ? "NAN" : "nan"); + isnan ? (fspecs.upper ? "NAN" : "nan") : (fspecs.upper ? "INF" : "inf"); constexpr size_t str_size = 3; auto sign = fspecs.sign; auto size = str_size + (sign ? 1 : 0); @@ -2182,16 +2182,8 @@ constexpr bool isfinite(T value) { return value - value == 0; // std::isfinite doesn't support __float128. } -template ::value && - !is_float128::value)> -FMT_CONSTEXPR20 bool isinf(T value) { - if (is_constant_evaluated()) return !isfinite(value) && value == value; - return std::isinf(value); -} -template ::value)> -constexpr bool isinf(T value) { - // std::isinf doesn't support __float128. - return !isfinite(value) && value == value; +template constexpr bool isnan(T value) { + return value != value; // std::isnan doesn't support __float128. } template ::value)> @@ -2200,7 +2192,7 @@ FMT_INLINE FMT_CONSTEXPR bool signbit(T value) { #ifdef __cpp_if_constexpr if constexpr (std::numeric_limits::is_iec559) { auto bits = detail::bit_cast(static_cast(value)); - return (bits & (uint64_t(1) << (num_bits() - 1))) != 0; + return (bits >> (num_bits() - 1)) != 0; } #endif } @@ -2223,7 +2215,7 @@ FMT_CONSTEXPR20 auto write(OutputIt out, T value, } if (!detail::isfinite(value)) - return write_nonfinite(out, detail::isinf(value), specs, fspecs); + return write_nonfinite(out, detail::isnan(value), specs, fspecs); if (specs.align == align::numeric && fspecs.sign) { auto it = reserve(out, 1); @@ -2279,7 +2271,7 @@ FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { constexpr auto specs = basic_format_specs(); uint mask = exponent_mask(); if ((bits & mask) == mask) - return write_nonfinite(out, std::isinf(value), specs, fspecs); + return write_nonfinite(out, std::isnan(value), specs, fspecs); auto dec = dragonbox::to_decimal(static_cast(value)); return write_float(out, dec, specs, fspecs, {}); diff --git a/test/format-test.cc b/test/format-test.cc index 8c0056e6..e7f65daf 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -87,6 +87,27 @@ TEST(float_test, isfinite) { #endif } +template void check_isnan() { + using fmt::detail::isnan; + EXPECT_FALSE(isnan(Float(0.0))); + EXPECT_FALSE(isnan(Float(42.0))); + EXPECT_FALSE(isnan(Float(-42.0))); + EXPECT_FALSE(isnan(Float(fmt::detail::max_value()))); + // Use double because std::numeric_limits is broken for __float128. + using limits = std::numeric_limits; + EXPECT_FALSE(isnan(Float(limits::infinity()))); + EXPECT_FALSE(isnan(Float(-limits::infinity()))); + EXPECT_TRUE(isnan(Float(limits::quiet_NaN()))); + EXPECT_TRUE(isnan(Float(-limits::quiet_NaN()))); +} + +TEST(float_test, isnan) { + check_isnan(); +#ifdef __SIZEOF_FLOAT128__ + check_isnan(); +#endif +} + struct uint32_pair { uint32_t u[2]; };