commit 5bb42f4e2755debb7434d1b90db3d53169ce5df8
parent 6403a87d3789e14d58a7e9aeffbaadd6bd58f810
Author: Antoine Amarilli <a3nm@a3nm.net>
Date:   Sun, 12 Mar 2017 11:00:38 +0100
bigint
Diffstat:
| InfInt.h |  |  | 1370 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| calc.cpp |  |  | 40 | ++++++++++++++++++++++++---------------- | 
2 files changed, 1394 insertions(+), 16 deletions(-)
diff --git a/InfInt.h b/InfInt.h
@@ -0,0 +1,1370 @@
+// http://stackoverflow.com/a/6321977/414272
+#ifdef __GNUC__
+// Avoid tons of warnings with root code
+#pragma GCC system_header
+#endif
+/*
+ * 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 <iostream>
+#include <vector>
+#include <sstream>
+#include <iomanip>
+
+//#include <limits.h>
+//#include <stdlib.h>
+
+#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 <exception>
+#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;
+};
+
+InfIntException::InfIntException(const std::string& txt) throw () :
+std::exception(), txt(txt)
+{
+}
+
+InfIntException::~InfIntException() throw ()
+{
+}
+
+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<ELEM_TYPE>& 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<ELEM_TYPE> 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;
+}
+
+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
+    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<ELEM_TYPE>& 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
diff --git a/calc.cpp b/calc.cpp
@@ -1,3 +1,5 @@
+#include<limits.h>
+#include "InfInt.h"
 #include <cstdio>
 #include <deque>
 #include <cassert>
@@ -7,17 +9,17 @@ using namespace std;
 
 // http://math.stackexchange.com/q/2099305
 
-bool ok(deque<long long> &v) {
+bool ok(deque<InfInt> &v) {
   for (unsigned int i = 0; i < v.size(); i++)
     for (unsigned int j = i+1; j < v.size(); j++)
-      if ((v[j] - v[i]) % v[i])
+      if (v[i] % (v[j] - v[i]) > 0)
         return false;
   return true;
 }
 
 
 // http://stackoverflow.com/a/4229930
-long long gcd(long long a, long long b)
+InfInt gcd(InfInt a, InfInt b)
 {
     for (;;)
     {
@@ -29,28 +31,34 @@ long long gcd(long long a, long long b)
 }
 
 // http://stackoverflow.com/a/4229930
-long long lcm(long long a, long long b)
+InfInt lcm(InfInt a, InfInt b)
 {
-    long long temp = gcd(a, b);
+    InfInt temp = gcd(a, b);
 
-    return temp ? (a / temp * b) : 0;
+    return temp > 0 ? (a / temp * b) : 0;
 }
 
-int main() {
-  deque<long long> v;
+int main(int argc, char **argv) {
+  deque<InfInt> v;
   v.push_front(1);
-  while (true) {
+  assert(argc == 2);
+  for (int iter = 0; iter < atoi(argv[1]); iter++) {
+    InfInt mygcd = 1;
+    for (auto x: v)
+      mygcd = lcm(mygcd, x);
+    v.push_front(0);
+    for (auto &x : v)
+      x += mygcd;
     printf("%ld:", v.size());
     for (auto x : v)
-      printf(" %lld", x);
+      cout << " " << x;
     printf("\n");
-  // http://stackoverflow.com/a/4229930
-  long long gcd = std::accumulate(v.begin(), v.end(), 1, lcm);
-  v.push_front(0);
-  for (auto &x : v)
-    x += gcd;
+    if (!ok(v)) {
+      printf("PROBLEM\n");
+      return 1;
+    }
   }
-  assert(ok(v));
+  return 0;
 }