From 5d804ee7fe9b197b29d2012191f7af74bcc1a837 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 17 Apr 2022 08:12:38 -0700 Subject: [PATCH] Fix handling of subnormals in exotic FP --- include/fmt/format-inl.h | 13 +++++-------- test/format-test.cc | 2 ++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 99023abd9277..feb7815d65f1 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -216,7 +216,7 @@ template struct basic_fp { template FMT_CONSTEXPR basic_fp(Float n) { assign(n); } // Assigns n to this and return true iff predecessor is closer than successor. - template FMT_CONSTEXPR bool assign(Float n) { + template FMT_CONSTEXPR auto assign(Float n) -> bool { static_assert((std::numeric_limits::is_iec559 && std::numeric_limits::digits <= 113) || is_float128::value, @@ -250,7 +250,7 @@ using fp = basic_fp; template FMT_CONSTEXPR basic_fp normalize(basic_fp value) { // Handle subnormals. - const uint64_t implicit_bit = 1ULL << num_significand_bits(); + const auto implicit_bit = F(1) << num_significand_bits(); const auto shifted_implicit_bit = implicit_bit << SHIFT; while ((value.f & shifted_implicit_bit) == 0) { value.f <<= 1; @@ -2212,17 +2212,14 @@ FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision, unsigned dragon_flags = 0; if (!is_fast_float()) { const auto inv_log2_10 = 0.3010299956639812; // 1 / log2(10) - const auto e = basic_fp::carrier_uint>(converted_value) - .e; + using info = dragonbox::float_info; + const auto f = basic_fp(converted_value); // Compute exp, an approximate power of 10, such that // 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1). // This is based on log10(value) == log2(value) / log2(10) and approximation // of log2(value) by e + num_fraction_bits idea from double-conversion. - auto num_fraction_bits = - num_significand_bits() - (has_implicit_bit() ? 0 : 1); exp = static_cast( - std::ceil((e + num_fraction_bits) * inv_log2_10 - 1e-10)); + std::ceil((f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10)); dragon_flags = dragon::fixup; } else if (!is_constant_evaluated() && precision < 0) { // Use Dragonbox for the shortest format. diff --git a/test/format-test.cc b/test/format-test.cc index 5acffab91039..7d81e6009be9 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1009,6 +1009,8 @@ TEST(format_test, precision) { if (std::numeric_limits::digits == 64) { auto ld = (std::numeric_limits::min)(); EXPECT_EQ(fmt::format("{:.0}", ld), "3e-4932"); + EXPECT_EQ(fmt::format("{:0g}", 5.02957084971264961283E-4940L), + "5.02957e-4940"); } EXPECT_EQ("123.", fmt::format("{:#.0f}", 123.0));