// Returns a / b. Integer Integer::divide(Integer& a, Integer& b) const { Integer q, row; int asign = a.sign(); int bsign = b.sign(); int i; q.set_size(a.size()); a.set_sign(PLUS); b.set_sign(PLUS); for (i = a.size() - 1; i >= 0; i--) { row <<= 1; row[0] = a[i]; q[i] = 0; while (row >= b) { q[i]++; row -= b; } } q.adjust(); if (q == ZERO) q.set_sign(PLUS); else q.set_sign(asign * bsign); a.set_sign(asign); b.set_sign(bsign); return q; }
// Compare a with b, possible results are: // 0 : a and b are equals. // PLUS(1) : b > a // MINUS(-1) : b < a int Integer::compare(const Integer& a, const Integer& b) const { if (a.sign() == MINUS && b.sign() == PLUS) { return PLUS; } if (a.sign() == PLUS && b.sign() == MINUS) { return MINUS; } if (b.size() > a.size()) { return PLUS * a.sign(); } if (a.size() > b.size()) { return MINUS * a.sign(); } for (int i = a.size() - 1; i >= 0; i--) { if (a[i] > b[i]) { return MINUS * a.sign(); } if (b[i] > a[i]) { return PLUS * a.sign(); } } return 0; }
// Return a * b. This method is known as "Long Multiplication". // Complexity: O(n^2) Integer Integer::multiply(Integer& a, Integer& b) const { Integer ans; unsigned int i, j, k, n, carry_mult, carry_sum; for (i = 0; i < a.size(); i++) { carry_mult = carry_sum = 0; k = i; // Shifting for (j = 0; j < b.size(); j++) { n = a[i] * b[j] + carry_mult; carry_mult = n / BASE; n = ans[k] + n % BASE + carry_sum; carry_sum = n / BASE; ans[k] = n % BASE; k++; } if (carry_sum > 0 || carry_mult > 0) { ans[k++] = carry_sum + carry_mult; } ans.set_size(k); } if (ans == ZERO) ans.set_sign(PLUS); else ans.set_sign(a.sign() * b.sign()); return ans; }
Integer Integer::add_if_different_sign(const Integer &arg) const { if (abs(*this) == abs(arg)) return 0; Integer res; // atgaa -> abs (of) this (is) greater (than) abs (of) arg: 1 or -1 int atgaa = (abs(*this) > abs(arg)) * 2 - 1; do res.push_back(0); while (res.size() < std::max(size(), arg.size())); for (size_t i = 0; i < res.size(); ++i) { if (i < size()) res[i] += (*this)[i] * atgaa; if (i < arg.size()) res[i] += arg[i] * -atgaa; if (res[i] < 0) { res[i] += 10; res[i + 1]--; } } res.sign = (atgaa == 1 ? sign : arg.sign); while (!res[-1]) res.vec->pop_back(); return res; }
// Returns n >> p => n / 10^p. Integer Integer::right_shift(const Integer& n, long long p) const { Integer ans = n; if (ans == ZERO) { return ZERO; } for (unsigned int i = 0; i + p < ans.size(); i++) { ans[i] = ans[i + p]; } ans.set_size(ans.size() - p); return ans; }
// Calculate a + b and store the result in c. a and b are positive. void Integer::add(Integer& a, Integer& b, Integer& c) const { int carry = 0, n, i; int max = std::max(a.size(), b.size()); for (i = 0; i < max; i++) { n = a[i] + b[i] + carry; carry = n / BASE; c[i] = n % BASE; } if (carry > 0) { c[i++] = carry; } c.set_size(i); c.adjust(); }
// Returns n << p => n * 10^p. Integer Integer::left_shift(const Integer& n, long long p) const { Integer ans = n; if (ans == ZERO) { return ZERO; } for (int i = ans.size() - 1; i >= 0; i--) { ans[i + p] = ans[i]; } for (int i = 0; i < p; i++) { ans[i] = 0; } ans.set_size(ans.size() + p); return ans; }
// Returns (*this)^2. Integer Integer::square() { if (size() < MIN_KARATSUBA_SQUARE) { return multiply(*this, *this); } unsigned int i, half = (size() + 1) / 2; Integer a0, a1; split(*this, a0, a1, half); Integer square0 = a0.square(); Integer square1 = a1.square(); Integer ans; ans.set_size(size() + size()); for (i = 0; i < 2 * half; i++) { ans[i] = square0[i]; } for (i = 2 * half; i < ans.size(); i++) { ans[i] = square1[i - 2 * half]; } Integer square2 = (a0 + a1).square(); square2 -= square0; square2 -= square1; int n, carry = 0; for (i = half; i < ans.size(); i++) { n = ans[i] + square2[i - half] + carry; carry = n / BASE; ans[i] = n % BASE; } if (carry > 0) { ans[i++] = carry; } ans.adjust(); return ans; }
// Returns a new integer c = a + b Integer Integer::add(Integer &a, Integer &b) const { Integer c; int carry = 0, i; if (a.sign() == b.sign()) { c.set_sign(a.sign()); } else { if (a.sign() == MINUS) { a.set_sign(PLUS); c = subtract(b, a); a.set_sign(MINUS); } else { b.set_sign(PLUS); c = subtract(a, b); b.set_sign(MINUS); } return c; } int max = std::max(a.size(), b.size()); int n; for (i = 0; i < max; i++) { n = carry + a[i] + b[i]; c[i] = n % BASE; carry = n / BASE; } if (carry > 0) { c[i++] = carry; } c.set_size(i); c.adjust(); return c; }
// a and b are positive integers. Integer Integer::subtract(Integer& a, Integer& b) const { Integer ans; int borrow = 0, n; // Three special cases: // a - (-b) == a + b // -a - b == -a + (-b) // -a - (-b) == -a + b if (a.sign() == MINUS || b.sign() == MINUS) { b.set_sign(MINUS * b.sign()); ans = add(a, b); b.set_sign(MINUS * b.sign()); return ans; } if (a == b) { return ZERO; } if (a < b) { ans = subtract(b, a); ans.set_sign(MINUS); return ans; } unsigned int i; for (i = 0; i < a.size(); i++) { n = a[i] - b[i] - borrow; borrow = (n < 0) ? 1 : 0; if (n < 0) { n += BASE; } ans[i] = n; } ans.set_size(i); ans.adjust(); ans.set_sign(PLUS); return ans; }
// a and b are positive and a > b void Integer::subtract(Integer& a, Integer& b, Integer& c) const { int n, borrow = 0; unsigned int i; for (i = 0; i < a.size(); i++) { n = a[i] - b[i] - borrow; if (n < 0) { n += BASE; } borrow = (n < 0) ? 1 : 0; c[i] = n; } c.set_size(i); c.adjust(); c.set_sign(PLUS); }
// Return a * b. This method is known as Karatsuba algorithm. // Complexity: O(n^(log_2 3)) ~ O(n^1.585) // References: // [1] Algorithms and Data Structures: The Basic Toolbox, Kurt Hehlhorn, et al. // [2] en.wikipedia.org/wiki/Karatsuba_algorithm Integer Integer::karatsuba(Integer& a, Integer& b) { unsigned int alength = a.size(); unsigned int blength = b.size(); unsigned int half = (max(alength, blength) + 1) / 2; // For small numbers the long multiplication is more efficient if (max(alength, blength) < MIN_KARATSUBA) { return multiply(a, b); } Integer a0, a1, b0, b1; split(a, a0, a1, half); split(b, b0, b1, half); Integer p1 = karatsuba(a1, b1); Integer p0 = karatsuba(a0, b0); Integer sum1, sum2; add(a0, a1, sum1); add(b0, b1, sum2); Integer p2 = karatsuba(sum1, sum2); unsigned int i; int n, carry = 0; Integer ans; ans.set_size(alength + blength); for (i = 0; i < 2 * half; i++) { ans[i] = p0[i]; } for (i = 2 * half; i < ans.size(); i++) { ans[i] = p1[i - 2 * half]; } // Subtracts for (i = 0; i < p2.size(); i++) { n = p2[i] - p0[i] - carry; carry = (n < 0) ? 1 : 0; if (n < 0) { n += BASE; } p2[i] = n; } p2.adjust(); for (i = 0; i < p2.size(); i++) { n = p2[i] - p1[i] - carry; carry = (n < 0) ? 1 : 0; if (n < 0) { n += BASE; } p2[i] = n; } p2.adjust(); for (i = half; i < ans.size(); i++) { n = ans[i] + p2[i - half] + carry; carry = n / BASE; ans[i] = n % BASE; } ans.adjust(); return ans; }