diff --git a/include/fmt/format.h b/include/fmt/format.h index f74ad7a9..1bf3bebe 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3354,8 +3354,11 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs, const int shift = ((print_xdigits - specs.precision - 1) * 4); const auto mask = carrier_uint(0xF) << shift; const auto v = static_cast((f.f & mask) >> shift); + // Round half to even like printf. + const bool odd = ((f.f >> (shift + 4)) & 1) != 0; + const bool rest_is_zero = (f.f & ((carrier_uint(1) << shift) - 1)) == 0; - if (v >= 8) { + if (v > 8 || (v == 8 && (odd || !rest_is_zero))) { const auto inc = carrier_uint(1) << (shift + 4); f.f += inc; f.f &= ~(inc - 1); diff --git a/test/format-test.cc b/test/format-test.cc index c44db6ab..6a403967 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1749,6 +1749,11 @@ TEST(format_test, format_double) { } EXPECT_EQ(fmt::format("{:.10a}", 4.2), "0x1.0ccccccccdp+2"); + // Ties round to even like printf. + EXPECT_EQ(fmt::format("{:.1a}", 1.03125), "0x1.0p+0"); + EXPECT_EQ(fmt::format("{:.1a}", 1.09375), "0x1.2p+0"); + EXPECT_EQ(fmt::format("{:.1a}", 1.0322265625), "0x1.1p+0"); + EXPECT_EQ(fmt::format("{:.1A}", 1.03125f), "0X1.0P+0"); EXPECT_EQ(fmt::format("{:a}", -42.0), "-0x1.5p+5"); EXPECT_EQ(fmt::format("{:A}", -42.0), "-0X1.5P+5");