#ifndef BIGINT_HPP #define BIGINT_HPP #include #include #include #include using std::size_t; inline std::uint32_t u(uint64_t a){ return (uint32_t)(a >> 32); } inline std::uint32_t l(uint64_t a){ return (uint32_t)(a & 0x00000000FFFFFFFF); } template inline int signum(T t){ if(t > 0)return 1; if(t < 0)return -1; return 0; } struct BigInt{ using uint64_t = std::uint64_t; using uint32_t = std::uint32_t; int signum; std::deque data; inline BigInt(size_t size, bool dummy) : data(size, 0){ } inline BigInt(unsigned int n) : data(1, 0){ data[0] = n; } inline BigInt(unsigned long long n) : data(2, 0){ data[1] = l(n); data[0] = u(n); } inline BigInt(int n) : data(1, 0){ data[0] = std::abs(n); signum = ::signum(n); } inline BigInt(long long n) : data(2, 0){ data[1] = l(std::abs(n)); data[0] = u(std::abs(n)); signum = ::signum(n); } inline uint64_t mod(uint64_t o){ uint64_t carry = 0; for(size_t i = 0;i < data.size();i++){ carry = ((carry << 32) + data[i]) % o; } return carry; } inline BigInt div(uint32_t o){ uint64_t carry = 0; BigInt ret = *this; for(size_t i = 0;i < data.size();i++){ ret.data[i] = (data[i] + (carry << 32)) / o; carry = (data[i] + (carry << 32)) % o; } return ret; } inline BigInt add(const BigInt& other){ BigInt ret((size_t)std::max((size_t)data.size(), (size_t)other.data.size()), false); uint64_t carry = 0; for(size_t s = 0;s < std::max(data.size(), other.data.size());s++){ uint64_t s1 = (s >= data.size() ? 0 : data[data.size() - s - 1]); uint64_t s2 = (s >= other.size() ? 0 : other.data[other.size() - s - 1]); uint64_t sum = s1 + s2 + carry; ret.data[ret.size() - s - 1] = l(sum); carry = u(sum); } return ret; } void trim(){ while(!(data[1] | data[0]))data.pop_front(); } inline BigInt mult(const BigInt& other){ std::deque> matrix(size(), std::deque(other.size() + 1, 0)); uint64_t carry = 0; BigInt ret(size() + other.size(), false); for(size_t i = 0;i < size();i++){ carry = 0; for(size_t ih = 0;ih < other.size();ih++){ uint64_t res = data[size() - i - 1] * other.data[other.size() - ih - 1]; res += carry; matrix[i][ih] = l(res); carry = u(res); } } carry = 0; if(false) for(size_t i = 0;i < matrix.size();i++){ for(size_t ih = 0;ih < matrix.size();ih++){ std::cout << matrix[i][ih] << " "; } std::cout << std::endl; } for(size_t column = 0;column < (matrix.size() + other.size());column++){ uint64_t accum = 0; for(size_t row = 0;row < matrix.size();row++){ if(row > column)goto end; else if(column - row < matrix[row].size()){ accum += matrix[row][column - row]; } } end: accum += carry; carry = u(accum); ret.data[ret.size() - column - 1] = l(accum); } ret.trim(); return ret; } inline BigInt& bitshiftLeft(int c){ if(c < 0)return bitshiftRight(-c); unsigned int jump = c / 32; unsigned int sh = c % 32; for(int i = 0;i < size() - jump;i++){ data[i] = l(data[i + jump] << sh); if(i < size() - jump - 1){ data[i] |= data[i + jump + 1] >> (32 - sh); } } //TODO: Set remaining bits to 0 return *this; } inline BigInt& bitshiftRight(int c){ if(c < 0)return bitshiftLeft(-c); unsigned int jump = c / 32; unsigned int sh = c % 32; for(unsigned int i = size() - 1;i >= jump;i--){ data[i] = data[i - jump] >> sh; if(i > jump){ data[i] |= l(data[i - jump - 1] << (32 - sh)); } } //TODO: Set remaining bits to 0 return *this; } inline BigInt& chunkshiftLeft(int c){ if(c < 0)return chunkshiftRight(-c); for(int i = 0;i < size() - c;i++){ data[i] = data[i] + c; } for(int i = size() - c;i < size();i++){ data[i] = 0; } return this; } inline BigInt& chunkshiftRight(int c){ if(c < 0)return chunkshiftLeft(-c); } inline size_t size()const{ return data.size(); } inline bool isZero(){ for(uint64_t d : data){ if(d)return false; } return true; } inline std::string rawString(){ std::string a = ""; for(uint64_t d : data){ a += (std::to_string(d) + "|"); } return a; } inline std::string toString(){ std::string a = ""; BigInt dec(*this); while(!dec.isZero()){ a = std::to_string(dec.mod(10)) + a; dec = dec.div(10); } return a; } }; #endif