#include #include namespace psemek::util { namespace { struct adder { std::uint32_t sum = 0; std::uint32_t carry = 0; void add(std::uint32_t x) { auto result = static_cast(sum) + x; sum = result & std::uint32_t(-1); carry += result >> 32; } }; } void big_int::canonicalize() { auto size = this->size(); auto negative = this->negative(); while (size > 0 && digits_[size - 1] == 0) --size; set_size(size); set_negative(size > 0 && negative); } void big_int::ensure_capacity(std::uint32_t new_capacity) { if (new_capacity == 0) { digits_ = nullptr; size_ = 0; capacity_ = 0; } else if (new_capacity > capacity_) { new_capacity = std::max({static_cast(1.6 * size()), static_cast(16), new_capacity}); auto new_digits = std::make_unique(new_capacity); std::size_t i = 0; for (; i < size(); ++i) new_digits[i] = digits_[i]; for (; i < new_capacity; ++i) new_digits[i] = 0; digits_ = std::move(new_digits); capacity_ = new_capacity; } } void big_int::add_positive(span digits) { digit carry = 0; std::size_t i = 0; std::size_t min_size = std::min(size(), digits.size()); for (; i < min_size; ++i) { adder adder{digits_[i]}; adder.add(digits[i]); adder.add(carry); std::tie(digits_[i], carry) = {adder.sum, adder.carry}; } if (i < digits.size()) { ensure_capacity(digits.size()); for (; i < digits.size(); ++i) { adder adder{digits[i]}; adder.add(carry); std::tie(digits_[i], carry) = {adder.sum, adder.carry}; } set_size(digits.size()); } if (i < size()) { for (; i < size() && carry != 0; ++i) { adder adder{digits_[i]}; adder.add(carry); std::tie(digits_[i], carry) = {adder.sum, adder.carry}; } } if (carry != 0) { ensure_capacity(size() + 1); digits_[size()] = carry; set_size(size() + 1); } canonicalize(); } }