---
tags: codebook
---
{%hackmd theme-dark %}
# unlimited_int
```cpp=
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<sstream>
using namespace std;
constexpr int limit = 1e9;
constexpr int limit_digit = log10(limit);
struct unlimited_int {
vector<int> data; bool negative;
operator bool() {
return data.size() > 1 && !data.back();
}
void swap(unlimited_int& x) {
auto datat = move(x.data);
auto negativet = move(x.negative);
x.data = data, x.negative = negative;
data = datat, negative = negativet;
}
unlimited_int& shrink() {
while (data.size() > 1 && !data.back())
data.pop_back();
long long n = 0;
for (size_t i = 0; i != data.size(); i++) {
data[i] = (n += data[i] + limit) % limit, n /= limit, n--;
}
return *this;
}
unlimited_int(const int& x): data(1, abs(x)), negative(x > 0) {}
unlimited_int(const string& s = ""): negative(!s.empty() && s.front() == '-') {
for (int i = s.size(); i >= limit_digit + negative; i -= limit_digit)
data.push_back(atoi(string(s.begin() + i - limit_digit, s.begin() + i).data()));
data.push_back(
atoi((string(s.begin() + negative, s.begin() + negative + (s.size() - negative) % limit_digit)).data()));
shrink();
}
};
istream& operator>>(istream& is, unlimited_int& x) {
string s; is >> s; size_t n = 0;
while (n < s.size() && !(s[n] == '-' || isdigit(s[n]))) n++;
unlimited_int(s.substr(n)).swap(x); return is;
}
string utos(const unlimited_int& x) {
string str, tmp; char c[limit_digit + 1]; size_t n;
for (auto i = x.data.crbegin() + 1; i < x.data.crend(); i++)
n = sprintf(c, "%d", *i), str += string(limit_digit - n, '0') + string(c, n);
n = sprintf(c, "%d", x.data.back());
return string(x.negative, '-') + string(c, n) + str;
}
unlimited_int operator<<(const unlimited_int& a, size_t b) {
unlimited_int c; c.data.assign(b, 0);
c.data.insert(c.data.end(), a.data.cbegin(), a.data.cend());
return c.shrink();
}
ostream& operator<<(ostream& os, const unlimited_int& x) {
string str, tmp; char c[limit_digit + 1];
size_t n = sprintf(c, "%d", x.data.back());
os << string(x.negative, '-') << string(c, n);
for (auto i = x.data.crbegin() + 1; i < x.data.crend(); i++)
n = sprintf(c, "%d", *i), os << string(limit_digit - n, '0') + string(c, n);
return os;
}
unlimited_int operator-(unlimited_int a) {
a.negative = !a.negative; return a;
}
unlimited_int uabs(unlimited_int x) {
x.negative = false; return x;
}
bool operator==(const unlimited_int& a, const unlimited_int& b) {
if ((a.negative ^ b.negative) | (a.data.size() ^ b.data.size()))
return false;
for (size_t i = 0; i != a.data.size(); i++)
if (a.data[i] ^ b.data[i])
return false;
return true;
}
bool operator<(const unlimited_int& a, const unlimited_int& b) {
if (a.negative != b.negative)
return a.negative > b.negative;
if (a.data.size() != b.data.size())
return a.negative ^ (a.data.size() < b.data.size());
for (size_t i = a.data.size() - 1; i >= 0; i--)
if (a.data[i] != b.data[i])
return a.negative ^ (a.data[i] < b.data[i]);
return false;
}
bool operator!=(const unlimited_int& a, const unlimited_int& b) {
return !(a == b);
}
bool operator<=(const unlimited_int& a, const unlimited_int& b) {
return (a == b) | (a < b);
}
bool operator>(const unlimited_int& a, const unlimited_int& b) {
return !(a <= b);
}
bool operator>=(const unlimited_int& a, const unlimited_int& b) {
return !(a < b);
}
unlimited_int operator+(const unlimited_int& a, const unlimited_int& b) {
bool cmp = uabs(a) > uabs(b);
const auto& ra(cmp ? a : b);
const auto& rb(cmp ? b : a);
long long n = 0; unlimited_int c;
c.data.assign(max(ra.data.size(), rb.data.size()) + 1, 0);
for (size_t i = 0; i != rb.data.size(); i++) {
if (a.negative ^ b.negative)
c.data[i] = (n += ra.data[i] - rb.data[i]) % limit, n /= limit;
else
c.data[i] = (n += ra.data[i] + rb.data[i]) % limit, n /= limit;
}
for (size_t i = rb.data.size(); i < ra.data.size(); i++)
c.data[i] = (n += ra.data.at(i)) % limit, n /= limit;
c.data.back() = n;
c.negative = ra.negative;
return c.shrink();
}
unlimited_int operator-(const unlimited_int& a, const unlimited_int& b) {
return a + (-b);
}
size_t hibit(size_t n) {
n |= (n >> 1);
n |= (n >> 2);
n |= (n >> 4);
n |= (n >> 8);
n |= (n >> 16);
return n - (n >> 1);
}
unlimited_int karatsuba(const unlimited_int& a, const unlimited_int& b) {
if (a.data.size() <= 3 || b.data.size() <= 3) {
unlimited_int c; long long n = 0;
c.data.resize(a.data.size() + b.data.size(), 0);
for (size_t i = 0, j; i != a.data.size(); i++) {
for (j = 0; j != b.data.size(); j++)
c.data[i + j] = (n += c.data[i + j] + static_cast<long long>(a.data[i]) * b.data[j]) % limit, n /= limit;
while (n) c.data[i + j] = (n += c.data[i + j]) % limit, n /= limit;
}
return c.shrink();
}
unlimited_int ca(a), cb(b);
size_t m = max(a.data.size(), b.data.size());
m = hibit(m) << bool(m ^ hibit(m));
ca.data.resize(m), cb.data.resize(m), m >>= 1;
unlimited_int a1, a2, b1, b2, c;
a1.data.assign(ca.data.begin(), ca.data.begin() + m);
a2.data.assign(ca.data.begin() + m, ca.data.end());
b1.data.assign(cb.data.begin(), cb.data.begin() + m);
b2.data.assign(cb.data.begin() + m, cb.data.end());
unlimited_int z1 = karatsuba(a1, b1);
unlimited_int z2 = karatsuba(a1 + a2, b2 + b1);
unlimited_int z3 = karatsuba(a2, b2);
return ((z3 << 2 * m) + ((z2 - z3 - z1) << m) + z1).shrink();
}
unlimited_int operator*(const unlimited_int& a, const unlimited_int& b) {
return karatsuba(a, b).shrink();
}
unlimited_int& operator*=(unlimited_int& a, const unlimited_int& b) {
return a = a * b;
}
unlimited_int pow(unlimited_int a, unsigned long long b) {
unlimited_int ans(1);
for (; b; a *= a, b >>= 1)
if (b & 1) ans *= a;
return ans;
}
int main() {
unlimited_int a, b;
// unsigned long long b;
while (cin >> a >> b)
cout << a * b << endl;
return 0;
}
```