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
This commit is contained in:
Shawn 2026-11-08 03:25:38 +00:00 committed by GitHub
parent d102a01edf
commit 9c19ea4664
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 17 additions and 1 deletions

View File

@ -3254,7 +3254,13 @@ FMT_CONSTEXPR20 inline void format_dragon(basic_fp<uint128_t> 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) {

View File

@ -1283,6 +1283,16 @@ TEST(format_test, precision) {
EXPECT_EQ(
fmt::format("{:0g}", std::numeric_limits<long double>::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<long double>(0x83126e978d4fdf3bULL), -73);
EXPECT_EQ(fmt::format("{:.20e}", ld), "9.99999999999999999958e-04");
ld = std::ldexp(static_cast<long double>(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.");