mirror of
https://github.com/fmtlib/fmt.git
synced 2025-11-28 13:19:48 +01:00
Add 128-bit operations to bigint
This commit is contained in:
@@ -368,23 +368,36 @@ class bigint {
|
||||
if (carry != 0) bigits_.push_back(carry);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR20 void multiply(uint64_t value) {
|
||||
const bigit mask = ~bigit(0);
|
||||
const double_bigit lower = value & mask;
|
||||
const double_bigit upper = value >> bigit_bits;
|
||||
double_bigit carry = 0;
|
||||
template <typename UInt, FMT_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
|
||||
std::is_same<UInt, uint128_t>::value)>
|
||||
FMT_CONSTEXPR20 void multiply(UInt value) {
|
||||
const UInt lower = static_cast<bigit>(value);
|
||||
const UInt upper = value >> bigit_bits;
|
||||
UInt carry = 0;
|
||||
for (size_t i = 0, n = bigits_.size(); i < n; ++i) {
|
||||
double_bigit result = bigits_[i] * lower + (carry & mask);
|
||||
UInt result = lower * bigits_[i] + static_cast<bigit>(carry);
|
||||
carry =
|
||||
bigits_[i] * upper + (result >> bigit_bits) + (carry >> bigit_bits);
|
||||
upper * bigits_[i] + (result >> bigit_bits) + (carry >> bigit_bits);
|
||||
bigits_[i] = static_cast<bigit>(result);
|
||||
}
|
||||
while (carry != 0) {
|
||||
bigits_.push_back(carry & mask);
|
||||
bigits_.push_back(static_cast<bigit>(carry));
|
||||
carry >>= bigit_bits;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename UInt, FMT_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
|
||||
std::is_same<UInt, uint128_t>::value)>
|
||||
FMT_CONSTEXPR20 void assign(UInt n) {
|
||||
size_t num_bigits = 0;
|
||||
do {
|
||||
bigits_[num_bigits++] = static_cast<bigit>(n);
|
||||
n >>= bigit_bits;
|
||||
} while (n != 0);
|
||||
bigits_.resize(num_bigits);
|
||||
exp_ = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR20 bigint() : exp_(0) {}
|
||||
explicit bigint(uint64_t n) { assign(n); }
|
||||
@@ -400,14 +413,9 @@ class bigint {
|
||||
exp_ = other.exp_;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR20 void assign(uint64_t n) {
|
||||
size_t num_bigits = 0;
|
||||
do {
|
||||
bigits_[num_bigits++] = n & ~bigit(0);
|
||||
n >>= bigit_bits;
|
||||
} while (n != 0);
|
||||
bigits_.resize(num_bigits);
|
||||
exp_ = 0;
|
||||
template <typename Int> FMT_CONSTEXPR20 void operator=(Int n) {
|
||||
FMT_ASSERT(n > 0, "");
|
||||
assign(uint64_or_128_t<Int>(n));
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR20 int num_bigits() const {
|
||||
@@ -478,14 +486,14 @@ class bigint {
|
||||
// Assigns pow(10, exp) to this bigint.
|
||||
FMT_CONSTEXPR20 void assign_pow10(int exp) {
|
||||
FMT_ASSERT(exp >= 0, "");
|
||||
if (exp == 0) return assign(1);
|
||||
if (exp == 0) return *this = 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);
|
||||
*this = 5;
|
||||
bitmask >>= 1;
|
||||
while (bitmask != 0) {
|
||||
square();
|
||||
@@ -2061,12 +2069,12 @@ FMT_CONSTEXPR20 inline void format_dragon(fp value, unsigned flags,
|
||||
bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0;
|
||||
int shift = is_predecessor_closer ? 2 : 1;
|
||||
if (value.e >= 0) {
|
||||
numerator.assign(value.f);
|
||||
numerator = value.f;
|
||||
numerator <<= value.e + shift;
|
||||
lower.assign(1);
|
||||
lower = 1;
|
||||
lower <<= value.e;
|
||||
if (is_predecessor_closer) {
|
||||
upper_store.assign(1);
|
||||
upper_store = 1;
|
||||
upper_store <<= value.e + 1;
|
||||
upper = &upper_store;
|
||||
}
|
||||
@@ -2082,16 +2090,16 @@ FMT_CONSTEXPR20 inline void format_dragon(fp value, unsigned flags,
|
||||
}
|
||||
numerator *= value.f;
|
||||
numerator <<= shift;
|
||||
denominator.assign(1);
|
||||
denominator = 1;
|
||||
denominator <<= shift - value.e;
|
||||
} else {
|
||||
numerator.assign(value.f);
|
||||
numerator = value.f;
|
||||
numerator <<= shift;
|
||||
denominator.assign_pow10(exp10);
|
||||
denominator <<= shift - value.e;
|
||||
lower.assign(1);
|
||||
lower = 1;
|
||||
if (is_predecessor_closer) {
|
||||
upper_store.assign(1ULL << 1);
|
||||
upper_store = 1ULL << 1;
|
||||
upper = &upper_store;
|
||||
}
|
||||
}
|
||||
@@ -2278,13 +2286,14 @@ FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision,
|
||||
} // namespace detail
|
||||
|
||||
template <> struct formatter<detail::bigint> {
|
||||
FMT_CONSTEXPR format_parse_context::iterator parse(
|
||||
format_parse_context& ctx) {
|
||||
FMT_CONSTEXPR auto parse(format_parse_context& ctx)
|
||||
-> format_parse_context::iterator {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
format_context::iterator format(const detail::bigint& n,
|
||||
format_context& ctx) {
|
||||
template <typename FormatContext>
|
||||
auto format(const detail::bigint& n, FormatContext& ctx) const ->
|
||||
typename FormatContext::iterator {
|
||||
auto out = ctx.out();
|
||||
bool first = true;
|
||||
for (auto i = n.bigits_.size(); i > 0; --i) {
|
||||
|
||||
@@ -339,6 +339,10 @@ class uint128_fallback {
|
||||
const uint128_fallback& rhs) -> bool {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
friend auto operator>(const uint128_fallback& lhs,
|
||||
const uint128_fallback& rhs) -> bool {
|
||||
return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_;
|
||||
}
|
||||
friend auto operator|(const uint128_fallback& lhs,
|
||||
const uint128_fallback& rhs) -> uint128_fallback {
|
||||
return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_};
|
||||
@@ -347,6 +351,16 @@ class uint128_fallback {
|
||||
const uint128_fallback& rhs) -> uint128_fallback {
|
||||
return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_};
|
||||
}
|
||||
friend auto operator+(const uint128_fallback& lhs,
|
||||
const uint128_fallback& rhs) -> uint128_fallback {
|
||||
auto result = uint128_fallback(lhs);
|
||||
result += rhs;
|
||||
return result;
|
||||
}
|
||||
friend auto operator*(const uint128_fallback&, uint32_t) -> uint128_fallback {
|
||||
FMT_ASSERT(false, "");
|
||||
return {};
|
||||
}
|
||||
friend auto operator-(const uint128_fallback& lhs, uint64_t rhs)
|
||||
-> uint128_fallback {
|
||||
FMT_ASSERT(lhs.lo_ >= rhs, "");
|
||||
@@ -973,10 +987,9 @@ template <typename T>
|
||||
using uint32_or_64_or_128_t =
|
||||
conditional_t<num_bits<T>() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS,
|
||||
uint32_t,
|
||||
conditional_t<num_bits<T>() <= 64, uint64_t, uint128_opt>>;
|
||||
conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>>;
|
||||
template <typename T>
|
||||
using uint64_or_128_t =
|
||||
conditional_t<num_bits<T>() <= 64, uint64_t, uint128_opt>;
|
||||
using uint64_or_128_t = conditional_t<num_bits<T>() <= 64, uint64_t, uint128_t>;
|
||||
|
||||
#define FMT_POWERS_OF_10(factor) \
|
||||
factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \
|
||||
|
||||
Reference in New Issue
Block a user