您的位置:首页 > 其它

I Love Big Numbers!

2008-12-03 01:26 288 查看
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 */
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: