22 #ifndef GEARS_MATH_UINTX_HPP
23 #define GEARS_MATH_UINTX_HPP
30 #include "../meta/alias.hpp"
32 #ifndef GEARS_NO_IOSTREAM
34 #endif // GEARS_NO_IOSTREAM
38 using namespace gears::meta;
40 constexpr
size_t pow(
size_t base,
size_t exponent) {
41 return exponent == 0 ? 1 : (base * pow(base, exponent - 1));
44 template<
typename Cont>
60 template<
typename InIt,
typename OutIt,
typename UnaryF>
61 inline OutIt map(InIt first, InIt last, OutIt result, UnaryF&& f) {
62 for(; first != last; ++first, ++result) {
68 template<
typename InIt,
typename InIt2,
typename OutIt,
typename BinaryF>
69 inline OutIt map(InIt first, InIt last, InIt2 start, OutIt result, BinaryF&& f) {
70 for (; first != last; ++first, ++start, ++result) {
71 *result = f(*first, *start);
79 T operator()(
const U& u,
size_t base)
const {
81 for(
int i = u.size() - 1; i >= 0; --i) {
82 result = result * base + u[i];
89 struct partial_cast<std::string> {
91 std::string operator()(
const U& u,
size_t base)
const {
92 unsigned long long x = 0;
93 for(
int i = u.size() - 1; i >= 0; --i) {
96 return std::to_string(x);
135 template<
size_t Bits = static_cast<
size_t>(-1),
typename Digit =
unsigned int,
typename Digits =
unsigned long long>
139 static constexpr
size_t digit_bits =
sizeof(Digits) * 8;
140 static constexpr
size_t digit_count = Bits == size_t(-1) ? size_t(-1) : (Bits / digit_bits);
141 static_assert(digit_count,
"Invalid bits parameter. Note: Use -1 for \"infinite\" precision");
143 std::vector<Digits> digits;
146 Digits operator()(Digits a, Digits b) {
153 multiply() =
default;
154 multiply(Digits n): k(n) {}
156 Digits operator()(Digits a) {
163 carry(Digits& a): c(a) {}
165 Digits operator()(Digits n) {
175 struct operator_carry :
public Base,
public carry {
176 operator_carry(Digits& c): carry(c) {}
178 Digits operator()(Digits a) {
179 return carry::operator()(Base::operator()(a));
182 Digits operator()(Digits a, Digits b) {
183 return carry::operator()(Base::operator()(a, b));
189 borrow(signed_type& b): b(b) {}
191 signed_type operator()(signed_type n) {
204 sub_borrow(signed_type& b): borrow(b) {}
206 Digits operator()(signed_type a, signed_type b) {
207 signed_type n = b - a - borrow;
218 while(digits.size() > 1) {
219 if(digits.back() == 0)
226 void add_zeroes(Digits n) {
227 digits.resize(digits.size() + n);
228 digits.insert(digits.begin(), n, 0);
232 if(digit_count == Bits)
234 if(digits.capacity() >= digit_count)
235 digits.resize(digit_count);
238 void multiply_helper(
uintx& x, Digits digit) {
240 operator_carry<multiply> mulwc(c);
242 detail::map(x.digits.begin(), x.digits.end(), x.digits.begin(), mulwc);
245 x.digits.push_back(c % base);
253 Digit divide_helper(
const uintx& remainder,
const uintx& denominator) {
255 Digit maximum = base - 1;
256 while(maximum - minimum > 0) {
257 Digit total = maximum + minimum;
258 Digit half_total = total / 2;
259 total = total - half_total * 2 ? half_total + 1 : half_total;
260 auto product = denominator * total;
261 if(product == remainder) {
265 if(remainder > product) {
277 typename std::enable_if<std::is_signed<T>::value, T>::type make_positive(T value) {
278 return value < 0 ? -value : value;
282 typename std::enable_if<std::is_unsigned<T>::value, T>::type make_positive(T value) {
286 static constexpr
size_t digits10 = std::numeric_limits<Digit>::digits10;
287 static constexpr
size_t base = detail::pow(10, digits10);
303 template<
typename Integer, gears::meta::EnableIf<std::is_
integral<Integer>> = gears::meta::_>
305 value = make_positive(value);
307 digits.push_back(value % base);
324 size_t count = digits10 - (s.size() % digits10);
325 std::string str(count,
'0');
327 digits.reserve(str.size() / digits10 + 1);
328 auto size = str.size();
331 while(position != size) {
332 digits.push_back(std::stoull(str.substr(position, digits10)));
333 position += digits10;
348 if(digits.size() < other.digits.size()) {
349 digits.resize(other.digits.size());
353 operator_carry<add> addwc(c);
355 auto it = detail::map(other.digits.begin(), other.digits.end(), digits.begin(), digits.begin(), addwc);
356 detail::map(it, digits.end(), it, carry(c));
368 return (result += other);
383 auto it = detail::map(other.digits.begin(), other.digits.end(), digits.begin(), digits.begin(), sub_borrow(b));
384 detail::map(it, digits.end(), it, borrow(b));
392 return (result -= other);
404 const uintx* first =
this;
405 const uintx* second = &other;
407 auto first_size = first->digits.size();
408 auto second_size = second->digits.size();
410 if(first_size < second_size) {
413 swap(first_size, second_size);
416 std::vector<uintx> ints(second_size);
418 for(
unsigned i = 0; i < second_size; ++i) {
419 ints[i].digits = first->digits;
420 multiply_helper(ints[i], second->digits[i]);
423 *
this = ints.front();
424 digits.resize(first_size + second_size);
426 for(
unsigned i = 1; i < second_size; ++i) {
427 ints[i].add_zeroes(i);
438 return (result *= other);
452 throw std::logic_error(
"Division by zero");
457 digits.resize(copy.size(), 0);
458 remainder.digits.reserve(digits.size());
459 for(
int i = digits.size() - 1; i >= 0; --i) {
460 remainder.add_zeroes(1);
461 remainder.digits[0] = copy[i];
462 remainder.normalize();
463 Digit count = divide_helper(remainder, other);
464 remainder -= other * count;
475 return (result /= other);
489 throw std::logic_error(
"Division by zero");
493 for(
int i = copy.size() - 1; i >= 0; --i) {
497 *
this -= other * divide_helper(*
this, other);
506 return (result %= other);
515 return digits == other.digits;
519 return digits != other.digits;
522 bool operator<(
const uintx& other)
const {
523 auto i = digits.size();
525 if(i < other.digits.size())
527 if(other.digits.size() < i)
533 if(digits[i] < other.digits[i])
535 if(other.digits[i] < digits[i])
543 bool operator>(
const uintx& other)
const {
544 return !(*
this < other);
547 bool operator<=(
const uintx& other)
const {
548 return !(other < *
this);
551 bool operator>=(
const uintx& other)
const {
552 return !(*
this < other);
566 const uintx& operator++() {
585 const uintx& operator--() {
596 explicit operator bool() const noexcept {
597 return digits.back() > 0;
600 #ifndef GEARS_NO_IOSTREAM
601 template<
typename Elem,
typename Traits>
602 friend std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& out,
const uintx& n) {
603 auto first = n.digits.crbegin();
604 auto last = n.digits.crend();
607 while(first != last) {
609 out.width(uintx::digits10);
615 template<
typename Elem,
typename Traits>
616 friend std::basic_istream<Elem, Traits>& operator>>(std::basic_istream<Elem, Traits>& in, uintx& n) {
623 #endif // GEARS_NO_IOSTREAM
625 template<
typename T,
size_t N,
typename U,
typename V>
626 friend T uintx_cast(
const uintx<N, U, V>& obj);
640 template<
typename T,
size_t N,
typename U,
typename V>
646 template<
char... Numbers>
647 inline uintx<> operator"" _x() noexcept {
648 const char str[
sizeof...(Numbers)] = { Numbers... };
649 return { std::string(str,
sizeof(str)) };
652 inline uintx<>
operator"" _x(
const char* s,
size_t len) {
653 return { std::string(s, len) };
659 #endif // GEARS_MATH_UINTX_HPP