Make GetCachedPower test more precise

This commit is contained in:
Victor Zverovich 2020-10-04 07:20:22 -07:00 committed by Victor Zverovich
parent a581e9e5d8
commit af8a180aed
2 changed files with 45 additions and 17 deletions

View File

@ -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<int>(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<int>(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);

View File

@ -212,14 +212,39 @@ TEST(FPTest, Multiply) {
}
TEST(FPTest, GetCachedPower) {
typedef std::numeric_limits<double> limits;
using limits = std::numeric_limits<double>;
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<double>(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));
}
}
}