/* * InfInt - Arbitrary-Precision Integer Arithmetic Library * Copyright (C) 2013 Sercan Tutar * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * * USAGE: * It is pretty straight forward to use the library. Just create an instance of * InfInt class and start using it. * * Useful methods: * intSqrt: integer square root operation * digitAt: returns digit at index * numberOfDigits: returns number of digits * size: returns size in bytes * toString: converts it to a string * * There are also conversion methods which allow conversion to primitive types: * toInt, toLong, toLongLong, toUnsignedInt, toUnsignedLong, toUnsignedLongLong. * * You may define INFINT_USE_EXCEPTIONS and library methods will start raising * InfIntException in case of error instead of writing error messages using * std::cerr. * * See ReadMe.txt for more info. * * * No overflows, happy programmers! * */ #ifndef INFINT_H_ #define INFINT_H_ #include #include #include #include #include //#include //#include #ifdef _WIN32 #define LONG_LONG_MIN LLONG_MIN #define LONG_LONG_MAX LLONG_MAX #define ULONG_LONG_MAX ULLONG_MAX #endif #ifdef INFINT_USE_EXCEPTIONS #include #endif typedef int ELEM_TYPE; typedef long long PRODUCT_TYPE; static const ELEM_TYPE BASE = 1000000000; static const ELEM_TYPE UPPER_BOUND = 999999999; static const ELEM_TYPE DIGIT_COUNT = 9; static const int powersOfTen[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 }; #ifdef INFINT_USE_EXCEPTIONS class InfIntException: public std::exception { public: InfIntException(const std::string& txt) throw (); ~InfIntException() throw (); const char* what() const throw (); private: std::string txt; }; inline InfIntException::InfIntException(const std::string& txt) throw () : std::exception(), txt(txt) { } inline InfIntException::~InfIntException() throw () { } inline const char* InfIntException::what() const throw () { return txt.c_str(); } #endif inline static div_t my_div(int num, int denom) { div_t result; result.quot = num / denom; result.rem = num - denom * result.quot; return result; } inline static ldiv_t my_ldiv(long num, long denom) { ldiv_t result; result.quot = num / denom; result.rem = num - denom * result.quot; return result; } inline static lldiv_t my_lldiv(long long num, long long denom) { lldiv_t result; result.quot = num / denom; result.rem = num - denom * result.quot; return result; } class InfInt { friend std::ostream& operator<<(std::ostream &s, const InfInt &n); friend std::istream& operator>>(std::istream &s, InfInt &val); public: /* constructors */ InfInt(); InfInt(const char* c); InfInt(const std::string& s); InfInt(int l); InfInt(long l); InfInt(long long l); InfInt(unsigned int l); InfInt(unsigned long l); InfInt(unsigned long long l); InfInt(const InfInt& l); /* assignment operators */ const InfInt& operator=(const char* c); const InfInt& operator=(const std::string& s); const InfInt& operator=(int l); const InfInt& operator=(long l); const InfInt& operator=(long long l); const InfInt& operator=(unsigned int l); const InfInt& operator=(unsigned long l); const InfInt& operator=(unsigned long long l); const InfInt& operator=(const InfInt& l); /* unary increment/decrement operators */ const InfInt& operator++(); const InfInt& operator--(); InfInt operator++(int); InfInt operator--(int); /* operational assignments */ const InfInt& operator+=(const InfInt& rhs); const InfInt& operator-=(const InfInt& rhs); const InfInt& operator*=(const InfInt& rhs); const InfInt& operator/=(const InfInt& rhs); // throw const InfInt& operator%=(const InfInt& rhs); // throw const InfInt& operator*=(ELEM_TYPE rhs); /* operations */ InfInt operator-() const; InfInt operator+(const InfInt& rhs) const; InfInt operator-(const InfInt& rhs) const; InfInt operator*(const InfInt& rhs) const; InfInt operator/(const InfInt& rhs) const; // throw InfInt operator%(const InfInt& rhs) const; // throw InfInt operator*(ELEM_TYPE rhs) const; /* relational operations */ bool operator==(const InfInt& rhs) const; bool operator!=(const InfInt& rhs) const; bool operator<(const InfInt& rhs) const; bool operator<=(const InfInt& rhs) const; bool operator>(const InfInt& rhs) const; bool operator>=(const InfInt& rhs) const; /* integer square root */ InfInt intSqrt() const; // throw /* digit operations */ char digitAt(size_t i) const; // throw size_t numberOfDigits() const; /* size in bytes */ size_t size() const; /* string conversion */ std::string toString() const; /* conversion to primitive types */ int toInt() const; // throw long toLong() const; // throw long long toLongLong() const; // throw unsigned int toUnsignedInt() const; // throw unsigned long toUnsignedLong() const; // throw unsigned long long toUnsignedLongLong() const; // throw private: static ELEM_TYPE dInR(const InfInt& R, const InfInt& D); static void multiplyByDigit(ELEM_TYPE factor, std::vector& val); void correct(bool justCheckLeadingZeros = false, bool hasValidSign = false); void fromString(const std::string& s); void optimizeSqrtSearchBounds(InfInt& lo, InfInt& hi) const; void truncateToBase(); bool equalizeSigns(); void removeLeadingZeros(); std::vector val; // number with base FACTOR bool pos; // true if number is positive }; inline InfInt::InfInt() : pos(true) { //PROFINY_SCOPE val.push_back((ELEM_TYPE) 0); } inline InfInt::InfInt(const char* c) { //PROFINY_SCOPE fromString(c); } inline InfInt::InfInt(const std::string& s) { //PROFINY_SCOPE fromString(s); } inline InfInt::InfInt(int l) : pos(l >= 0) { //PROFINY_SCOPE bool subtractOne = false; if (l == INT_MIN) { subtractOne = true; ++l; } if (!pos) { l = -l; } do { div_t dt = my_div(l, BASE); val.push_back((ELEM_TYPE) dt.rem); l = dt.quot; } while (l > 0); if (subtractOne) { --*this; } } inline InfInt::InfInt(long l) : pos(l >= 0) { //PROFINY_SCOPE bool subtractOne = false; if (l == LONG_MIN) { subtractOne = true; ++l; } if (!pos) { l = -l; } do { ldiv_t dt = my_ldiv(l, BASE); val.push_back((ELEM_TYPE) dt.rem); l = dt.quot; } while (l > 0); if (subtractOne) { --*this; } } inline InfInt::InfInt(long long l) : pos(l >= 0) { //PROFINY_SCOPE bool subtractOne = false; if (l == LONG_LONG_MIN) { subtractOne = true; ++l; } if (!pos) { l = -l; } do { lldiv_t dt = my_lldiv(l, BASE); val.push_back((ELEM_TYPE) dt.rem); l = dt.quot; } while (l > 0); if (subtractOne) { --*this; } } inline InfInt::InfInt(unsigned int l) : pos(true) { //PROFINY_SCOPE do { val.push_back((ELEM_TYPE) (l % BASE)); l = l / BASE; } while (l > 0); } inline InfInt::InfInt(unsigned long l) : pos(true) { //PROFINY_SCOPE do { val.push_back((ELEM_TYPE) (l % BASE)); l = l / BASE; } while (l > 0); } inline InfInt::InfInt(unsigned long long l) : pos(true) { //PROFINY_SCOPE do { val.push_back((ELEM_TYPE) (l % BASE)); l = l / BASE; } while (l > 0); } inline InfInt::InfInt(const InfInt& l) : pos(l.pos), val(l.val) { //PROFINY_SCOPE } inline const InfInt& InfInt::operator=(const char* c) { //PROFINY_SCOPE fromString(c); return *this; } inline const InfInt& InfInt::operator=(const std::string& s) { //PROFINY_SCOPE fromString(s); return *this; } inline const InfInt& InfInt::operator=(int l) { //PROFINY_SCOPE bool subtractOne = false; if (l == INT_MIN) { subtractOne = true; ++l; } pos = l >= 0; val.clear(); if (!pos) { l = -l; } do { div_t dt = my_div(l, BASE); val.push_back((ELEM_TYPE) dt.rem); l = dt.quot; } while (l > 0); return subtractOne ? --*this : *this; } inline const InfInt& InfInt::operator=(long l) { //PROFINY_SCOPE bool subtractOne = false; if (l == LONG_MIN) { subtractOne = true; ++l; } pos = l >= 0; val.clear(); if (!pos) { l = -l; } do { ldiv_t dt = my_ldiv(l, BASE); val.push_back((ELEM_TYPE) dt.rem); l = dt.quot; } while (l > 0); return subtractOne ? --*this : *this; } inline const InfInt& InfInt::operator=(long long l) { //PROFINY_SCOPE bool subtractOne = false; if (l == LONG_LONG_MIN) { subtractOne = true; ++l; } pos = l >= 0; val.clear(); if (!pos) { l = -l; } do { lldiv_t dt = my_lldiv(l, BASE); val.push_back((ELEM_TYPE) dt.rem); l = dt.quot; } while (l > 0); return subtractOne ? --*this : *this; } inline const InfInt& InfInt::operator=(unsigned int l) { //PROFINY_SCOPE pos = true; val.clear(); do { val.push_back((ELEM_TYPE) (l % BASE)); l = l / BASE; } while (l > 0); return *this; } inline const InfInt& InfInt::operator=(unsigned long l) { //PROFINY_SCOPE pos = true; val.clear(); do { val.push_back((ELEM_TYPE) (l % BASE)); l = l / BASE; } while (l > 0); return *this; } inline const InfInt& InfInt::operator=(unsigned long long l) { //PROFINY_SCOPE pos = true; val.clear(); do { val.push_back((ELEM_TYPE) (l % BASE)); l = l / BASE; } while (l > 0); return *this; } inline const InfInt& InfInt::operator=(const InfInt& l) { //PROFINY_SCOPE pos = l.pos; val = l.val; return *this; } inline const InfInt& InfInt::operator++() { //PROFINY_SCOPE val[0] += (pos ? 1 : -1); this->correct(false, true); return *this; } inline const InfInt& InfInt::operator--() { //PROFINY_SCOPE val[0] -= (pos ? 1 : -1); this->correct(false, true); return *this; } inline InfInt InfInt::operator++(int) { //PROFINY_SCOPE InfInt result = *this; val[0] += (pos ? 1 : -1); this->correct(false, true); return result; } inline InfInt InfInt::operator--(int) { //PROFINY_SCOPE InfInt result = *this; val[0] -= (pos ? 1 : -1); this->correct(false, true); return result; } inline const InfInt& InfInt::operator+=(const InfInt& rhs) { //PROFINY_SCOPE if (rhs.val.size() > val.size()) { val.resize(rhs.val.size(), 0); } for (size_t i = 0; i < val.size(); ++i) { val[i] = (pos ? val[i] : -val[i]) + (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0); } correct(); return *this; } inline const InfInt& InfInt::operator-=(const InfInt& rhs) { //PROFINY_SCOPE if (rhs.val.size() > val.size()) { val.resize(rhs.val.size(), 0); } for (size_t i = 0; i < val.size(); ++i) { val[i] = (pos ? val[i] : -val[i]) - (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0); } correct(); return *this; } inline const InfInt& InfInt::operator*=(const InfInt& rhs) { //PROFINY_SCOPE // TODO: optimize (do not use operator*) *this = *this * rhs; return *this; } inline const InfInt& InfInt::operator/=(const InfInt& rhs) { //PROFINY_SCOPE if (rhs == 0) { #ifdef INFINT_USE_EXCEPTIONS throw InfIntException("division by zero"); #else std::cerr << "Division by zero!" << std::endl; return *this; #endif } InfInt R, D = (rhs.pos ? rhs : -rhs), N = (pos ? *this : -*this); bool oldpos = pos; std::fill(val.begin(), val.end(), 0); for (int i = (int) N.val.size() - 1; i >= 0; --i) { R.val.insert(R.val.begin(), N.val[i]); R.correct(true); ELEM_TYPE cnt = dInR(R, D); R -= D * cnt; val[i] += cnt; } correct(); pos = (val.size() == 1 && val[0] == 0) ? true : (oldpos == rhs.pos); return *this; } inline const InfInt& InfInt::operator%=(const InfInt& rhs) { //PROFINY_SCOPE // TODO: optimize (do not use operator%) *this = *this % rhs; return *this; // if (rhs == 0) // { //#ifdef INFINT_USE_EXCEPTIONS // throw InfIntException("division by zero"); //#else // std::cerr << "Division by zero!" << std::endl; // return *this; //#endif // } // InfInt D = (rhs.pos ? rhs : -rhs), N = (pos ? *this : -*this); // bool oldpos = pos; // val.clear(); // for (int i = (int) N.val.size() - 1; i >= 0; --i) // { // val.insert(val.begin(), N.val[i]); // correct(true); // *this -= D * dInR(*this, D); // } // correct(); // pos = (val.size() == 1 && val[0] == 0) ? true : oldpos; // return *this; } inline const InfInt& InfInt::operator*=(ELEM_TYPE rhs) { //PROFINY_SCOPE ELEM_TYPE factor = rhs < 0 ? -rhs : rhs; bool oldpos = pos; multiplyByDigit(factor, val); correct(); pos = (val.size() == 1 && val[0] == 0) ? true : (oldpos == (rhs >= 0)); return *this; } inline InfInt InfInt::operator-() const { //PROFINY_SCOPE InfInt result = *this; result.pos = !pos; return result; } inline InfInt InfInt::operator+(const InfInt& rhs) const { //PROFINY_SCOPE InfInt result; result.val.resize(val.size() > rhs.val.size() ? val.size() : rhs.val.size(), 0); for (size_t i = 0; i < val.size() || i < rhs.val.size(); ++i) { result.val[i] = (i < val.size() ? (pos ? val[i] : -val[i]) : 0) + (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0); } result.correct(); return result; } inline InfInt InfInt::operator-(const InfInt& rhs) const { //PROFINY_SCOPE InfInt result; result.val.resize(val.size() > rhs.val.size() ? val.size() : rhs.val.size(), 0); for (size_t i = 0; i < val.size() || i < rhs.val.size(); ++i) { result.val[i] = (i < val.size() ? (pos ? val[i] : -val[i]) : 0) - (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0); } result.correct(); return result; } inline InfInt InfInt::operator*(const InfInt& rhs) const { //PROFINY_SCOPE InfInt result; result.val.resize(val.size() + rhs.val.size(), 0); PRODUCT_TYPE carry = 0; size_t digit = 0; for (;; ++digit) { lldiv_t dt = my_lldiv(carry, BASE); carry = dt.quot; result.val[digit] = (ELEM_TYPE) dt.rem; bool found = false; for (size_t i = digit < rhs.val.size() ? 0 : digit - rhs.val.size() + 1; i < val.size() && i <= digit; ++i) { PRODUCT_TYPE pval = result.val[digit] + val[i] * (PRODUCT_TYPE) rhs.val[digit - i]; if (pval >= BASE || pval <= -BASE) { lldiv_t dt = my_lldiv(pval, BASE); carry += dt.quot; pval = dt.rem; } result.val[digit] = (ELEM_TYPE) pval; found = true; } if (!found) { break; } } for (; carry > 0; ++digit) { lldiv_t dt = my_lldiv(carry, BASE); result.val[digit] = (ELEM_TYPE) dt.rem; carry = dt.quot; } result.correct(); result.pos = (result.val.size() == 1 && result.val[0] == 0) ? true : (pos == rhs.pos); return result; } inline InfInt InfInt::operator/(const InfInt& rhs) const { //PROFINY_SCOPE if (rhs == 0) { #ifdef INFINT_USE_EXCEPTIONS throw InfIntException("division by zero"); #else std::cerr << "Division by zero!" << std::endl; return 0; #endif } InfInt Q, R, D = (rhs.pos ? rhs : -rhs), N = (pos ? *this : -*this); Q.val.resize(N.val.size(), 0); for (int i = (int) N.val.size() - 1; i >= 0; --i) { R.val.insert(R.val.begin(), N.val[i]); R.correct(true); ELEM_TYPE cnt = dInR(R, D); R -= D * cnt; Q.val[i] += cnt; } Q.correct(); Q.pos = (Q.val.size() == 1 && Q.val[0] == 0) ? true : (pos == rhs.pos); return Q; } inline InfInt InfInt::operator%(const InfInt& rhs) const { //PROFINY_SCOPE if (rhs == 0) { #ifdef INFINT_USE_EXCEPTIONS throw InfIntException("division by zero"); #else std::cerr << "Division by zero!" << std::endl; return 0; #endif } InfInt R, D = (rhs.pos ? rhs : -rhs), N = (pos ? *this : -*this); for (int i = (int) N.val.size() - 1; i >= 0; --i) { R.val.insert(R.val.begin(), N.val[i]); R.correct(true); R -= D * dInR(R, D); } R.correct(); R.pos = (R.val.size() == 1 && R.val[0] == 0) ? true : pos; return R; } inline InfInt InfInt::operator*(ELEM_TYPE rhs) const { //PROFINY_SCOPE InfInt result = *this; ELEM_TYPE factor = rhs < 0 ? -rhs : rhs; multiplyByDigit(factor, result.val); result.correct(); result.pos = (result.val.size() == 1 && result.val[0] == 0) ? true : (pos == (rhs >= 0)); return result; } inline bool InfInt::operator==(const InfInt& rhs) const { //PROFINY_SCOPE if (pos != rhs.pos || val.size() != rhs.val.size()) { return false; } for (int i = (int) val.size() - 1; i >= 0; --i) { if (val[i] != rhs.val[i]) { return false; } } return true; } inline bool InfInt::operator!=(const InfInt& rhs) const { //PROFINY_SCOPE if (pos != rhs.pos || val.size() != rhs.val.size()) { return true; } for (int i = (int) val.size() - 1; i >= 0; --i) { if (val[i] != rhs.val[i]) { return true; } } return false; } inline bool InfInt::operator<(const InfInt& rhs) const { //PROFINY_SCOPE if (pos && !rhs.pos) { return false; } if (!pos && rhs.pos) { return true; } if (val.size() > rhs.val.size()) { return pos ? false : true; } if (val.size() < rhs.val.size()) { return pos ? true : false; } for (int i = (int) val.size() - 1; i >= 0; --i) { if (val[i] < rhs.val[i]) { return pos ? true : false; } if (val[i] > rhs.val[i]) { return pos ? false : true; } } return false; } inline bool InfInt::operator<=(const InfInt& rhs) const { //PROFINY_SCOPE if (pos && !rhs.pos) { return false; } if (!pos && rhs.pos) { return true; } if (val.size() > rhs.val.size()) { return pos ? false : true; } if (val.size() < rhs.val.size()) { return pos ? true : false; } for (int i = (int) val.size() - 1; i >= 0; --i) { if (val[i] < rhs.val[i]) { return pos ? true : false; } if (val[i] > rhs.val[i]) { return pos ? false : true; } } return true; } inline bool InfInt::operator>(const InfInt& rhs) const { //PROFINY_SCOPE if (pos && !rhs.pos) { return true; } if (!pos && rhs.pos) { return false; } if (val.size() > rhs.val.size()) { return pos ? true : false; } if (val.size() < rhs.val.size()) { return pos ? false : true; } for (int i = (int) val.size() - 1; i >= 0; --i) { if (val[i] < rhs.val[i]) { return pos ? false : true; } if (val[i] > rhs.val[i]) { return pos ? true : false; } } return false; } inline bool InfInt::operator>=(const InfInt& rhs) const { //PROFINY_SCOPE if (pos && !rhs.pos) { return true; } if (!pos && rhs.pos) { return false; } if (val.size() > rhs.val.size()) { return pos ? true : false; } if (val.size() < rhs.val.size()) { return pos ? false : true; } for (int i = (int) val.size() - 1; i >= 0; --i) { if (val[i] < rhs.val[i]) { return pos ? false : true; } if (val[i] > rhs.val[i]) { return pos ? true : false; } } return true; } inline void InfInt::optimizeSqrtSearchBounds(InfInt& lo, InfInt& hi) const { //PROFINY_SCOPE InfInt hdn = 1; for (int i = (int) this->numberOfDigits() / 2; i >= 2; --i) { hdn *= 10; } if (lo < hdn) { lo = hdn; } hdn *= 100; if (hi > hdn) { hi = hdn; } } inline InfInt InfInt::intSqrt() const { //PROFINY_SCOPE if (*this <= 0) { #ifdef INFINT_USE_EXCEPTIONS throw InfIntException("intSqrt called for non-positive integer"); #else std::cerr << "intSqrt called for non-positive integer: " << *this << std::endl; return 0; #endif } InfInt hi = *this / 2 + 1, lo = 0, mid, mid2; optimizeSqrtSearchBounds(lo, hi); do { mid = (hi + lo) / 2; // 8 factor mid2 = mid * mid; // 1 factor if (mid2 == *this) { lo = mid; break; } else if (mid2 < *this) { lo = mid; } else { hi = mid; } } while (lo < hi - 1 && mid2 != *this); return lo; } inline char InfInt::digitAt(size_t i) const { //PROFINY_SCOPE if (numberOfDigits() <= i) { #ifdef INFINT_USE_EXCEPTIONS throw InfIntException("invalid digit index"); #else std::cerr << "Invalid digit index: " << i << std::endl; return -1; #endif } return (val[i / DIGIT_COUNT] / powersOfTen[i % DIGIT_COUNT]) % 10; } inline size_t InfInt::numberOfDigits() const { //PROFINY_SCOPE return (val.size() - 1) * DIGIT_COUNT + (val.back() > 99999999 ? 9 : (val.back() > 9999999 ? 8 : (val.back() > 999999 ? 7 : (val.back() > 99999 ? 6 : (val.back() > 9999 ? 5 : (val.back() > 999 ? 4 : (val.back() > 99 ? 3 : (val.back() > 9 ? 2 : 1)))))))); } inline std::string InfInt::toString() const { //PROFINY_SCOPE std::ostringstream oss; oss << *this; return oss.str(); } inline size_t InfInt::size() const { //PROFINY_SCOPE return val.size() * sizeof(ELEM_TYPE) + sizeof(bool); } inline int InfInt::toInt() const { //PROFINY_SCOPE if (*this > INT_MAX || *this < INT_MIN) { #ifdef INFINT_USE_EXCEPTIONS throw InfIntException("out of bounds"); #else std::cerr << "Out of INT bounds: " << *this << std::endl; #endif } int result = 0; for (int i = (int) val.size() - 1; i >= 0; --i) { result = result * BASE + val[i]; } return pos ? result : -result; } inline long InfInt::toLong() const { //PROFINY_SCOPE if (*this > LONG_MAX || *this < LONG_MIN) { #ifdef INFINT_USE_EXCEPTIONS throw InfIntException("out of bounds"); #else std::cerr << "Out of LONG bounds: " << *this << std::endl; #endif } long result = 0; for (int i = (int) val.size() - 1; i >= 0; --i) { result = result * BASE + val[i]; } return pos ? result : -result; } inline long long InfInt::toLongLong() const { //PROFINY_SCOPE if (*this > LONG_LONG_MAX || *this < LONG_LONG_MIN) { #ifdef INFINT_USE_EXCEPTIONS throw InfIntException("out of bounds"); #else std::cerr << "Out of LLONG bounds: " << *this << std::endl; #endif } long long result = 0; for (int i = (int) val.size() - 1; i >= 0; --i) { result = result * BASE + val[i]; } return pos ? result : -result; } inline unsigned int InfInt::toUnsignedInt() const { //PROFINY_SCOPE if (!pos || *this > UINT_MAX) { #ifdef INFINT_USE_EXCEPTIONS throw InfIntException("out of bounds"); #else std::cerr << "Out of UINT bounds: " << *this << std::endl; #endif } unsigned int result = 0; for (int i = (int) val.size() - 1; i >= 0; --i) { result = result * BASE + val[i]; } return result; } inline unsigned long InfInt::toUnsignedLong() const { //PROFINY_SCOPE if (!pos || *this > ULONG_MAX) { #ifdef INFINT_USE_EXCEPTIONS throw InfIntException("out of bounds"); #else std::cerr << "Out of ULONG bounds: " << *this << std::endl; #endif } unsigned long result = 0; for (int i = (int) val.size() - 1; i >= 0; --i) { result = result * BASE + val[i]; } return result; } inline unsigned long long InfInt::toUnsignedLongLong() const { //PROFINY_SCOPE if (!pos || *this > ULONG_LONG_MAX) { #ifdef INFINT_USE_EXCEPTIONS throw InfIntException("out of bounds"); #else std::cerr << "Out of ULLONG bounds: " << *this << std::endl; #endif } unsigned long long result = 0; for (int i = (int) val.size() - 1; i >= 0; --i) { result = result * BASE + val[i]; } return result; } inline void InfInt::truncateToBase() { //PROFINY_SCOPE for (size_t i = 0; i < val.size(); ++i) // truncate each { if (val[i] >= BASE || val[i] <= -BASE) { div_t dt = my_div(val[i], BASE); val[i] = dt.rem; if (i + 1 >= val.size()) { val.push_back(dt.quot); } else { val[i + 1] += dt.quot; } } } } inline bool InfInt::equalizeSigns() { //PROFINY_SCOPE bool isPositive = true; int i = (int) ((val.size())) - 1; for (; i >= 0; --i) { if (val[i] != 0) { isPositive = val[i--] > 0; break; } } if (isPositive) { for (; i >= 0; --i) { if (val[i] < 0) { int k = 0, index = i + 1; for (; (size_t)(index) < val.size() && val[index] == 0; ++k, ++index) ; // count adjacent zeros on left //if ((size_t)(index) < val.size() && val[index] > 0) { // number on the left is positive val[index] -= 1; val[i] += BASE; for (; k > 0; --k) { val[i + k] = UPPER_BOUND; } } } } } else { for (; i >= 0; --i) { if (val[i] > 0) { int k = 0, index = i + 1; for (; (size_t)(index) < val.size() && val[index] == 0; ++k, ++index) ; // count adjacent zeros on right //if ((size_t)(index) < val.size() && val[index] < 0) { // number on the left is negative val[index] += 1; val[i] -= BASE; for (; k > 0; --k) { val[i + k] = -UPPER_BOUND; } } } } } return isPositive; } inline void InfInt::removeLeadingZeros() { //PROFINY_SCOPE for (int i = (int) (val.size()) - 1; i > 0; --i) // remove leading 0's { if (val[i] != 0) { return; } else { val.erase(val.begin() + i); } } } inline void InfInt::correct(bool justCheckLeadingZeros, bool hasValidSign) { //PROFINY_SCOPE if (!justCheckLeadingZeros) { truncateToBase(); if (equalizeSigns()) { pos = ((val.size() == 1 && val[0] == 0) || !hasValidSign) ? true : pos; } else { pos = hasValidSign ? !pos : false; for (size_t i = 0; i < val.size(); ++i) { val[i] = abs(val[i]); } } } removeLeadingZeros(); } inline void InfInt::fromString(const std::string& s) { //PROFINY_SCOPE pos = true; val.clear(); val.reserve(s.size() / DIGIT_COUNT + 1); int i = (int) s.size() - DIGIT_COUNT; for (; i >= 0; i -= DIGIT_COUNT) { val.push_back(atoi(s.substr(i, DIGIT_COUNT).c_str())); } if (i > -DIGIT_COUNT) { std::string ss = s.substr(0, i + DIGIT_COUNT); if (ss.size() == 1 && ss[0] == '-') { pos = false; } else { val.push_back(atoi(ss.c_str())); } } if (val.back() < 0) { val.back() = -val.back(); pos = false; } correct(true); } inline ELEM_TYPE InfInt::dInR(const InfInt& R, const InfInt& D) { //PROFINY_SCOPE ELEM_TYPE min = 0, max = UPPER_BOUND; while (max > min) { ELEM_TYPE avg = max + min; div_t dt = my_div(avg, 2); avg = dt.rem ? (dt.quot + 1) : dt.quot; InfInt prod = D * avg; if (R == prod) { return avg; } else if (R > prod) { min = avg; } else { max = avg - 1; } } return min; } inline void InfInt::multiplyByDigit(ELEM_TYPE factor, std::vector& val) { //PROFINY_SCOPE ELEM_TYPE carry = 0; for (size_t i = 0; i < val.size(); ++i) { PRODUCT_TYPE pval = val[i] * (PRODUCT_TYPE) factor + carry; if (pval >= BASE || pval <= -BASE) { lldiv_t dt = my_lldiv(pval, BASE); carry = (ELEM_TYPE) dt.quot; pval = dt.rem; } else { carry = 0; } val[i] = (ELEM_TYPE) pval; } if (carry > 0) { val.push_back(carry); } } /**************************************************************/ /******************** NON-MEMBER OPERATORS ********************/ /**************************************************************/ inline std::istream& operator>>(std::istream &s, InfInt &n) { //PROFINY_SCOPE std::string str; s >> str; n.fromString(str); return s; } inline std::ostream& operator<<(std::ostream &s, const InfInt &n) { //PROFINY_SCOPE if (!n.pos) { s << '-'; } bool first = true; for (int i = (int) n.val.size() - 1; i >= 0; --i) { if (first) { s << n.val[i]; first = false; } else { s << std::setfill('0') << std::setw(DIGIT_COUNT) << n.val[i]; } } return s; } #endif