/*** * This software was written by Nils Maier. No copyright is claimed, and the * software is hereby placed in the public domain. * * In case this attempt to disclaim copyright and place the software in the * public domain is deemed null and void in your jurisdiction, then the * software is Copyright 2004,2013 Nils Maier and it is hereby released to the * general public under the following terms: * Redistribution and use in source and binary forms, with or without * modification, are permitted. * There's ABSOLUTELY NO WARRANTY, express or implied. */ #ifndef BIGNUM_H #define BIGNUM_H #include #include #include #include namespace bignum { template class ulong { public: typedef char char_t; typedef std::make_unsigned::type uchar_t; private: std::unique_ptr buf_; public: inline ulong() : buf_(new char_t[dim]()) {} inline ulong(size_t t) : buf_(new char_t[dim]()) { memcpy(buf_.get(), (char_t*)&t, sizeof(t)); } inline ulong(const ulong& rhs) : buf_(new char_t[dim]()) { memcpy(buf_.get(), rhs.buf_.get(), dim); } explicit inline ulong(const char_t* data, size_t size) : buf_(new char_t[dim]()) { if (size > dim) { throw std::bad_alloc(); } memcpy(buf_.get(), data, size); } virtual ~ulong() {} ulong& operator=(const ulong& rhs) { memcpy(buf_.get(), rhs.buf_.get(), dim); return *this; } bool operator==(const ulong& rhs) const { return memcmp(buf_.get(), rhs.buf_.get(), dim) == 0; } bool operator!=(const ulong& rhs) const { return memcmp(buf_.get(), rhs.buf_.get(), dim) != 0; } bool operator>(const ulong& rhs) const { const auto b1 = buf_.get(); const auto b2 = rhs.buf_.get(); for (ssize_t i = dim - 1; i >= 0; --i) { for (ssize_t j = 1; j >= 0; --j) { char_t t = ((uchar_t)(b1[i] << 4 * (1 - j))) >> 4; char_t r = ((uchar_t)(b2[i] << 4 * (1 - j))) >> 4; if (t != r) { return t > r; } } } return false; } bool operator>=(const ulong& rhs) const { return *this == rhs || *this > rhs; } bool operator<(const ulong& rhs) const { return !(*this >= rhs); } bool operator<=(const ulong& rhs) const { return *this == rhs || *this < rhs; } ulong operator+(const ulong& rhs) const { ulong rv; const auto b1 = buf_.get(); const auto b2 = rhs.buf_.get(); const auto rb = rv.buf_.get(); bool base = false; for (size_t i = 0; i < dim; ++i) { for (ssize_t j = 0; j < 2; ++j) { char_t t = ((uchar_t)(b1[i] << 4 * (1 - j))) >> 4; char_t r = ((uchar_t)(b2[i] << 4 * (1 - j))) >> 4; if (base) { t++; } if (r + t >= 16) { rb[i] += (t + r - 16) << j * 4; base = true; } else { rb[i] += (t + r) << j * 4; base = false; } } } return rv; } ulong& operator+=(const ulong& rhs) { *this = *this + rhs; return *this; } ulong& operator++() { *this = *this + 1; return *this; } ulong operator++(int) { ulong tmp = *this; *this = *this + 1; return tmp; } ulong operator-(const ulong& rhs) const { ulong rv; const auto b1 = buf_.get(); const auto b2 = rhs.buf_.get(); const auto rb = rv.buf_.get(); bool base = false; for (size_t i = 0; i < dim; ++i) { for (ssize_t j = 0; j < 2; ++j) { char_t t = ((uchar_t)(b1[i] << 4 * (1 - j))) >> 4; char_t r = ((uchar_t)(b2[i] << 4 * (1 - j))) >> 4; if (base) { t--; } if (t >= r) { rb[i] += (t - r) << j * 4; base = false; } else { rb[i] += (t + 16 - r) << j * 4; base = true; } } } return rv; } ulong& operator-=(const ulong& rhs) { *this = *this - rhs; return *this; } ulong& operator--() { *this = *this - 1; return *this; } ulong operator--(int) { ulong tmp = *this; *this = *this - 1; return tmp; } ulong operator*(const ulong& rhs) const { ulong c = rhs, rv; const ulong null; size_t cap = c.capacity(); while (c != null) { ulong tmp = *this; tmp.mul(cap - 1); rv += tmp; ulong diff(1); diff.mul(cap - 1); c -= diff; cap = c.capacity(); } return rv; } ulong& operator*=(const ulong& rhs) { *this = *this* rhs; return *this; } ulong operator/(const ulong& rhs) const { ulong quotient, remainder; div(rhs, quotient, remainder); return quotient; } ulong& operator/=(const ulong& rhs) { *this = *this / rhs; return *this; } ulong operator%(const ulong& rhs) const { ulong quotient, remainder; div(rhs, quotient, remainder); return remainder; } ulong& operator%=(const ulong& rhs) { *this = *this % rhs; return *this; } ulong mul_mod(const ulong& mul, const ulong& mod) const { if (capacity() + mul.capacity() <= dim) { return (*this * mul) % mod; } ulong et(buf_.get(), dim), emul(mul.buf_.get(), dim), emod(mod.buf_.get(), dim), erv = (et * emul) % emod; ulong rv; erv.binary(rv.buf_.get(), dim); return rv; } std::unique_ptr binary() const { ulong c = *this; std::unique_ptr rv; rv.swap(c.buf_); return rv; } void binary(char_t* buf, size_t len) const { memcpy(buf, buf_.get(), std::min(dim, len)); } size_t length() const { return dim; } private: size_t capacity() const { size_t rv = dim * 2; const auto b = buf_.get(); for (ssize_t i = dim - 1; i >= 0; --i) { char_t f = b[i] >> 4; char_t s = (b[i] << 4) >> 4; if (!f && !s) { rv -= 2; continue; } if (!f) { --rv; } return rv; } return rv; } void mul(size_t digits) { ulong tmp = *this; auto bt = tmp.buf_.get(); auto b = buf_.get(); memset(b, 0, dim); const size_t npar = digits % 2; const size_t d2 = digits / 2; for (size_t i = d2; i < dim; ++i) { for (size_t j = 0; j < 2; ++j) { char_t c = ((uchar_t)(bt[(dim - 1) - i] << 4 * (1 - j))) >> 4; char_t r = c << (npar * (1 - j) * 4 + (1 - npar) * j * 4); ssize_t idx = i - d2 - npar * j; if (idx >= 0) { b[(dim - 1) - idx] += r; } } } } void div(const ulong& d, ulong& q, ulong& r) const { ulong tmp = d; r = *this; q = 0; size_t cr = r.capacity(); const size_t cd = d.capacity(); while (cr > cd) { tmp = d; tmp.mul(cr - cd - 1); ulong qt(1); qt.mul(cr - cd - 1); ulong t = tmp; t.mul(1); if (r >= t) { tmp = t; qt.mul(1); } while (r >= tmp) { r -= tmp; q += qt; } cr = r.capacity(); } while (r >= d) { r -= d; ++q; } } }; } // namespace bignum #endif