mirror of
https://github.com/fmtlib/fmt.git
synced 2026-11-09 14:50:24 +08:00
Format zero as 0x0p+0 in hexfloat (#4878)
fmt::format("{:a}", 0.0) produced 0x0p-1022 where printf's %a gives
0x0p+0, and likewise for -0.0, {:A}, {:#a} and any explicit precision.
basic_fp::assign maps a zero biased exponent to 1 ("subnormals use
biased exponent 1"), which is right for subnormals but not for zero, so
format_hexfloat inherited the minimum subnormal exponent for a value
whose significand carries no information. Reset the exponent there
rather than in assign, which the decimal path shares.
A zero significand can only come from +-0: normals get the implicit bit
added, and a subnormal has a nonzero significand by definition. So the
guard cannot affect anything else, and denorm_min keeps its existing
denormalized form (0x0.0000000000001p-1022, asserted in format_double).
The five new expectations were taken from printf rather than derived,
and all fail without this change.
This commit is contained in:
parent
0cf9f5c99e
commit
6c285ba88a
@ -3110,6 +3110,11 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs,
|
||||
f.e += num_float_significand_bits;
|
||||
if (!has_implicit_bit<Float>()) --f.e;
|
||||
|
||||
// basic_fp maps a zero biased exponent to the minimum subnormal exponent,
|
||||
// which is correct for subnormals but not for zero: printf prints zero as
|
||||
// 0x0p+0. A zero significand can only come from +-0, so reset the exponent.
|
||||
if (f.f == 0) f.e = 0;
|
||||
|
||||
const auto num_fraction_bits =
|
||||
num_float_significand_bits + (has_implicit_bit<Float>() ? 1 : 0);
|
||||
const auto num_xdigits = (num_fraction_bits + 3) / 4;
|
||||
|
||||
@ -1539,6 +1539,13 @@ TEST(format_test, format_double) {
|
||||
|
||||
d = std::numeric_limits<double>::denorm_min();
|
||||
EXPECT_EQ(fmt::format("{:a}", d), "0x0.0000000000001p-1022");
|
||||
|
||||
// Zero has no subnormal exponent: printf prints it as 0x0p+0.
|
||||
EXPECT_EQ(fmt::format("{:a}", 0.0), "0x0p+0");
|
||||
EXPECT_EQ(fmt::format("{:a}", -0.0), "-0x0p+0");
|
||||
EXPECT_EQ(fmt::format("{:A}", 0.0), "0X0P+0");
|
||||
EXPECT_EQ(fmt::format("{:#a}", 0.0), "0x0.p+0");
|
||||
EXPECT_EQ(fmt::format("{:.3a}", 0.0), "0x0.000p+0");
|
||||
}
|
||||
|
||||
if (std::numeric_limits<long double>::digits == 64) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user