From 9c19ea466408e1872fb26cfc734eab9e5490d9d2 Mon Sep 17 00:00:00 2001 From: Shawn <97796289+ShawnNotFound@users.noreply.github.com> Date: Sun, 8 Nov 2026 03:25:38 +0000 Subject: [PATCH] Fix precision formatting of long double values just below a power of 10 (#5010) * Fix precision formatting of long double values just below a power of 10 format_dragon included the upper boundary when checking whether the estimated exponent is one too high. This is needed for the shortest output, but with a given precision it left a leading zero digit, so values such as nextafter(1e43L, 0) were printed with an extra digit in fixed notation or a mantissa below 1 in exponent notation. * Apply clang-format --- include/fmt/format.h | 8 +++++++- test/format-test.cc | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 2b7a933f..b3e3fb86 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3254,7 +3254,13 @@ FMT_CONSTEXPR20 inline void format_dragon(basic_fp value, if (!upper) upper = &lower; bool shortest = num_digits < 0; if ((flags & dragon::fixup) != 0) { - if (add_compare(numerator, *upper, denominator) + even <= 0) { + // In the shortest mode the upper boundary is included because the output + // may round up to the next power of 10. With a given number of digits, + // rounding happens after digit generation, so only the value is compared. + bool too_high = + shortest ? add_compare(numerator, *upper, denominator) + even <= 0 + : compare(numerator, denominator) < 0; + if (too_high) { --exp10; numerator *= 10; if (num_digits < 0) { diff --git a/test/format-test.cc b/test/format-test.cc index c61d2ce4..19f1fd52 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1283,6 +1283,16 @@ TEST(format_test, precision) { EXPECT_EQ( fmt::format("{:0g}", std::numeric_limits::denorm_min()), "3.6452e-4951"); + + // Values just below a power of 10 where the initial exponent estimate is + // one too high. + ld = std::ldexp(static_cast(0x83126e978d4fdf3bULL), -73); + EXPECT_EQ(fmt::format("{:.20e}", ld), "9.99999999999999999958e-04"); + ld = std::ldexp(static_cast(0xe596b7b0c643c719ULL), 79); + EXPECT_EQ(fmt::format("{:.0f}", ld), + "9999999999999999999741184793924429452148736"); + EXPECT_EQ(fmt::format("{:.19e}", ld), "9.9999999999999999997e+42"); + EXPECT_EQ(fmt::format("{:.21g}", ld), "9.99999999999999999974e+42"); } EXPECT_EQ(fmt::format("{:#.0f}", 123.0), "123.");