Fix rounding

This commit is contained in:
Victor Zverovich 2019-02-02 08:49:25 -08:00
parent e61cac687d
commit b8d34e0db3
3 changed files with 15 additions and 7 deletions

View File

@ -266,7 +266,9 @@ const char basic_data<T>::DIGITS[] =
factor * 1000000000 factor * 1000000000
template <typename T> template <typename T>
const uint32_t basic_data<T>::POWERS_OF_10_32[] = {1, FMT_POWERS_OF_10(1)}; const uint64_t basic_data<T>::POWERS_OF_10_64[] = {
1, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(1000000000ull),
10000000000000000000ull};
template <typename T> template <typename T>
const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {0, const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {0,
@ -334,7 +336,7 @@ template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
template <typename T> struct bits { template <typename T> struct bits {
static FMT_CONSTEXPR_DECL const int value = static FMT_CONSTEXPR_DECL const int value =
sizeof(T) * std::numeric_limits<unsigned char>::digits; static_cast<int>(sizeof(T) * std::numeric_limits<unsigned char>::digits);
}; };
// A handmade floating-point number f * pow(2, e). // 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<uint64_t>(hi) << -one.e) + lo; uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
if (remainder <= delta || size > max_digits) { if (remainder <= delta || size > max_digits) {
return grisu2_round(buf, size, max_digits, delta, remainder, return grisu2_round(buf, size, max_digits, delta, remainder,
static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) static_cast<uint64_t>(data::POWERS_OF_10_64[exp])
<< -one.e, << -one.e,
diff.f, exp) diff.f, exp)
? size ? size
@ -540,7 +542,7 @@ FMT_FUNC int grisu2_gen_digits(char* buf, uint32_t hi, uint64_t lo, int& exp,
--exp; --exp;
if (lo < delta || size > max_digits) { if (lo < delta || size > max_digits) {
return grisu2_round(buf, size, max_digits, delta, lo, one.f, 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 ? size
: -1; : -1;
} }
@ -692,6 +694,7 @@ FMT_FUNC gen_digits_params process_specs(const core_format_specs& specs,
params.upper = true; params.upper = true;
FMT_FALLTHROUGH FMT_FALLTHROUGH
case '\0': case '\0':
num_digits = 17;
case 'g': case 'g':
params.trailing_zeros = (specs.flags & HASH_FLAG) != 0; params.trailing_zeros = (specs.flags & HASH_FLAG) != 0;
if (-4 <= exp && exp < num_digits + 1) { 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}. ++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
uint64_t delta = upper.f - lower.f; uint64_t delta = upper.f - lower.f;
fp diff = upper - scaled_value; // wp_w in Grisu. 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. // lo = upper % one.
uint64_t lo = upper.f & (one.f - 1); uint64_t lo = upper.f & (one.f - 1);
gen_digits_params params = process_specs(specs, cached_exp + exp, buf); gen_digits_params params = process_specs(specs, cached_exp + exp, buf);

View File

@ -750,7 +750,7 @@ template <typename T> struct int_traits {
// Static data is placed in this class template to allow header-only // Static data is placed in this class template to allow header-only
// configuration. // configuration.
template <typename T = void> struct FMT_API basic_data { template <typename T = void> 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 uint32_t ZERO_OR_POWERS_OF_10_32[];
static const uint64_t ZERO_OR_POWERS_OF_10_64[]; static const uint64_t ZERO_OR_POWERS_OF_10_64[];
static const uint64_t POW10_SIGNIFICANDS[]; static const uint64_t POW10_SIGNIFICANDS[];

View File

@ -9,7 +9,7 @@
#include "fmt/format.h" #include "fmt/format.h"
#include "gtest.h" #include "gtest.h"
bool reported_skipped; static bool reported_skipped;
#undef TEST #undef TEST
#define TEST(test_fixture, test_name) \ #define TEST(test_fixture, test_name) \
@ -39,3 +39,8 @@ TEST(GrisuTest, Inf) {
TEST(GrisuTest, Zero) { TEST(GrisuTest, Zero) {
EXPECT_EQ("0", fmt::format("{}", 0.0)); EXPECT_EQ("0", fmt::format("{}", 0.0));
} }
TEST(GrisuTest, Round) {
EXPECT_EQ("1.9156918820264798e-56",
fmt::format("{}", 1.9156918820264798e-56));
}