| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- /***
- * 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 <cstring>
- #include <algorithm>
- #include <memory>
- #include <stdint.h>
- namespace bignum {
- template <size_t dim> class ulong {
- public:
- typedef char char_t;
- typedef std::make_unsigned<char_t>::type uchar_t;
- private:
- std::unique_ptr<char_t[]> 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<dim>& 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<dim>& operator=(const ulong<dim>& rhs)
- {
- memcpy(buf_.get(), rhs.buf_.get(), dim);
- return *this;
- }
- bool operator==(const ulong<dim>& rhs) const
- {
- return memcmp(buf_.get(), rhs.buf_.get(), dim) == 0;
- }
- bool operator!=(const ulong<dim>& rhs) const
- {
- return memcmp(buf_.get(), rhs.buf_.get(), dim) != 0;
- }
- bool operator>(const ulong<dim>& 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<dim>& rhs) const
- {
- return *this == rhs || *this > rhs;
- }
- bool operator<(const ulong<dim>& rhs) const { return !(*this >= rhs); }
- bool operator<=(const ulong<dim>& rhs) const
- {
- return *this == rhs || *this < rhs;
- }
- ulong<dim> operator+(const ulong<dim>& rhs) const
- {
- ulong<dim> 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<dim>& operator+=(const ulong<dim>& rhs)
- {
- *this = *this + rhs;
- return *this;
- }
- ulong<dim>& operator++()
- {
- *this = *this + 1;
- return *this;
- }
- ulong<dim> operator++(int)
- {
- ulong<dim> tmp = *this;
- *this = *this + 1;
- return tmp;
- }
- ulong<dim> operator-(const ulong<dim>& rhs) const
- {
- ulong<dim> 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<dim>& operator-=(const ulong<dim>& rhs)
- {
- *this = *this - rhs;
- return *this;
- }
- ulong<dim>& operator--()
- {
- *this = *this - 1;
- return *this;
- }
- ulong<dim> operator--(int)
- {
- ulong<dim> tmp = *this;
- *this = *this - 1;
- return tmp;
- }
- ulong<dim> operator*(const ulong<dim>& rhs) const
- {
- ulong<dim> c = rhs, rv;
- const ulong<dim> null;
- size_t cap = c.capacity();
- while (c != null) {
- ulong<dim> tmp = *this;
- tmp.mul(cap - 1);
- rv += tmp;
- ulong<dim> diff(1);
- diff.mul(cap - 1);
- c -= diff;
- cap = c.capacity();
- }
- return rv;
- }
- ulong<dim>& operator*=(const ulong<dim>& rhs)
- {
- *this = *this* rhs;
- return *this;
- }
- ulong<dim> operator/(const ulong<dim>& rhs) const
- {
- ulong<dim> quotient, remainder;
- div(rhs, quotient, remainder);
- return quotient;
- }
- ulong<dim>& operator/=(const ulong<dim>& rhs)
- {
- *this = *this / rhs;
- return *this;
- }
- ulong<dim> operator%(const ulong<dim>& rhs) const
- {
- ulong<dim> quotient, remainder;
- div(rhs, quotient, remainder);
- return remainder;
- }
- ulong<dim>& operator%=(const ulong<dim>& rhs)
- {
- *this = *this % rhs;
- return *this;
- }
- ulong<dim> mul_mod(const ulong<dim>& mul, const ulong<dim>& mod) const
- {
- if (capacity() + mul.capacity() <= dim) {
- return (*this * mul) % mod;
- }
- ulong<dim * 2> et(buf_.get(), dim), emul(mul.buf_.get(), dim),
- emod(mod.buf_.get(), dim), erv = (et * emul) % emod;
- ulong<dim> rv;
- erv.binary(rv.buf_.get(), dim);
- return rv;
- }
- std::unique_ptr<char_t[]> binary() const
- {
- ulong<dim> c = *this;
- std::unique_ptr<char_t[]> 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<dim> 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<dim>& d, ulong<dim>& q, ulong<dim>& r) const
- {
- ulong<dim> 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<dim> qt(1);
- qt.mul(cr - cd - 1);
- ulong<dim> 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
|