C(++)ECCO
C++ Error Control COding: a header-only library for ECC simulations and experiments, modeling complete coding systems across arbitrary finite fields and complex inter-field relationships - Christian Senger <senger@inue.uni-stuttgart.de>
Loading...
Searching...
No Matches
InfInt.hpp
Go to the documentation of this file.
1/*
2 * InfInt - Arbitrary-Precision Integer Arithmetic Library
3 * Copyright (C) 2013 Sercan Tutar
4 * Copyright (C) 2025 Christian Senger
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 *
11 * USAGE:
12 * It is pretty straight forward to use the library. Just create an instance of
13 * InfInt class and start using it.
14 *
15 * Useful methods:
16 * intSqrt: integer square root operation
17 * digitAt: returns digit at index
18 * numberOfDigits: returns number of digits
19 * size: returns size in bytes
20 * to_string: converts it to a string
21 *
22 * There are also conversion methods which allow conversion to primitive types:
23 * toInt, toLong, toLongLong, toUnsignedInt, toUnsignedLong, toUnsignedLongLong.
24 *
25 * You may define INFINT_USE_EXCEPTIONS and library methods will start raising
26 * InfIntException in case of error instead of writing error messages using
27 * std::cerr.
28 *
29 * See ReadMe.txt for more info.
30 *
31 *
32 * No overflows, happy programmers!
33 *
34 */
35
36#ifndef INFINT_H_
37#define INFINT_H_
38
39#include <climits>
40#include <iomanip>
41#include <iostream>
42#include <sstream>
43#include <vector>
44
45// #include <limits.h>
46// #include <stdlib.h>
47
48#ifndef LONG_LONG_MIN
49#define LONG_LONG_MIN LLONG_MIN
50#endif
51
52#ifndef LONG_LONG_MAX
53#define LONG_LONG_MAX LLONG_MAX
54#endif
55
56#ifndef ULONG_LONG_MAX
57#define ULONG_LONG_MAX ULLONG_MAX
58#endif
59
60#define INFINT_USE_EXCEPTIONS
61
63#include <exception>
64#endif
65
66typedef int ELEM_TYPE;
67typedef long long PRODUCT_TYPE;
68static const ELEM_TYPE BASE = 1000000000;
69static const ELEM_TYPE UPPER_BOUND = 999999999;
70static const ELEM_TYPE DIGIT_COUNT = 9;
71static const int powersOfTen[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
72
74class InfIntException : public std::exception {
75 public:
76 InfIntException(const std::string& txt) throw();
77 ~InfIntException() throw();
78 const char* what() const throw();
79
80 private:
81 std::string txt;
82};
83
84inline InfIntException::InfIntException(const std::string& txt) throw()
85 : std::exception(), txt(txt) {}
86
87inline InfIntException::~InfIntException() throw() {}
88
89inline const char* InfIntException::what() const throw() { return txt.c_str(); }
90#endif
91
92inline static div_t my_div(int num, int denom) {
93 div_t result;
94 result.quot = num / denom;
95 result.rem = num - denom * result.quot;
96 return result;
97}
98
99inline static ldiv_t my_ldiv(long num, long denom) {
100 ldiv_t result;
101 result.quot = num / denom;
102 result.rem = num - denom * result.quot;
103 return result;
104}
105
106inline static lldiv_t my_lldiv(long long num, long long denom) {
107 lldiv_t result;
108 result.quot = num / denom;
109 result.rem = num - denom * result.quot;
110 return result;
111}
112
113class InfInt {
114 friend std::ostream& operator<<(std::ostream& s, const InfInt& n);
115 friend std::istream& operator>>(std::istream& s, InfInt& val);
116
117 public:
118 /* constructors */
119 InfInt();
120 InfInt(const char* c);
121 InfInt(const std::string& s);
122 InfInt(int l);
123 InfInt(long l);
124 InfInt(long long l);
125 InfInt(unsigned int l);
126 InfInt(unsigned long l);
127 InfInt(unsigned long long l);
128 InfInt(const InfInt& l);
129
130 /* assignment operators */
131 const InfInt& operator=(const char* c);
132 const InfInt& operator=(const std::string& s);
133 const InfInt& operator=(int l);
134 const InfInt& operator=(long l);
135 const InfInt& operator=(long long l);
136 const InfInt& operator=(unsigned int l);
137 const InfInt& operator=(unsigned long l);
138 const InfInt& operator=(unsigned long long l);
139 const InfInt& operator=(const InfInt& l);
140
141 /* unary increment/decrement operators */
142 const InfInt& operator++();
143 const InfInt& operator--();
144 InfInt operator++(int);
145 InfInt operator--(int);
146
147 /* operational assignments */
148 const InfInt& operator+=(const InfInt& rhs);
149 const InfInt& operator-=(const InfInt& rhs);
150 const InfInt& operator*=(const InfInt& rhs);
151 const InfInt& operator/=(const InfInt& rhs); // throw
152 const InfInt& operator%=(const InfInt& rhs); // throw
153 const InfInt& operator*=(ELEM_TYPE rhs);
154
155 /* operations */
156 InfInt operator-() const;
157 InfInt operator+(const InfInt& rhs) const;
158 InfInt operator-(const InfInt& rhs) const;
159 InfInt operator*(const InfInt& rhs) const;
160 InfInt operator/(const InfInt& rhs) const; // throw
161 InfInt operator%(const InfInt& rhs) const; // throw
162 InfInt operator*(ELEM_TYPE rhs) const;
163
164 /* relational operations */
165 bool operator==(const InfInt& rhs) const;
166 bool operator!=(const InfInt& rhs) const;
167 bool operator<(const InfInt& rhs) const;
168 bool operator<=(const InfInt& rhs) const;
169 bool operator>(const InfInt& rhs) const;
170 bool operator>=(const InfInt& rhs) const;
171
172 /* integer square root */
173 InfInt intSqrt() const; // throw
174
175 /* digit operations */
176 char digitAt(size_t i) const; // throw
177 size_t numberOfDigits() const;
178
179 /* size in bytes */
180 size_t size() const;
181
182 /* string conversion */
183 std::string to_string() const;
184
185 /* conversion to primitive types */
186 int toInt() const; // throw
187 long toLong() const; // throw
188 long long toLongLong() const; // throw
189 unsigned int toUnsignedInt() const; // throw
190 unsigned long toUnsignedLong() const; // throw
191 unsigned long long toUnsignedLongLong() const; // throw
192
193 private:
194 static ELEM_TYPE dInR(const InfInt& R, const InfInt& D);
195 static void multiplyByDigit(ELEM_TYPE factor, std::vector<ELEM_TYPE>& val);
196
197 void correct(bool justCheckLeadingZeros = false, bool hasValidSign = false);
198 void fromString(const std::string& s);
199 void optimizeSqrtSearchBounds(InfInt& lo, InfInt& hi) const;
200 void truncateToBase();
201 bool equalizeSigns();
202 void removeLeadingZeros();
203
204 std::vector<ELEM_TYPE> val; // number with base FACTOR
205 bool pos; // true if number is positive
206};
207
208inline InfInt::InfInt() : pos(true) {
209 // PROFINY_SCOPE
210 val.push_back((ELEM_TYPE)0);
211}
212
213inline InfInt::InfInt(const char* c) {
214 // PROFINY_SCOPE
215 fromString(c);
216}
217
218inline InfInt::InfInt(const std::string& s) {
219 // PROFINY_SCOPE
220 fromString(s);
221}
222
223inline InfInt::InfInt(int l) : pos(l >= 0) {
224 // PROFINY_SCOPE
225 bool subtractOne = false;
226 if (l == INT_MIN) {
227 subtractOne = true;
228 ++l;
229 }
230
231 if (!pos) {
232 l = -l;
233 }
234 do {
235 div_t dt = my_div(l, BASE);
236 val.push_back((ELEM_TYPE)dt.rem);
237 l = dt.quot;
238 } while (l > 0);
239
240 if (subtractOne) {
241 --*this;
242 }
243}
244
245inline InfInt::InfInt(long l) : pos(l >= 0) {
246 // PROFINY_SCOPE
247 bool subtractOne = false;
248 if (l == LONG_MIN) {
249 subtractOne = true;
250 ++l;
251 }
252
253 if (!pos) {
254 l = -l;
255 }
256 do {
257 ldiv_t dt = my_ldiv(l, BASE);
258 val.push_back((ELEM_TYPE)dt.rem);
259 l = dt.quot;
260 } while (l > 0);
261
262 if (subtractOne) {
263 --*this;
264 }
265}
266
267inline InfInt::InfInt(long long l) : pos(l >= 0) {
268 // PROFINY_SCOPE
269 bool subtractOne = false;
270 if (l == LONG_LONG_MIN) {
271 subtractOne = true;
272 ++l;
273 }
274
275 if (!pos) {
276 l = -l;
277 }
278 do {
279 lldiv_t dt = my_lldiv(l, BASE);
280 val.push_back((ELEM_TYPE)dt.rem);
281 l = dt.quot;
282 } while (l > 0);
283
284 if (subtractOne) {
285 --*this;
286 }
287}
288
289inline InfInt::InfInt(unsigned int l) : pos(true) {
290 // PROFINY_SCOPE
291 do {
292 val.push_back((ELEM_TYPE)(l % BASE));
293 l = l / BASE;
294 } while (l > 0);
295}
296
297inline InfInt::InfInt(unsigned long l) : pos(true) {
298 // PROFINY_SCOPE
299 do {
300 val.push_back((ELEM_TYPE)(l % BASE));
301 l = l / BASE;
302 } while (l > 0);
303}
304
305inline InfInt::InfInt(unsigned long long l) : pos(true) {
306 // PROFINY_SCOPE
307 do {
308 val.push_back((ELEM_TYPE)(l % BASE));
309 l = l / BASE;
310 } while (l > 0);
311}
312
313inline InfInt::InfInt(const InfInt& l) : val(l.val), pos(l.pos) {
314 // PROFINY_SCOPE
315}
316
317inline const InfInt& InfInt::operator=(const char* c) {
318 // PROFINY_SCOPE
319 fromString(c);
320 return *this;
321}
322
323inline const InfInt& InfInt::operator=(const std::string& s) {
324 // PROFINY_SCOPE
325 fromString(s);
326 return *this;
327}
328
329inline const InfInt& InfInt::operator=(int l) {
330 // PROFINY_SCOPE
331 bool subtractOne = false;
332 if (l == INT_MIN) {
333 subtractOne = true;
334 ++l;
335 }
336
337 pos = l >= 0;
338 val.clear();
339 if (!pos) {
340 l = -l;
341 }
342 do {
343 div_t dt = my_div(l, BASE);
344 val.push_back((ELEM_TYPE)dt.rem);
345 l = dt.quot;
346 } while (l > 0);
347
348 return subtractOne ? --*this : *this;
349}
350
351inline const InfInt& InfInt::operator=(long l) {
352 // PROFINY_SCOPE
353 bool subtractOne = false;
354 if (l == LONG_MIN) {
355 subtractOne = true;
356 ++l;
357 }
358
359 pos = l >= 0;
360 val.clear();
361 if (!pos) {
362 l = -l;
363 }
364 do {
365 ldiv_t dt = my_ldiv(l, BASE);
366 val.push_back((ELEM_TYPE)dt.rem);
367 l = dt.quot;
368 } while (l > 0);
369
370 return subtractOne ? --*this : *this;
371}
372
373inline const InfInt& InfInt::operator=(long long l) {
374 // PROFINY_SCOPE
375 bool subtractOne = false;
376 if (l == LONG_LONG_MIN) {
377 subtractOne = true;
378 ++l;
379 }
380
381 pos = l >= 0;
382 val.clear();
383 if (!pos) {
384 l = -l;
385 }
386 do {
387 lldiv_t dt = my_lldiv(l, BASE);
388 val.push_back((ELEM_TYPE)dt.rem);
389 l = dt.quot;
390 } while (l > 0);
391
392 return subtractOne ? --*this : *this;
393}
394
395inline const InfInt& InfInt::operator=(unsigned int l) {
396 // PROFINY_SCOPE
397 pos = true;
398 val.clear();
399 do {
400 val.push_back((ELEM_TYPE)(l % BASE));
401 l = l / BASE;
402 } while (l > 0);
403 return *this;
404}
405
406inline const InfInt& InfInt::operator=(unsigned long l) {
407 // PROFINY_SCOPE
408 pos = true;
409 val.clear();
410 do {
411 val.push_back((ELEM_TYPE)(l % BASE));
412 l = l / BASE;
413 } while (l > 0);
414 return *this;
415}
416
417inline const InfInt& InfInt::operator=(unsigned long long l) {
418 // PROFINY_SCOPE
419 pos = true;
420 val.clear();
421 do {
422 val.push_back((ELEM_TYPE)(l % BASE));
423 l = l / BASE;
424 } while (l > 0);
425 return *this;
426}
427
428inline const InfInt& InfInt::operator=(const InfInt& l) {
429 // PROFINY_SCOPE
430 if (this == &l) return *this;
431 pos = l.pos;
432 val = l.val;
433 return *this;
434}
435
436inline const InfInt& InfInt::operator++() {
437 // PROFINY_SCOPE
438 val[0] += (pos ? 1 : -1);
439 this->correct(false, true);
440 return *this;
441}
442
443inline const InfInt& InfInt::operator--() {
444 // PROFINY_SCOPE
445 val[0] -= (pos ? 1 : -1);
446 this->correct(false, true);
447 return *this;
448}
449
450inline InfInt InfInt::operator++(int) {
451 // PROFINY_SCOPE
452 InfInt result = *this;
453 val[0] += (pos ? 1 : -1);
454 this->correct(false, true);
455 return result;
456}
457
458inline InfInt InfInt::operator--(int) {
459 // PROFINY_SCOPE
460 InfInt result = *this;
461 val[0] -= (pos ? 1 : -1);
462 this->correct(false, true);
463 return result;
464}
465
466inline const InfInt& InfInt::operator+=(const InfInt& rhs) {
467 // PROFINY_SCOPE
468 if (rhs.val.size() > val.size()) {
469 val.resize(rhs.val.size(), 0);
470 }
471 for (size_t i = 0; i < val.size(); ++i) {
472 val[i] = (pos ? val[i] : -val[i]) +
473 (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0);
474 }
475 correct();
476 return *this;
477}
478
479inline const InfInt& InfInt::operator-=(const InfInt& rhs) {
480 // PROFINY_SCOPE
481 if (rhs.val.size() > val.size()) {
482 val.resize(rhs.val.size(), 0);
483 }
484 for (size_t i = 0; i < val.size(); ++i) {
485 val[i] = (pos ? val[i] : -val[i]) -
486 (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0);
487 }
488 correct();
489 return *this;
490}
491
492inline const InfInt& InfInt::operator*=(const InfInt& rhs) {
493 // PROFINY_SCOPE
494 // TODO: optimize (do not use operator*)
495 *this = *this * rhs;
496 return *this;
497}
498
499inline const InfInt& InfInt::operator/=(const InfInt& rhs) {
500 // PROFINY_SCOPE
501 if (rhs == 0) {
503 throw InfIntException("division by zero");
504#else
505 std::cerr << "Division by zero!" << std::endl;
506 return *this;
507#endif
508 }
509 InfInt R;
510 InfInt D = (rhs.pos ? rhs : -rhs);
511 InfInt N = (pos ? *this : -*this);
512 bool oldpos = pos;
513 std::fill(val.begin(), val.end(), 0);
514 for (int i = (int)N.val.size() - 1; i >= 0; --i) {
515 R.val.insert(R.val.begin(), N.val[i]);
516 R.correct(true);
517 ELEM_TYPE cnt = dInR(R, D);
518 R -= D * cnt;
519 val[i] += cnt;
520 }
521 correct();
522 pos = (val.size() == 1 && val[0] == 0) ? true : (oldpos == rhs.pos);
523 return *this;
524}
525
526inline const InfInt& InfInt::operator%=(const InfInt& rhs) {
527 // PROFINY_SCOPE
528 // TODO: optimize (do not use operator%)
529 *this = *this % rhs;
530 return *this;
531 // if (rhs == 0)
532 // {
533 // #ifdef INFINT_USE_EXCEPTIONS
534 // throw InfIntException("division by zero");
535 // #else
536 // std::cerr << "Division by zero!" << std::endl;
537 // return *this;
538 // #endif
539 // }
540 // InfInt D = (rhs.pos ? rhs : -rhs), N = (pos ? *this : -*this);
541 // bool oldpos = pos;
542 // val.clear();
543 // for (int i = (int) N.val.size() - 1; i >= 0; --i)
544 // {
545 // val.insert(val.begin(), N.val[i]);
546 // correct(true);
547 // *this -= D * dInR(*this, D);
548 // }
549 // correct();
550 // pos = (val.size() == 1 && val[0] == 0) ? true : oldpos;
551 // return *this;
552}
553
554inline const InfInt& InfInt::operator*=(ELEM_TYPE rhs) {
555 // PROFINY_SCOPE
556 ELEM_TYPE factor = rhs < 0 ? -rhs : rhs;
557 bool oldpos = pos;
558 multiplyByDigit(factor, val);
559 correct();
560 pos = (val.size() == 1 && val[0] == 0) ? true : (oldpos == (rhs >= 0));
561 return *this;
562}
563
564inline InfInt InfInt::operator-() const {
565 // PROFINY_SCOPE
566 InfInt result = *this;
567 result.pos = !pos;
568 return result;
569}
570
571inline InfInt InfInt::operator+(const InfInt& rhs) const {
572 // PROFINY_SCOPE
573 InfInt result;
574 result.val.resize(val.size() > rhs.val.size() ? val.size() : rhs.val.size(), 0);
575 for (size_t i = 0; i < val.size() || i < rhs.val.size(); ++i) {
576 result.val[i] = (i < val.size() ? (pos ? val[i] : -val[i]) : 0) +
577 (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0);
578 }
579 result.correct();
580 return result;
581}
582
583inline InfInt InfInt::operator-(const InfInt& rhs) const {
584 // PROFINY_SCOPE
585 InfInt result;
586 result.val.resize(val.size() > rhs.val.size() ? val.size() : rhs.val.size(), 0);
587 for (size_t i = 0; i < val.size() || i < rhs.val.size(); ++i) {
588 result.val[i] = (i < val.size() ? (pos ? val[i] : -val[i]) : 0) -
589 (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0);
590 }
591 result.correct();
592 return result;
593}
594
595inline InfInt InfInt::operator*(const InfInt& rhs) const {
596 // PROFINY_SCOPE
597 InfInt result;
598 result.val.resize(val.size() + rhs.val.size(), 0);
599 PRODUCT_TYPE carry = 0;
600 size_t digit = 0;
601 for (;; ++digit) {
602 lldiv_t dt = my_lldiv(carry, BASE);
603 carry = dt.quot;
604 result.val[digit] = (ELEM_TYPE)dt.rem;
605
606 bool found = false;
607 for (size_t i = digit < rhs.val.size() ? 0 : digit - rhs.val.size() + 1;
608 i < val.size() && i <= digit; ++i) {
609 PRODUCT_TYPE pval = result.val[digit] + val[i] * (PRODUCT_TYPE)rhs.val[digit - i];
610 if (pval >= BASE || pval <= -BASE) {
611 lldiv_t dt = my_lldiv(pval, BASE);
612 carry += dt.quot;
613 pval = dt.rem;
614 }
615 result.val[digit] = (ELEM_TYPE)pval;
616 found = true;
617 }
618 if (!found) {
619 break;
620 }
621 }
622 for (; carry > 0; ++digit) {
623 lldiv_t dt = my_lldiv(carry, BASE);
624 result.val[digit] = (ELEM_TYPE)dt.rem;
625 carry = dt.quot;
626 }
627 result.correct();
628 result.pos = (result.val.size() == 1 && result.val[0] == 0) ? true : (pos == rhs.pos);
629 return result;
630}
631
632inline InfInt InfInt::operator/(const InfInt& rhs) const {
633 // PROFINY_SCOPE
634 if (rhs == 0) {
636 throw InfIntException("division by zero");
637#else
638 std::cerr << "Division by zero!" << std::endl;
639 return 0;
640#endif
641 }
642 InfInt Q;
643 InfInt R;
644 InfInt D = (rhs.pos ? rhs : -rhs);
645 InfInt N = (pos ? *this : -*this);
646 Q.val.resize(N.val.size(), 0);
647 for (int i = (int)N.val.size() - 1; i >= 0; --i) {
648 R.val.insert(R.val.begin(), N.val[i]);
649 R.correct(true);
650 ELEM_TYPE cnt = dInR(R, D);
651 R -= D * cnt;
652 Q.val[i] += cnt;
653 }
654 Q.correct();
655 Q.pos = (Q.val.size() == 1 && Q.val[0] == 0) ? true : (pos == rhs.pos);
656 return Q;
657}
658
659inline InfInt InfInt::operator%(const InfInt& rhs) const {
660 // PROFINY_SCOPE
661 if (rhs == 0) {
663 throw InfIntException("division by zero");
664#else
665 std::cerr << "Division by zero!" << std::endl;
666 return 0;
667#endif
668 }
669 InfInt R;
670 InfInt D = (rhs.pos ? rhs : -rhs);
671 InfInt N = (pos ? *this : -*this);
672 for (int i = (int)N.val.size() - 1; i >= 0; --i) {
673 R.val.insert(R.val.begin(), N.val[i]);
674 R.correct(true);
675 R -= D * dInR(R, D);
676 }
677 R.correct();
678 R.pos = (R.val.size() == 1 && R.val[0] == 0) ? true : pos;
679 return R;
680}
681
682inline InfInt InfInt::operator*(ELEM_TYPE rhs) const {
683 // PROFINY_SCOPE
684 InfInt result = *this;
685 ELEM_TYPE factor = rhs < 0 ? -rhs : rhs;
686 multiplyByDigit(factor, result.val);
687 result.correct();
688 result.pos = (result.val.size() == 1 && result.val[0] == 0) ? true : (pos == (rhs >= 0));
689 return result;
690}
691
692inline bool InfInt::operator==(const InfInt& rhs) const {
693 // PROFINY_SCOPE
694 if (pos != rhs.pos || val.size() != rhs.val.size()) {
695 return false;
696 }
697 for (int i = (int)val.size() - 1; i >= 0; --i) {
698 if (val[i] != rhs.val[i]) {
699 return false;
700 }
701 }
702 return true;
703}
704
705inline bool InfInt::operator!=(const InfInt& rhs) const {
706 // PROFINY_SCOPE
707 if (pos != rhs.pos || val.size() != rhs.val.size()) {
708 return true;
709 }
710 for (int i = (int)val.size() - 1; i >= 0; --i) {
711 if (val[i] != rhs.val[i]) {
712 return true;
713 }
714 }
715 return false;
716}
717
718inline bool InfInt::operator<(const InfInt& rhs) const {
719 // PROFINY_SCOPE
720 if (pos && !rhs.pos) {
721 return false;
722 }
723 if (!pos && rhs.pos) {
724 return true;
725 }
726 if (val.size() > rhs.val.size()) {
727 return pos ? false : true;
728 }
729 if (val.size() < rhs.val.size()) {
730 return pos ? true : false;
731 }
732 for (int i = (int)val.size() - 1; i >= 0; --i) {
733 if (val[i] < rhs.val[i]) {
734 return pos ? true : false;
735 }
736 if (val[i] > rhs.val[i]) {
737 return pos ? false : true;
738 }
739 }
740 return false;
741}
742
743inline bool InfInt::operator<=(const InfInt& rhs) const {
744 // PROFINY_SCOPE
745 if (pos && !rhs.pos) {
746 return false;
747 }
748 if (!pos && rhs.pos) {
749 return true;
750 }
751 if (val.size() > rhs.val.size()) {
752 return pos ? false : true;
753 }
754 if (val.size() < rhs.val.size()) {
755 return pos ? true : false;
756 }
757 for (int i = (int)val.size() - 1; i >= 0; --i) {
758 if (val[i] < rhs.val[i]) {
759 return pos ? true : false;
760 }
761 if (val[i] > rhs.val[i]) {
762 return pos ? false : true;
763 }
764 }
765 return true;
766}
767
768inline bool InfInt::operator>(const InfInt& rhs) const {
769 // PROFINY_SCOPE
770 if (pos && !rhs.pos) {
771 return true;
772 }
773 if (!pos && rhs.pos) {
774 return false;
775 }
776 if (val.size() > rhs.val.size()) {
777 return pos ? true : false;
778 }
779 if (val.size() < rhs.val.size()) {
780 return pos ? false : true;
781 }
782 for (int i = (int)val.size() - 1; i >= 0; --i) {
783 if (val[i] < rhs.val[i]) {
784 return pos ? false : true;
785 }
786 if (val[i] > rhs.val[i]) {
787 return pos ? true : false;
788 }
789 }
790 return false;
791}
792
793inline bool InfInt::operator>=(const InfInt& rhs) const {
794 // PROFINY_SCOPE
795 if (pos && !rhs.pos) {
796 return true;
797 }
798 if (!pos && rhs.pos) {
799 return false;
800 }
801 if (val.size() > rhs.val.size()) {
802 return pos ? true : false;
803 }
804 if (val.size() < rhs.val.size()) {
805 return pos ? false : true;
806 }
807 for (int i = (int)val.size() - 1; i >= 0; --i) {
808 if (val[i] < rhs.val[i]) {
809 return pos ? false : true;
810 }
811 if (val[i] > rhs.val[i]) {
812 return pos ? true : false;
813 }
814 }
815 return true;
816}
817
818inline void InfInt::optimizeSqrtSearchBounds(InfInt& lo, InfInt& hi) const {
819 // PROFINY_SCOPE
820 InfInt hdn = 1;
821 for (int i = (int)this->numberOfDigits() / 2; i >= 2; --i) {
822 hdn *= 10;
823 }
824 if (lo < hdn) {
825 lo = hdn;
826 }
827 hdn *= 100;
828 if (hi > hdn) {
829 hi = hdn;
830 }
831}
832
833inline InfInt InfInt::intSqrt() const {
834 // PROFINY_SCOPE
835 if (*this <= 0) {
837 throw InfIntException("intSqrt called for non-positive integer");
838#else
839 std::cerr << "intSqrt called for non-positive integer: " << *this << std::endl;
840 return 0;
841#endif
842 }
843 InfInt hi = *this / 2 + 1;
844 InfInt lo = 0;
845 InfInt mid;
846 InfInt mid2;
847 optimizeSqrtSearchBounds(lo, hi);
848 do {
849 mid = (hi + lo) / 2; // 8 factor
850 mid2 = mid * mid; // 1 factor
851 if (mid2 == *this) {
852 lo = mid;
853 break;
854 }
855 if (mid2 < *this) {
856 lo = mid;
857 } else {
858 hi = mid;
859 }
860 } while (lo < hi - 1 && mid2 != *this);
861 return lo;
862}
863
864inline char InfInt::digitAt(size_t i) const {
865 // PROFINY_SCOPE
866 if (numberOfDigits() <= i) {
868 throw InfIntException("invalid digit index");
869#else
870 std::cerr << "Invalid digit index: " << i << std::endl;
871 return -1;
872#endif
873 }
874 return (val[i / DIGIT_COUNT] / powersOfTen[i % DIGIT_COUNT]) % 10;
875}
876
877inline size_t InfInt::numberOfDigits() const {
878 // PROFINY_SCOPE
879 return (val.size() - 1) * DIGIT_COUNT +
880 (val.back() > 99999999
881 ? 9
882 : (val.back() > 9999999
883 ? 8
884 : (val.back() > 999999
885 ? 7
886 : (val.back() > 99999
887 ? 6
888 : (val.back() > 9999
889 ? 5
890 : (val.back() > 999
891 ? 4
892 : (val.back() > 99
893 ? 3
894 : (val.back() > 9 ? 2 : 1))))))));
895}
896
897inline std::string InfInt::to_string() const {
898 // PROFINY_SCOPE
899 std::ostringstream oss;
900 oss << *this;
901 return oss.str();
902}
903
904inline size_t InfInt::size() const {
905 // PROFINY_SCOPE
906 return val.size() * sizeof(ELEM_TYPE) + sizeof(bool);
907}
908
909inline int InfInt::toInt() const {
910 // PROFINY_SCOPE
911 if (*this > INT_MAX || *this < INT_MIN) {
913 throw InfIntException("out of bounds");
914#else
915 std::cerr << "Out of INT bounds: " << *this << std::endl;
916#endif
917 }
918 int result = 0;
919 for (int i = (int)val.size() - 1; i >= 0; --i) {
920 result = result * BASE + val[i];
921 }
922 return pos ? result : -result;
923}
924
925inline long InfInt::toLong() const {
926 // PROFINY_SCOPE
927 if (*this > LONG_MAX || *this < LONG_MIN) {
929 throw InfIntException("out of bounds");
930#else
931 std::cerr << "Out of LONG bounds: " << *this << std::endl;
932#endif
933 }
934 long result = 0;
935 for (int i = (int)val.size() - 1; i >= 0; --i) {
936 result = result * BASE + val[i];
937 }
938 return pos ? result : -result;
939}
940
941inline long long InfInt::toLongLong() const {
942 // PROFINY_SCOPE
943 if (*this > LONG_LONG_MAX || *this < LONG_LONG_MIN) {
945 throw InfIntException("out of bounds");
946#else
947 std::cerr << "Out of LLONG bounds: " << *this << std::endl;
948#endif
949 }
950 long long result = 0;
951 for (int i = (int)val.size() - 1; i >= 0; --i) {
952 result = result * BASE + val[i];
953 }
954 return pos ? result : -result;
955}
956
957inline unsigned int InfInt::toUnsignedInt() const {
958 // PROFINY_SCOPE
959 if (!pos || *this > UINT_MAX) {
961 throw InfIntException("out of bounds");
962#else
963 std::cerr << "Out of UINT bounds: " << *this << std::endl;
964#endif
965 }
966 unsigned int result = 0;
967 for (int i = (int)val.size() - 1; i >= 0; --i) {
968 result = result * BASE + val[i];
969 }
970 return result;
971}
972
973inline unsigned long InfInt::toUnsignedLong() const {
974 // PROFINY_SCOPE
975 if (!pos || *this > ULONG_MAX) {
977 throw InfIntException("out of bounds");
978#else
979 std::cerr << "Out of ULONG bounds: " << *this << std::endl;
980#endif
981 }
982 unsigned long result = 0;
983 for (int i = (int)val.size() - 1; i >= 0; --i) {
984 result = result * BASE + val[i];
985 }
986 return result;
987}
988
989inline unsigned long long InfInt::toUnsignedLongLong() const {
990 // PROFINY_SCOPE
991 if (!pos || *this > ULONG_LONG_MAX) {
993 throw InfIntException("out of bounds");
994#else
995 std::cerr << "Out of ULLONG bounds: " << *this << std::endl;
996#endif
997 }
998 unsigned long long result = 0;
999 for (int i = (int)val.size() - 1; i >= 0; --i) {
1000 result = result * BASE + val[i];
1001 }
1002 return result;
1003}
1004
1005inline void InfInt::truncateToBase() {
1006 // PROFINY_SCOPE
1007 for (size_t i = 0; i < val.size(); ++i) // truncate each
1008 {
1009 if (val[i] >= BASE || val[i] <= -BASE) {
1010 div_t dt = my_div(val[i], BASE);
1011 val[i] = dt.rem;
1012 if (i + 1 >= val.size()) {
1013 val.push_back(dt.quot);
1014 } else {
1015 val[i + 1] += dt.quot;
1016 }
1017 }
1018 }
1019}
1020
1021inline bool InfInt::equalizeSigns() {
1022 // PROFINY_SCOPE
1023 bool isPositive = true;
1024 int i = (int)((val.size())) - 1;
1025 for (; i >= 0; --i) {
1026 if (val[i] != 0) {
1027 isPositive = val[i--] > 0;
1028 break;
1029 }
1030 }
1031
1032 if (isPositive) {
1033 for (; i >= 0; --i) {
1034 if (val[i] < 0) {
1035 int k = 0;
1036 int index = i + 1;
1037 for (; (size_t)(index) < val.size() && val[index] == 0; ++k, ++index)
1038 ; // count adjacent zeros on left
1039 // if ((size_t)(index) < val.size() && val[index] > 0)
1040 { // number on the left is positive
1041 val[index] -= 1;
1042 val[i] += BASE;
1043 for (; k > 0; --k) {
1044 val[i + k] = UPPER_BOUND;
1045 }
1046 }
1047 }
1048 }
1049 } else {
1050 for (; i >= 0; --i) {
1051 if (val[i] > 0) {
1052 int k = 0;
1053 int index = i + 1;
1054 for (; (size_t)(index) < val.size() && val[index] == 0; ++k, ++index)
1055 ; // count adjacent zeros on right
1056 // if ((size_t)(index) < val.size() && val[index] < 0)
1057 { // number on the left is negative
1058 val[index] += 1;
1059 val[i] -= BASE;
1060 for (; k > 0; --k) {
1061 val[i + k] = -UPPER_BOUND;
1062 }
1063 }
1064 }
1065 }
1066 }
1067
1068 return isPositive;
1069}
1070
1071inline void InfInt::removeLeadingZeros() {
1072 // PROFINY_SCOPE
1073 for (int i = (int)(val.size()) - 1; i > 0; --i) // remove leading 0's
1074 {
1075 if (val[i] != 0) {
1076 return;
1077 }
1078
1079 val.erase(val.begin() + i);
1080 }
1081}
1082
1083inline void InfInt::correct(bool justCheckLeadingZeros, bool hasValidSign) {
1084 // PROFINY_SCOPE
1085 if (!justCheckLeadingZeros) {
1086 truncateToBase();
1087
1088 if (equalizeSigns()) {
1089 pos = ((val.size() == 1 && val[0] == 0) || !hasValidSign) ? true : pos;
1090 } else {
1091 pos = hasValidSign ? !pos : false;
1092 for (size_t i = 0; i < val.size(); ++i) {
1093 val[i] = abs(val[i]);
1094 }
1095 }
1096 }
1097
1098 removeLeadingZeros();
1099}
1100
1101inline void InfInt::fromString(const std::string& s) {
1102 // PROFINY_SCOPE
1103 pos = true;
1104 val.clear();
1105 val.reserve(s.size() / DIGIT_COUNT + 1);
1106 int i = (int)s.size() - DIGIT_COUNT;
1107 for (; i >= 0; i -= DIGIT_COUNT) {
1108 val.push_back(atoi(s.substr(i, DIGIT_COUNT).c_str()));
1109 }
1110 if (i > -DIGIT_COUNT) {
1111 std::string ss = s.substr(0, i + DIGIT_COUNT);
1112 if (ss.size() == 1 && ss[0] == '-') {
1113 pos = false;
1114 } else {
1115 val.push_back(atoi(ss.c_str()));
1116 }
1117 }
1118 if (val.back() < 0) {
1119 val.back() = -val.back();
1120 pos = false;
1121 }
1122 correct(true);
1123}
1124
1125inline ELEM_TYPE InfInt::dInR(const InfInt& R, const InfInt& D) {
1126 // PROFINY_SCOPE
1127 ELEM_TYPE min = 0;
1128 ELEM_TYPE max = UPPER_BOUND;
1129 while (max > min) {
1130 ELEM_TYPE avg = max + min;
1131 div_t dt = my_div(avg, 2);
1132 avg = dt.rem ? (dt.quot + 1) : dt.quot;
1133 InfInt prod = D * avg;
1134 if (R == prod) {
1135 return avg;
1136 }
1137 if (R > prod) {
1138 min = avg;
1139 } else {
1140 max = avg - 1;
1141 }
1142 }
1143 return min;
1144}
1145
1146inline void InfInt::multiplyByDigit(ELEM_TYPE factor, std::vector<ELEM_TYPE>& val) {
1147 // PROFINY_SCOPE
1148 ELEM_TYPE carry = 0;
1149 for (size_t i = 0; i < val.size(); ++i) {
1150 PRODUCT_TYPE pval = val[i] * (PRODUCT_TYPE)factor + carry;
1151 if (pval >= BASE || pval <= -BASE) {
1152 lldiv_t dt = my_lldiv(pval, BASE);
1153 carry = (ELEM_TYPE)dt.quot;
1154 pval = dt.rem;
1155 } else {
1156 carry = 0;
1157 }
1158 val[i] = (ELEM_TYPE)pval;
1159 }
1160 if (carry > 0) {
1161 val.push_back(carry);
1162 }
1163}
1164
1165/**************************************************************/
1166/******************** NON-MEMBER OPERATORS ********************/
1167/**************************************************************/
1168
1169inline std::istream& operator>>(std::istream& s, InfInt& n) {
1170 // PROFINY_SCOPE
1171 std::string str;
1172 s >> str;
1173 n.fromString(str);
1174 return s;
1175}
1176
1177inline std::ostream& operator<<(std::ostream& s, const InfInt& n) {
1178 // PROFINY_SCOPE
1179 if (!n.pos) {
1180 s << '-';
1181 }
1182 bool first = true;
1183 for (int i = (int)n.val.size() - 1; i >= 0; --i) {
1184 if (first) {
1185 s << n.val[i];
1186 first = false;
1187 } else {
1188 s << std::setfill('0') << std::setw(DIGIT_COUNT) << n.val[i];
1189 }
1190 }
1191 s << std::setfill(' ');
1192 return s;
1193}
1194
1195namespace std {
1196inline std::string to_string(const InfInt& val) { return val.to_string(); }
1197}; // namespace std
1198
1200 size_t operator()(const InfInt& e) const noexcept { return std::hash<unsigned long long>{}(e.toUnsignedLongLong()); }
1201};
1202
1203#endif
static const int powersOfTen[]
Definition InfInt.hpp:71
int ELEM_TYPE
Definition InfInt.hpp:66
#define ULONG_LONG_MAX
Definition InfInt.hpp:57
#define LONG_LONG_MAX
Definition InfInt.hpp:53
static div_t my_div(int num, int denom)
Definition InfInt.hpp:92
long long PRODUCT_TYPE
Definition InfInt.hpp:67
#define LONG_LONG_MIN
Definition InfInt.hpp:49
static const ELEM_TYPE DIGIT_COUNT
Definition InfInt.hpp:70
#define INFINT_USE_EXCEPTIONS
Definition InfInt.hpp:60
static const ELEM_TYPE BASE
Definition InfInt.hpp:68
static ldiv_t my_ldiv(long num, long denom)
Definition InfInt.hpp:99
static lldiv_t my_lldiv(long long num, long long denom)
Definition InfInt.hpp:106
static const ELEM_TYPE UPPER_BOUND
Definition InfInt.hpp:69
InfIntException(const std::string &txt)
Definition InfInt.hpp:84
const char * what() const
Definition InfInt.hpp:89
InfInt(long l)
Definition InfInt.hpp:245
InfInt operator--(int)
Definition InfInt.hpp:458
bool operator!=(const InfInt &rhs) const
Definition InfInt.hpp:705
int toInt() const
Definition InfInt.hpp:909
InfInt(unsigned long l)
Definition InfInt.hpp:297
const InfInt & operator=(long l)
Definition InfInt.hpp:351
const InfInt & operator+=(const InfInt &rhs)
Definition InfInt.hpp:466
const InfInt & operator=(const std::string &s)
Definition InfInt.hpp:323
char digitAt(size_t i) const
Definition InfInt.hpp:864
bool operator<(const InfInt &rhs) const
Definition InfInt.hpp:718
InfInt operator*(const InfInt &rhs) const
Definition InfInt.hpp:595
bool operator<=(const InfInt &rhs) const
Definition InfInt.hpp:743
const InfInt & operator%=(const InfInt &rhs)
Definition InfInt.hpp:526
bool operator>(const InfInt &rhs) const
Definition InfInt.hpp:768
std::string to_string() const
Definition InfInt.hpp:897
friend std::istream & operator>>(std::istream &s, InfInt &val)
Definition InfInt.hpp:1169
InfInt(const char *c)
Definition InfInt.hpp:213
InfInt intSqrt() const
Definition InfInt.hpp:833
const InfInt & operator=(unsigned long long l)
Definition InfInt.hpp:417
unsigned int toUnsignedInt() const
Definition InfInt.hpp:957
const InfInt & operator=(int l)
Definition InfInt.hpp:329
const InfInt & operator--()
Definition InfInt.hpp:443
long toLong() const
Definition InfInt.hpp:925
const InfInt & operator*=(const InfInt &rhs)
Definition InfInt.hpp:492
const InfInt & operator=(const char *c)
Definition InfInt.hpp:317
size_t size() const
Definition InfInt.hpp:904
const InfInt & operator=(unsigned long l)
Definition InfInt.hpp:406
bool operator>=(const InfInt &rhs) const
Definition InfInt.hpp:793
const InfInt & operator=(const InfInt &l)
Definition InfInt.hpp:428
long long toLongLong() const
Definition InfInt.hpp:941
const InfInt & operator-=(const InfInt &rhs)
Definition InfInt.hpp:479
unsigned long long toUnsignedLongLong() const
Definition InfInt.hpp:989
size_t numberOfDigits() const
Definition InfInt.hpp:877
const InfInt & operator++()
Definition InfInt.hpp:436
InfInt operator++(int)
Definition InfInt.hpp:450
InfInt(const std::string &s)
Definition InfInt.hpp:218
InfInt operator*(ELEM_TYPE rhs) const
Definition InfInt.hpp:682
InfInt(int l)
Definition InfInt.hpp:223
const InfInt & operator/=(const InfInt &rhs)
Definition InfInt.hpp:499
InfInt operator-(const InfInt &rhs) const
Definition InfInt.hpp:583
const InfInt & operator=(unsigned int l)
Definition InfInt.hpp:395
const InfInt & operator=(long long l)
Definition InfInt.hpp:373
InfInt operator+(const InfInt &rhs) const
Definition InfInt.hpp:571
InfInt(unsigned int l)
Definition InfInt.hpp:289
InfInt(long long l)
Definition InfInt.hpp:267
InfInt operator%(const InfInt &rhs) const
Definition InfInt.hpp:659
const InfInt & operator*=(ELEM_TYPE rhs)
Definition InfInt.hpp:554
unsigned long toUnsignedLong() const
Definition InfInt.hpp:973
InfInt operator-() const
Definition InfInt.hpp:564
InfInt operator/(const InfInt &rhs) const
Definition InfInt.hpp:632
InfInt(unsigned long long l)
Definition InfInt.hpp:305
bool operator==(const InfInt &rhs) const
Definition InfInt.hpp:692
InfInt(const InfInt &l)
Definition InfInt.hpp:313
InfInt()
Definition InfInt.hpp:208
std::string to_string(const InfInt &val)
Definition InfInt.hpp:1196
size_t operator()(const InfInt &e) const noexcept
Definition InfInt.hpp:1200