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