All Classes Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
uintx.hpp
1 // The MIT License (MIT)
2 
3 // Copyright (c) 2012-2014 Danny Y., Rapptz
4 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal in
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 // the Software, and to permit persons to whom the Software is furnished to do so,
10 // subject to the following conditions:
11 
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #ifndef GEARS_MATH_UINTX_HPP
23 #define GEARS_MATH_UINTX_HPP
24 
25 #include <cstddef>
26 #include <limits>
27 #include <vector>
28 #include <string>
29 #include <stdexcept>
30 #include "../meta/alias.hpp"
31 
32 #ifndef GEARS_NO_IOSTREAM
33 #include <iosfwd>
34 #endif // GEARS_NO_IOSTREAM
35 
36 namespace gears {
37 namespace math {
38 using namespace gears::meta; // workaround for extremely strange bug
39 namespace detail {
40 constexpr size_t pow(size_t base, size_t exponent) {
41  return exponent == 0 ? 1 : (base * pow(base, exponent - 1));
42 }
43 
44 template<typename Cont>
45 inline void reverse(Cont& c) {
46  auto first = std::begin(c);
47  auto last = std::end(c);
48 
49  if(first == last)
50  return;
51  --last;
52  while(first < last) {
53  using std::swap;
54  swap(*first, *last);
55  ++first;
56  --last;
57  }
58 }
59 
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) {
63  *result = f(*first);
64  }
65  return result;
66 }
67 
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);
72  }
73  return result;
74 }
75 
76 template<typename T>
77 struct partial_cast {
78  template<typename U>
79  T operator()(const U& u, size_t base) const {
80  T result{};
81  for(int i = u.size() - 1; i >= 0; --i) {
82  result = result * base + u[i];
83  }
84  return result;
85  }
86 };
87 
88 template<>
89 struct partial_cast<std::string> {
90  template<typename U>
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) {
94  x = x * base + u[i];
95  }
96  return std::to_string(x);
97  }
98 };
99 
100 } // detail
101 
135 template<size_t Bits = static_cast<size_t>(-1), typename Digit = unsigned int, typename Digits = unsigned long long>
136 struct uintx {
137 private:
138  using signed_type = gears::meta::Type<std::make_signed<Digits>>;
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");
142 
143  std::vector<Digits> digits;
144 
145  struct add {
146  Digits operator()(Digits a, Digits b) {
147  return a + b;
148  }
149  };
150 
151  struct multiply {
152  Digits k;
153  multiply() = default;
154  multiply(Digits n): k(n) {}
155 
156  Digits operator()(Digits a) {
157  return a * k;
158  }
159  };
160 
161  struct carry {
162  Digits& c;
163  carry(Digits& a): c(a) {}
164 
165  Digits operator()(Digits n) {
166  n += c;
167  c = n / base;
168  n %= base;
169 
170  return n;
171  }
172  };
173 
174  template<class Base>
175  struct operator_carry : public Base, public carry {
176  operator_carry(Digits& c): carry(c) {}
177 
178  Digits operator()(Digits a) {
179  return carry::operator()(Base::operator()(a));
180  }
181 
182  Digits operator()(Digits a, Digits b) {
183  return carry::operator()(Base::operator()(a, b));
184  }
185  };
186 
187  struct borrow {
188  signed_type& b;
189  borrow(signed_type& b): b(b) {}
190 
191  signed_type operator()(signed_type n) {
192  n -= b;
193  b = 0;
194  while(n < 0) {
195  n += base;
196  ++b;
197  }
198  return n;
199  }
200  };
201 
202  struct sub_borrow {
203  signed_type& borrow;
204  sub_borrow(signed_type& b): borrow(b) {}
205 
206  Digits operator()(signed_type a, signed_type b) {
207  signed_type n = b - a - borrow;
208  borrow = 0;
209  while(n < 0) {
210  n += base;
211  ++borrow;
212  }
213  return n;
214  }
215  };
216 
217  void normalize() {
218  while(digits.size() > 1) {
219  if(digits.back() == 0)
220  digits.pop_back();
221  else
222  break;
223  }
224  }
225 
226  void add_zeroes(Digits n) {
227  digits.resize(digits.size() + n);
228  digits.insert(digits.begin(), n, 0);
229  }
230 
231  void check_bits() {
232  if(digit_count == Bits)
233  return;
234  if(digits.capacity() >= digit_count)
235  digits.resize(digit_count);
236  }
237 
238  void multiply_helper(uintx& x, Digits digit) {
239  Digits c = 0;
240  operator_carry<multiply> mulwc(c);
241  mulwc.k = digit;
242  detail::map(x.digits.begin(), x.digits.end(), x.digits.begin(), mulwc);
243 
244  while(c) {
245  x.digits.push_back(c % base);
246  c /= base;
247  }
248 
249  x.normalize();
250  x.check_bits();
251  }
252 
253  Digit divide_helper(const uintx& remainder, const uintx& denominator) {
254  Digit minimum = 0;
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) {
262  return total;
263  }
264 
265  if(remainder > product) {
266  minimum = total;
267  }
268  else {
269  maximum = total - 1;
270  }
271  }
272 
273  return minimum;
274  }
275 
276  template<typename T>
277  typename std::enable_if<std::is_signed<T>::value, T>::type make_positive(T value) {
278  return value < 0 ? -value : value;
279  }
280 
281  template<typename T>
282  typename std::enable_if<std::is_unsigned<T>::value, T>::type make_positive(T value) {
283  return value;
284  }
285 public:
286  static constexpr size_t digits10 = std::numeric_limits<Digit>::digits10;
287  static constexpr size_t base = detail::pow(10, digits10);
288 
293  uintx(): digits(0) {}
294 
303  template<typename Integer, gears::meta::EnableIf<std::is_integral<Integer>> = gears::meta::_>
304  uintx(Integer value) {
305  value = make_positive(value);
306  do {
307  digits.push_back(value % base);
308  value /= base;
309  }
310  while(value > 0);
311  }
312 
323  uintx(const std::string& s) {
324  size_t count = digits10 - (s.size() % digits10);
325  std::string str(count, '0');
326  str += s;
327  digits.reserve(str.size() / digits10 + 1);
328  auto size = str.size();
329  size_t position = 0;
330 
331  while(position != size) {
332  digits.push_back(std::stoull(str.substr(position, digits10)));
333  position += digits10;
334  }
335 
336  detail::reverse(digits);
337  check_bits();
338  }
339 
341 
347  uintx& operator+=(const uintx& other) {
348  if(digits.size() < other.digits.size()) {
349  digits.resize(other.digits.size());
350  }
351 
352  Digits c = 0;
353  operator_carry<add> addwc(c);
354 
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));
357 
358  if(c)
359  digits.push_back(c);
360 
361  normalize();
362  check_bits();
363  return *this;
364  }
365 
366  uintx operator+(const uintx& other) const {
367  uintx result(*this);
368  return (result += other);
369  }
371 
373 
381  uintx& operator-=(const uintx& other) {
382  signed_type b = 0;
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));
385  normalize();
386  check_bits();
387  return *this;
388  }
389 
390  uintx operator-(const uintx& other) const {
391  uintx result(*this);
392  return (result -= other);
393  }
395 
397 
403  uintx& operator*=(const uintx& other) {
404  const uintx* first = this;
405  const uintx* second = &other;
406 
407  auto first_size = first->digits.size();
408  auto second_size = second->digits.size();
409 
410  if(first_size < second_size) {
411  using std::swap;
412  swap(first, second);
413  swap(first_size, second_size);
414  }
415 
416  std::vector<uintx> ints(second_size);
417 
418  for(unsigned i = 0; i < second_size; ++i) {
419  ints[i].digits = first->digits;
420  multiply_helper(ints[i], second->digits[i]);
421  }
422 
423  *this = ints.front();
424  digits.resize(first_size + second_size);
425 
426  for(unsigned i = 1; i < second_size; ++i) {
427  ints[i].add_zeroes(i);
428  *this += ints[i];
429  }
430 
431  normalize();
432  check_bits();
433  return *this;
434  }
435 
436  uintx operator*(const uintx& other) const {
437  uintx result(*this);
438  return (result *= other);
439  }
441 
443 
450  uintx& operator/=(const uintx& other) {
451  if(other == 0)
452  throw std::logic_error("Division by zero");
453 
454  uintx remainder;
455  auto copy = digits;
456  digits.clear();
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;
465  digits[i] += count;
466  }
467 
468  normalize();
469  check_bits();
470  return *this;
471  }
472 
473  uintx operator/(const uintx& other) const {
474  uintx result(*this);
475  return (result /= other);
476  }
478 
480 
487  uintx& operator%=(const uintx& other) {
488  if(other == 0)
489  throw std::logic_error("Division by zero");
490 
491  auto copy = digits;
492  digits.clear();
493  for(int i = copy.size() - 1; i >= 0; --i) {
494  add_zeroes(1);
495  digits[0] = copy[i];
496  normalize();
497  *this -= other * divide_helper(*this, other);
498  }
499  normalize();
500  check_bits();
501  return *this;
502  }
503 
504  uintx operator%(const uintx& other) const {
505  uintx result(*this);
506  return (result %= other);
507  }
509 
511 
514  bool operator==(const uintx& other) const {
515  return digits == other.digits;
516  }
517 
518  bool operator!=(const uintx& other) const {
519  return digits != other.digits;
520  }
521 
522  bool operator<(const uintx& other) const {
523  auto i = digits.size();
524 
525  if(i < other.digits.size())
526  return true;
527  if(other.digits.size() < i)
528  return false;
529 
530  --i;
531 
532  do {
533  if(digits[i] < other.digits[i])
534  return true;
535  if(other.digits[i] < digits[i])
536  return false;
537  --i;
538  } while (i > 0);
539 
540  return false;
541  }
542 
543  bool operator>(const uintx& other) const {
544  return !(*this < other);
545  }
546 
547  bool operator<=(const uintx& other) const {
548  return !(other < *this);
549  }
550 
551  bool operator>=(const uintx& other) const {
552  return !(*this < other);
553  }
555 
557 
561  auto copy = *this;
562  *this += 1;
563  return copy;
564  }
565 
566  const uintx& operator++() {
567  *this += 1;
568  return *this;
569  }
571 
573 
580  auto copy = *this;
581  *this -= 1;
582  return copy;
583  }
584 
585  const uintx& operator--() {
586  *this -= 1;
587  return *this;
588  }
590 
596  explicit operator bool() const noexcept {
597  return digits.back() > 0;
598  }
599 
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();
605  if(first != last)
606  out << *first++;
607  while(first != last) {
608  out.fill('0');
609  out.width(uintx::digits10);
610  out << *first++;
611  }
612  return out;
613  }
614 
615  template<typename Elem, typename Traits>
616  friend std::basic_istream<Elem, Traits>& operator>>(std::basic_istream<Elem, Traits>& in, uintx& n) {
617  std::string str;
618  in >> str;
619  n = str;
620  return in;
621  }
622 
623  #endif // GEARS_NO_IOSTREAM
624 
625  template<typename T, size_t N, typename U, typename V>
626  friend T uintx_cast(const uintx<N, U, V>& obj);
627 };
628 
640 template<typename T, size_t N, typename U, typename V>
641 inline T uintx_cast(const uintx<N, U, V>& obj) {
642  return detail::partial_cast<T>()(obj.digits, uintx<N, U, V>::base);
643 }
644 
645 namespace literals {
646 template<char... Numbers>
647 inline uintx<> operator"" _x() noexcept {
648  const char str[sizeof...(Numbers)] = { Numbers... };
649  return { std::string(str, sizeof(str)) };
650 }
651 
652 inline uintx<> operator"" _x(const char* s, size_t len) {
653  return { std::string(s, len) };
654 }
655 } // literals
656 } // math
657 } // gears
658 
659 #endif // GEARS_MATH_UINTX_HPP