mirror of
https://github.com/fmtlib/fmt.git
synced 2025-04-09 18:45:18 +00:00
Implement multiplication and part of assignment from pow of 10
This commit is contained in:
parent
0887887e23
commit
b3bf665764
@ -473,14 +473,14 @@ class bigint {
|
|||||||
// A bigint is stored as an array of bigits (big digits), with bigit at index
|
// A bigint is stored as an array of bigits (big digits), with bigit at index
|
||||||
// 0 being the least significant one.
|
// 0 being the least significant one.
|
||||||
using bigit = uint32_t;
|
using bigit = uint32_t;
|
||||||
|
using double_bigit = uint64_t;
|
||||||
basic_memory_buffer<bigit> bigits_;
|
basic_memory_buffer<bigit> bigits_;
|
||||||
|
|
||||||
static FMT_CONSTEXPR_DECL const int bigit_bits = bits<bigit>::value;
|
static FMT_CONSTEXPR_DECL const int bigit_bits = bits<bigit>::value;
|
||||||
|
|
||||||
friend struct formatter<bigint>;
|
friend struct formatter<bigint>;
|
||||||
|
|
||||||
public:
|
void assign(uint64_t n) {
|
||||||
explicit bigint(uint64_t n) {
|
|
||||||
int num_bigits = bits<uint64_t>::value / bigit_bits;
|
int num_bigits = bits<uint64_t>::value / bigit_bits;
|
||||||
bigits_.resize(num_bigits);
|
bigits_.resize(num_bigits);
|
||||||
for (int i = 0; i < num_bigits; ++i) {
|
for (int i = 0; i < num_bigits; ++i) {
|
||||||
@ -489,9 +489,37 @@ class bigint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bigint() {}
|
||||||
|
explicit bigint(uint64_t n) { assign(n); }
|
||||||
|
|
||||||
|
// Assigns pow(10, exp) to this bigint.
|
||||||
|
void assign_pow10(int exp) {
|
||||||
|
assert(exp >= 0);
|
||||||
|
if (exp == 0) return assign(1);
|
||||||
|
// Find the top bit.
|
||||||
|
int bitmask = 1;
|
||||||
|
while (exp >= bitmask) bitmask <<= 1;
|
||||||
|
bitmask >>= 1;
|
||||||
|
// pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by
|
||||||
|
// repeated squaring and multiplication.
|
||||||
|
assign(5);
|
||||||
|
bitmask >>= 1;
|
||||||
|
while (bitmask != 0) {
|
||||||
|
square();
|
||||||
|
if ((exp & bitmask) != 0) *this *= 5;
|
||||||
|
bitmask >>= 1;
|
||||||
|
}
|
||||||
|
*this <<= exp; // Multiply by pow(2, exp) by shifting.
|
||||||
|
}
|
||||||
|
|
||||||
bigint(const bigint&) = delete;
|
bigint(const bigint&) = delete;
|
||||||
void operator=(const bigint&) = delete;
|
void operator=(const bigint&) = delete;
|
||||||
|
|
||||||
|
void square() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
bigint& operator<<=(int shift) {
|
bigint& operator<<=(int shift) {
|
||||||
assert(shift >= 0 && shift < bigit_bits);
|
assert(shift >= 0 && shift < bigit_bits);
|
||||||
bigit carry = 0;
|
bigit carry = 0;
|
||||||
@ -503,6 +531,23 @@ class bigint {
|
|||||||
if (carry != 0) bigits_.push_back(carry);
|
if (carry != 0) bigits_.push_back(carry);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bigint& operator*=(uint32_t value) {
|
||||||
|
assert(value > 0);
|
||||||
|
// Verify that the computation doesn't overflow.
|
||||||
|
constexpr double_bigit max32 = (std::numeric_limits<bigit>::max)();
|
||||||
|
constexpr double_bigit max64 = (std::numeric_limits<double_bigit>::max)();
|
||||||
|
static_assert(max32 * max32 <= max64 - max32, "");
|
||||||
|
bigit carry = 0;
|
||||||
|
const double_bigit wide_value = value;
|
||||||
|
for (size_t i = 0, n = bigits_.size(); i < n; ++i) {
|
||||||
|
double_bigit result = bigits_[i] * wide_value + carry;
|
||||||
|
bigits_[i] = static_cast<bigit>(result);
|
||||||
|
carry = static_cast<bigit>(result >> bigit_bits);
|
||||||
|
}
|
||||||
|
if (carry != 0) bigits_.push_back(carry);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum round_direction { unknown, up, down };
|
enum round_direction { unknown, up, down };
|
||||||
@ -725,8 +770,9 @@ template <int GRISU_VERSION> struct grisu_shortest_handler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_API void fallback_format(const fp& value) {
|
FMT_API void fallback_format(const fp& value, int exp10) {
|
||||||
(void)value; // TODO
|
(void)value; // TODO
|
||||||
|
(void)exp10;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Double,
|
template <typename Double,
|
||||||
@ -782,7 +828,7 @@ FMT_API bool grisu_format(Double value, buffer<char>& buf, int precision,
|
|||||||
result = grisu_gen_digits(upper, upper.f - lower.f, exp, handler);
|
result = grisu_gen_digits(upper, upper.f - lower.f, exp, handler);
|
||||||
size = handler.size;
|
size = handler.size;
|
||||||
if (result == digits::error) {
|
if (result == digits::error) {
|
||||||
fallback_format(fp_value);
|
fallback_format(fp_value, exp - cached_exp10);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -29,6 +29,7 @@ static_assert(!std::is_copy_constructible<bigint>::value, "");
|
|||||||
static_assert(!std::is_copy_assignable<bigint>::value, "");
|
static_assert(!std::is_copy_assignable<bigint>::value, "");
|
||||||
|
|
||||||
TEST(BigIntTest, Construct) {
|
TEST(BigIntTest, Construct) {
|
||||||
|
EXPECT_EQ("", fmt::format("{}", bigint()));
|
||||||
EXPECT_EQ("42", fmt::format("{}", bigint(0x42)));
|
EXPECT_EQ("42", fmt::format("{}", bigint(0x42)));
|
||||||
EXPECT_EQ("123456789abcedf0", fmt::format("{}", bigint(0x123456789abcedf0)));
|
EXPECT_EQ("123456789abcedf0", fmt::format("{}", bigint(0x123456789abcedf0)));
|
||||||
}
|
}
|
||||||
@ -43,6 +44,20 @@ TEST(BigIntTest, ShiftLeft) {
|
|||||||
EXPECT_EQ("108000000", fmt::format("{}", n));
|
EXPECT_EQ("108000000", fmt::format("{}", n));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(BigIntTest, Multiply) {
|
||||||
|
bigint n(0x42);
|
||||||
|
n *= 1;
|
||||||
|
EXPECT_EQ("42", fmt::format("{}", n));
|
||||||
|
n *= 2;
|
||||||
|
EXPECT_EQ("84", fmt::format("{}", n));
|
||||||
|
n *= 0x12345678;
|
||||||
|
EXPECT_EQ("962fc95e0", fmt::format("{}", n));
|
||||||
|
auto max = (std::numeric_limits<uint32_t>::max)();
|
||||||
|
bigint bigmax(max);
|
||||||
|
bigmax *= max;
|
||||||
|
EXPECT_EQ("fffffffe00000001", fmt::format("{}", bigmax));
|
||||||
|
}
|
||||||
|
|
||||||
template <bool is_iec559> void test_construct_from_double() {
|
template <bool is_iec559> void test_construct_from_double() {
|
||||||
fmt::print("warning: double is not IEC559, skipping FP tests\n");
|
fmt::print("warning: double is not IEC559, skipping FP tests\n");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user