---
# System prepended metadata

title: unlimited_int
tags: [codebook]

---

---
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;
}
```