My big integer class is finally finished. I have not tested it extensively yet. Anybody who is willing to find a tiny and clearly implemented big number class would find it worthy to have a try. Bug reports are always welcomed.
big_unsigned.hpp:
- /***************************************************************************
- * Copyright (C) 2008 by Liu Kaipeng *
- * LiuKaipeng at gmail dot com *
- ***************************************************************************/
- #ifndef BIG_UNSIGNED_H
- #define BIG_UNSIGNED_H
- #include <algorithm>
- #include <fstream>
- #include <limits>
- #include <sstream>
- #include <vector>
- /*
- * basic_big_unsigned - A implementation of big unsigned operations.
- *
- * This class is in fact a wrapper of the underlying container.
- */
- template<typename Type, typename Container = std::vector<Type> >
- struct basic_big_unsigned
- {
- typedef basic_big_unsigned self_type;
- typedef Container container_type;
- typedef typename container_type::value_type value_type;
- typedef typename container_type::size_type size_type;
- static int const repr_digits = std::numeric_limits<value_type>::digits;
- static value_type const repr_base = 1 << (repr_digits / 2);
- // Constructs.
- basic_big_unsigned() {}
- basic_big_unsigned(value_type other) {
- if (other) repr_.push_back(other), progress(0);
- }
- explicit basic_big_unsigned(container_type const& repr) : repr_(repr) {}
- // Conversions.
- value_type value() const {
- value_type u = value_type();
- for (size_type i = 0; i != repr_.size() && i != 2; ++i)
- u = u * repr_base + repr_[i];
- return u;
- }
- // Representations.
- container_type& repr() { return repr_; }
- container_type const& repr() const { return repr_; }
- bool is_zero() const { return repr_.empty(); }
- // Operations.
- self_type& operator+=(self_type const& other) {
- if (repr_.size() < other.repr_.size())
- repr_.resize(other.repr_.size());
- size_type i = 0;
- value_type carry = 0;
- for (; i != other.repr_.size(); ++i)
- if (overflow(repr_[i] += other.repr_[i] + carry))
- repr_[i] -= repr_base, carry = 1;
- else
- carry = 0;
- if (carry != 0)
- if (i == repr_.size()) repr_.push_back(carry);
- else repr_[i] += carry, progress(i);
- return *this;
- }
- self_type& operator+=(value_type other) {
- if (overflow(other))
- return *this += self_type(other);
- if (is_zero()) repr_.resize(1);
- repr_[0] += other;
- progress(0);
- return *this;
- }
- self_type operator+(self_type const& other) const {
- self_type tmp(*this); tmp += other; return tmp;
- }
- self_type operator+(value_type other) const {
- self_type tmp(*this); tmp += other; return tmp;
- }
- self_type& operator-=(self_type const& other) {
- size_type i = 0;
- for (; i != other.repr_.size(); ++i)
- if (underflow(repr_[i] -= other.repr_[i]))
- --repr_[i+1], repr_[i] += repr_base;
- degress(i);
- return *this;
- }
- self_type& operator-=(value_type other) {
- repr_[0] -= other;
- degress(0);
- return *this;
- }
- self_type operator-(self_type const& other) const {
- self_type tmp(*this); return tmp -= other;
- }
- self_type operator-(value_type other) const {
- self_type tmp(*this); return tmp -= other;
- }
- self_type& operator*=(self_type const& other) {
- return *this = *this * other;
- }
- self_type& operator*=(value_type other) {
- if (overflow(other))
- return *this *= self_type(other);
- value_type carry = 0;
- for (size_type i = 0; i != repr_.size(); ++i) {
- repr_[i] *= other;
- repr_[i] += carry;
- carry = repr_[i] / repr_base;
- repr_[i] -= carry * repr_base;
- }
- if (carry != 0) repr_.push_back(carry);
- return *this;
- }
- self_type operator*(self_type const& other) const {
- self_type tmp;
- if (!other.is_zero()) {
- tmp.repr_.resize(repr_.size() + other.repr_.size());
- for (size_t i = 0; i != repr_.size(); ++i)
- for (size_t j = 0; j != other.repr_.size(); ++j)
- if (overflow(tmp.repr_[i+j] += repr_[i] * other.repr_[j])) {
- tmp.repr_[i+j+1] += tmp.repr_[i+j] / repr_base;
- tmp.repr_[i+j] %= repr_base;
- }
- tmp.strip();
- }
- return tmp;
- }
- self_type operator*(value_type other) const {
- self_type tmp(*this); return tmp *= other;
- }
- self_type& operator/=(self_type const& other) {
- return *this = *this / other;
- }
- self_type& operator/=(value_type other) {
- value_type rem;
- div_with_rem(other, rem);
- return *this;
- }
- self_type operator/(self_type const& other) const {
- self_type tmp(*this);
- tmp = tmp.div_to_rem(other);
- return tmp;
- }
- self_type operator/(value_type other) const {
- self_type tmp(*this); return tmp /= other;
- }
- self_type& operator%=(self_type const& other) {
- div_to_rem(other);
- return *this;
- }
- self_type& operator%=(value_type other) {
- div_to_rem(self_type(other));
- return *this;
- }
- self_type operator%(self_type const& other) const {
- self_type tmp(*this); return tmp %= other;
- }
- value_type operator%(value_type other) const {
- value_type rem;
- self_type tmp(*this);
- tmp.div_with_rem(other, rem);
- return rem;
- }
- self_type& operator++() { return *this += 1; }
- self_type operator++(int) { self_type tmp(*this); return tmp += 1; }
- self_type& operator--() { return *this -= 1; }
- self_type operator--(int) { self_type tmp(*this); return tmp -= 1; }
- // Modular operations.
- self_type div_to_rem(self_type const& other) {
- self_type tmp;
- if (!is_zero() && repr_.size() >= other.repr_.size()) {
- tmp.repr_.resize(repr_.size() - other.repr_.size() + 1);
- for (size_type i = tmp.repr_.size(); i != 0; --i) {
- value_type high = repr_base - 1, low = 0,
- mul = (high + low + 1) >> 1;
- for (; high > low; mul = (high + low + 1) >> 1)
- if (less_mul_shift(other, mul, i-1)) high = mul - 1;
- else low = mul;
- sub_mul_shift(other, mul, i-1);
- tmp.repr_[i-1] = mul;
- }
- tmp.degress(tmp.repr_.size());
- }
- return tmp;
- }
- void div_with_rem(value_type other, value_type& rem) {
- rem = 0;
- for (size_type i = repr_.size(); i != 0; --i) {
- rem = rem * repr_base + repr_[i-1];
- repr_[i-1] = rem / other;
- rem -= repr_[i-1] * other;
- }
- strip();
- }
- private:
- static bool overflow(value_type u) { return u >= repr_base; }
- static bool underflow(value_type u) { return u - repr_base < -repr_base; }
- void strip() { for (; !is_zero() && repr_.back() == 0; ) repr_.pop_back(); }
- void progress(size_type pos) {
- value_type carry = 0;
- for (; pos != repr_.size() && overflow(repr_[pos] += carry); ++pos) {
- carry = repr_[pos] / repr_base;
- repr_[pos] -= carry * repr_base;
- }
- if (pos == repr_.size() && carry != 0) repr_.push_back(carry);
- }
- void degress(size_type pos) {
- value_type borrow = 0;
- for (; pos != repr_.size() && underflow(repr_[pos] -= borrow); ++pos) {
- borrow = (repr_base - 1 - repr_[pos]) / repr_base;
- repr_[pos] += borrow * repr_base;
- }
- if (pos == repr_.size() && borrow != 0) repr_.clear();
- strip();
- }
- bool less_mul_shift(self_type const& other, value_type mul, size_type shift)
- const {
- if (repr_.size() < other.repr_.size() + shift && mul)
- return true;
- value_type rem = 0, pro = 0;
- for (size_type i = repr_.size(), j = i - shift; i != shift; --i, --j) {
- rem = rem * repr_base + repr_[i-1];
- pro = other.repr_.size() < j ? 0 : other.repr_[j-1] * mul;
- if (rem < pro) return true;
- if ((rem -= pro) >= mul) return false;
- }
- return false;
- }
- void sub_mul_shift(self_type const& other, value_type mul, size_type shift) {
- size_type i = shift;
- for (; i != other.repr_.size() + shift; ++i) {
- if (underflow(repr_[i] -= other.repr_[i-shift] * mul)) {
- value_type borrow = (repr_base - 1 - repr_[i]) / repr_base;
- repr_[i+1] -= borrow;
- repr_[i] += borrow * repr_base;
- }
- }
- degress(i);
- }
- private:
- container_type repr_;
- };
- // Comparisons of basic_big_unsigned.
- template<typename Type, typename Container>
- inline bool operator==(basic_big_unsigned<Type, Container> const& x,
- basic_big_unsigned<Type, Container> const& y) {
- return x.repr() == y.repr();
- }
- template<typename Type, typename Container>
- inline bool operator!=(basic_big_unsigned<Type, Container> const& x,
- basic_big_unsigned<Type, Container> const& y) {
- return !(x == y);
- }
- template<typename Type, typename Container>
- inline bool operator<(basic_big_unsigned<Type, Container> const& x,
- basic_big_unsigned<Type, Container> const& y) {
- if (x.repr().size() != y.repr().size())
- return x.repr().size() < y.repr().size();
- else
- return std::lexicographical_compare(x.repr().rbegin(), x.repr().rend(),
- y.repr().rbegin(), y.repr().rend());
- }
- template<typename Type, typename Container>
- inline bool operator>(basic_big_unsigned<Type, Container> const& x,
- basic_big_unsigned<Type, Container> const& y) {
- return y < x;
- }
- template<typename Type, typename Container>
- inline bool operator<=(basic_big_unsigned<Type, Container> const& x,
- basic_big_unsigned<Type, Container> const& y) {
- return !(y < x);
- }
- template<typename Type, typename Container>
- inline bool operator>=(basic_big_unsigned<Type, Container> const& x,
- basic_big_unsigned<Type, Container> const& y) {
- return !(x < y);
- }
- // Input and output of basic_big_unsigned.
- template<typename Type, typename Container>
- std::istream& operator>>(std::istream& is,
- basic_big_unsigned<Type, Container>& u) {
- typedef basic_big_unsigned<Type, Container> big_unsigned_type;
- typedef typename big_unsigned_type::value_type value_type;
- value_type base = big_unsigned_type::repr_base;
- std::size_t digits = 4;
- std::ios_base::fmtflags flags = is.flags();
- if (flags & std::ios_base::dec) base = 10000;
- if (flags & std::ios_base::oct) digits = 5;
- u.repr().clear();
- value_type val;
- std::stringstream ss;
- ss.flags(is.flags());
- for (char buf[5]; is.read(buf, digits) && ss.write(buf, is.gcount()); )
- ss >> val, u *= base, u += val;
- return is;
- }
- template<typename Type, typename Container>
- std::ostream& operator<<(std::ostream& os,
- basic_big_unsigned<Type, Container> const& u) {
- typedef basic_big_unsigned<Type, Container> big_unsigned_type;
- typedef typename big_unsigned_type::value_type value_type;
- if (u.is_zero()) return os << "0";
- value_type base = big_unsigned_type::repr_base;
- std::size_t digits = 4;
- std::ios_base::fmtflags flags = os.flags();
- if (flags & std::ios_base::dec) base = 10000;
- if (flags & std::ios_base::oct) digits = 5;
- value_type val;
- std::vector<value_type> vals;
- for (big_unsigned_type tmp(u); !tmp.is_zero(); vals.push_back(val))
- tmp.div_with_rem(base, val);
- os << vals.back();
- if (vals.size() > 1) {
- char f = os.fill('0');
- for (std::size_t i = vals.size() - 1; i != 0; --i)
- os.width(digits), os << vals[i-1];
- os.fill(f);
- }
- return os;
- }
- typedef basic_big_unsigned<unsigned> big_unsigned;
- #endif /* BIG_UNSIGNED_H */