From af8a180aedb30686cc721db9b3df8ede73929d54 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 4 Oct 2020 07:20:22 -0700 Subject: [PATCH] Make GetCachedPower test more precise --- include/fmt/format-inl.h | 27 +++++++++++++++------------ test/format-impl-test.cc | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 0fd719b4..80e0f8f4 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -1262,9 +1262,8 @@ class bigint { FMT_ASSERT(compare(*this, other) >= 0, ""); bigit borrow = 0; int i = other.exp_ - exp_; - for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j) { + for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j) subtract_bigits(i, other.bigits_[j], borrow); - } while (borrow > 0) subtract_bigits(i, 0, borrow); remove_leading_zeros(); } @@ -1436,22 +1435,26 @@ class bigint { exp_ *= 2; } + // If this bigint has a bigger exponent than other, adds trailing zero to make + // exponents equal. This simplifies some operations such as subtraction. + void align(const bigint& other) { + int exp_difference = exp_ - other.exp_; + if (exp_difference <= 0) return; + int num_bigits = static_cast(bigits_.size()); + bigits_.resize(to_unsigned(num_bigits + exp_difference)); + for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j) + bigits_[j] = bigits_[i]; + std::uninitialized_fill_n(bigits_.data(), exp_difference, 0); + exp_ -= exp_difference; + } + // Divides this bignum by divisor, assigning the remainder to this and // returning the quotient. int divmod_assign(const bigint& divisor) { FMT_ASSERT(this != &divisor, ""); if (compare(*this, divisor) < 0) return 0; - int num_bigits = static_cast(bigits_.size()); FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, ""); - int exp_difference = exp_ - divisor.exp_; - if (exp_difference > 0) { - // Align bigints by adding trailing zeros to simplify subtraction. - bigits_.resize(to_unsigned(num_bigits + exp_difference)); - for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j) - bigits_[j] = bigits_[i]; - std::uninitialized_fill_n(bigits_.data(), exp_difference, 0); - exp_ -= exp_difference; - } + align(divisor); int quotient = 0; do { subtract_aligned(divisor); diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index b93a4c25..1290c077 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -212,14 +212,39 @@ TEST(FPTest, Multiply) { } TEST(FPTest, GetCachedPower) { - typedef std::numeric_limits limits; + using limits = std::numeric_limits; for (auto exp = limits::min_exponent; exp <= limits::max_exponent; ++exp) { int dec_exp = 0; auto fp = fmt::detail::get_cached_power(exp, dec_exp); - EXPECT_LE(exp, fp.e); - int dec_exp_step = 8; - EXPECT_LE(fp.e, exp + dec_exp_step * log2(10)); - EXPECT_DOUBLE_EQ(pow(10, dec_exp), ldexp(static_cast(fp.f), fp.e)); + bigint exact, cache(fp.f); + if (dec_exp >= 0) { + exact.assign_pow10(dec_exp); + if (fp.e <= 0) + exact <<= -fp.e; + else + cache <<= fp.e; + exact.align(cache); + cache.align(exact); + auto exact_str = fmt::format("{}", exact); + auto cache_str = fmt::format("{}", cache); + EXPECT_EQ(exact_str.size(), cache_str.size()); + EXPECT_EQ(exact_str.substr(0, 15), cache_str.substr(0, 15)); + int diff = cache_str[15] - exact_str[15]; + if (diff == 1) + EXPECT_GT(exact_str[16], '8'); + else + EXPECT_EQ(diff, 0); + } else { + cache.assign_pow10(-dec_exp); + cache *= fp.f + 1; // Inexact check. + exact.assign(1); + exact <<= -fp.e; + exact.align(cache); + auto exact_str = fmt::format("{}", exact); + auto cache_str = fmt::format("{}", cache); + EXPECT_EQ(exact_str.size(), cache_str.size()); + EXPECT_EQ(exact_str.substr(0, 16), cache_str.substr(0, 16)); + } } }