From b8d34e0db34c41a3874e8657208537ca48fcbf01 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 2 Feb 2019 08:49:25 -0800 Subject: [PATCH] Fix rounding --- include/fmt/format-inl.h | 13 ++++++++----- include/fmt/format.h | 2 +- test/grisu-test.cc | 7 ++++++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 40040020..c1ec62f7 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -266,7 +266,9 @@ const char basic_data::DIGITS[] = factor * 1000000000 template -const uint32_t basic_data::POWERS_OF_10_32[] = {1, FMT_POWERS_OF_10(1)}; +const uint64_t basic_data::POWERS_OF_10_64[] = { + 1, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(1000000000ull), + 10000000000000000000ull}; template const uint32_t basic_data::ZERO_OR_POWERS_OF_10_32[] = {0, @@ -334,7 +336,7 @@ template const wchar_t basic_data::WRESET_COLOR[] = L"\x1b[0m"; template struct bits { static FMT_CONSTEXPR_DECL const int value = - sizeof(T) * std::numeric_limits::digits; + static_cast(sizeof(T) * std::numeric_limits::digits); }; // A handmade floating-point number f * pow(2, e). @@ -523,7 +525,7 @@ FMT_FUNC int grisu2_gen_digits(char* buf, uint32_t hi, uint64_t lo, int& exp, uint64_t remainder = (static_cast(hi) << -one.e) + lo; if (remainder <= delta || size > max_digits) { return grisu2_round(buf, size, max_digits, delta, remainder, - static_cast(data::POWERS_OF_10_32[exp]) + static_cast(data::POWERS_OF_10_64[exp]) << -one.e, diff.f, exp) ? size @@ -540,7 +542,7 @@ FMT_FUNC int grisu2_gen_digits(char* buf, uint32_t hi, uint64_t lo, int& exp, --exp; if (lo < delta || size > max_digits) { return grisu2_round(buf, size, max_digits, delta, lo, one.f, - diff.f * data::POWERS_OF_10_32[-exp], exp) + diff.f * data::POWERS_OF_10_64[-exp], exp) ? size : -1; } @@ -692,6 +694,7 @@ FMT_FUNC gen_digits_params process_specs(const core_format_specs& specs, params.upper = true; FMT_FALLTHROUGH case '\0': + num_digits = 17; case 'g': params.trailing_zeros = (specs.flags & HASH_FLAG) != 0; if (-4 <= exp && exp < num_digits + 1) { @@ -759,7 +762,7 @@ grisu2_format(Double value, buffer& buf, core_format_specs specs) { ++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}. uint64_t delta = upper.f - lower.f; fp diff = upper - scaled_value; // wp_w in Grisu. - // lo (p2 in Grisu) contains the least significants digits of scaled_upper. + // lo (p2 in Grisu) contains the least significants digits of scaled upper. // lo = upper % one. uint64_t lo = upper.f & (one.f - 1); gen_digits_params params = process_specs(specs, cached_exp + exp, buf); diff --git a/include/fmt/format.h b/include/fmt/format.h index 8af59b7f..afc4fbd2 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -750,7 +750,7 @@ template struct int_traits { // Static data is placed in this class template to allow header-only // configuration. template struct FMT_API basic_data { - static const uint32_t POWERS_OF_10_32[]; + static const uint64_t POWERS_OF_10_64[]; static const uint32_t ZERO_OR_POWERS_OF_10_32[]; static const uint64_t ZERO_OR_POWERS_OF_10_64[]; static const uint64_t POW10_SIGNIFICANDS[]; diff --git a/test/grisu-test.cc b/test/grisu-test.cc index 05f580dd..49242766 100644 --- a/test/grisu-test.cc +++ b/test/grisu-test.cc @@ -9,7 +9,7 @@ #include "fmt/format.h" #include "gtest.h" -bool reported_skipped; +static bool reported_skipped; #undef TEST #define TEST(test_fixture, test_name) \ @@ -39,3 +39,8 @@ TEST(GrisuTest, Inf) { TEST(GrisuTest, Zero) { EXPECT_EQ("0", fmt::format("{}", 0.0)); } + +TEST(GrisuTest, Round) { + EXPECT_EQ("1.9156918820264798e-56", + fmt::format("{}", 1.9156918820264798e-56)); +}