Department of Computer Science | Institute of Theoretical Computer Science | CADMO

Theory of Combinatorial Algorithms

Prof. Emo Welzl and Prof. Bernd Gärtner

// Programm: integer.h // Implements integer numbers of arbitrary size #include #include #include #include #include #include namespace ifm { class integer { public: // constructors // ------------ integer(); // 0 integer(int i); // i integer(unsigned int i); // i integer(float f); // f integer(double d); // d // arithmetic operators (with the standard semantics) // -------------------------------------------------- integer operator-() const; integer& operator+=(const integer& x); integer& operator++(); integer operator++(int); integer& operator-=(const integer& x); integer& operator--(); integer operator--(int); integer& operator*=(const integer& x); integer& operator/=(const integer& x); integer& operator%=(const integer& x); // global friend operators // ----------------------- friend bool operator==(const integer& x, const integer& y); friend bool operator<(const integer& x, const integer& y); friend std::ostream& operator<<(std::ostream& o, const integer& x); friend std::istream& operator>>(std::istream& i, integer& x); private: // typedefs // -------- typedef std::deque Seq; typedef Seq::iterator It; typedef Seq::const_iterator Cit; typedef Seq::const_reverse_iterator Crit; // data members // ------------ // an integer is represented by a base, a sign, and a sequence // of digits in the given base. // the base must be a power of 10 to facilitate decimal input and output static const unsigned int power_ = 4; static const unsigned int base_ = 10000; // the sign bool sign_; // false <=> negative // the sequence Seq seq_; // represents the nonnegative number // // \sum_{i=0}^{seq_.size()-1} seq_[i]*base_^i // The number 0 is represented by a length-1-sequence with seq_[0] == 0 // private member functions // ------------------------ // PRE: seq_ is empty // POST: seq_ is initialized to represent the number i void init(unsigned int i); // POST: return value is true iff |*this| < |x|. bool abs_less(const integer& x) const; // POST: seq_ is updated to represent |*this| + |x| integer& add(const integer& x); // PRE: |x| <= |*this| // POST: seq_ is updated to represent |*this| - |x| integer& subtract(const integer& x); // PRE: *this != 0, x < base_ // POST: seq_ is updated to represent |*this| * |x| integer& mult(unsigned int x); // PRE: x != 0 // POST: *this is replaced by the remainder of the division // of *this by x; r holds the result of the division integer& div(const integer& x, integer& r); // PRE: s >= 0 // POST: *this is multiplied by base_^s integer& leftshift (int s); // POST: returns true true iff highest significand digit is nonzero bool is_normalized() const; // POST: returns true iff *this has value 0 bool is_zero() const; }; // global operators // ---------------- bool operator!=(const integer& x, const integer& y); bool operator<=(const integer& x, const integer& y); bool operator>(const integer& x, const integer& y); bool operator>=(const integer& x, const integer& y); integer operator+(const integer& x, const integer& y); integer operator-(const integer& x, const integer& y); integer operator*(const integer& x, const integer& y); integer operator/(const integer& x, const integer& y); integer operator%(const integer& x, const integer& y); // Implementation: public member functions // --------------------------------------- integer::integer() : sign_(true) { seq_.push_back(0); assert (is_normalized()); } void integer::init(unsigned int i) { assert (seq_.empty()); if (i == 0) seq_.push_back(0); else while (i > 0) { seq_.push_back(i % base_); i /= base_; } } integer::integer(int i) : sign_(i >= 0) { if (i < 0) i = -i; init(i); assert (is_normalized()); } integer::integer(unsigned int i) : sign_(true) { init(i); assert (is_normalized()); } integer::integer(float f) : sign_ (f >= 0) { int exp; float m = std::frexp (std::abs(f), &exp); // if |f| is nonzero, then |f| = 0.b_1b_2....b_24 * 2^exp // the integer resulting from this is obtained by moving the // comma exp places to the right (and forgetting about the digits // that may still follow) integer b; for (; exp > 0; --exp) { b *= 2; if (m >= 0.5f) { b += 1; m = 2.0f * (m - 0.5f); } else m = 2.0f * m; } seq_ = b.seq_; assert (is_normalized()); } integer::integer(double d) : sign_ (d >= 0) { int exp; double m = std::frexp (std::abs(d), &exp); // if |d| is nonzero, then |d| = 0.b_1b_2....b_53 * 2^exp // the integer resulting from this is obtained by moving the // comma exp places to the right (and forgetting about the digits // that may still follow) integer b; for (; exp > 0; --exp) { b *= 2; if (m >= 0.5) { b += 1; m = 2.0 * (m - 0.5); } else m = 2.0 * m; } seq_ = b.seq_; assert (is_normalized()); } bool integer::abs_less(const integer& x) const { if (seq_.size() < x.seq_.size()) return true; if (seq_.size() > x.seq_.size()) return false; Crit i = seq_.rbegin(); Crit j = x.seq_.rbegin(); for (; i != seq_.rend(); ++i, ++j) { if (*i < *j) return true; if (*i > *j) return false; } return false; } integer integer::operator-() const { integer x = *this; if (!is_zero()) x.sign_ = !sign_; return x; } integer& integer::operator+=(const integer& x) { if (sign_ == x.sign_) return add(x); if (!abs_less(x)) return subtract(x); integer z = x; z.subtract(*this); std::swap(z, *this); assert (is_normalized()); return *this; } integer& integer::operator++() { return *this += 1; } integer integer::operator++(int) { integer z = *this; *this += 1; return z; } integer& integer::operator-=(const integer& x) { if (sign_ != x.sign_) return add(x); if (!abs_less(x)) return subtract(x); integer z = x; z.subtract(*this); z.sign_ = !z.sign_; std::swap(z, *this); assert (is_normalized()); return *this; } integer& integer::operator--() { return *this -= 1; } integer integer::operator--(int) { integer z = *this; *this -= 1; return z; } integer& integer::operator*=(const integer& x) { if (is_zero()) return *this; integer r = 0; r.sign_ = (sign_ && x.sign_ || !sign_ && !x.sign_); for (Cit i = x.seq_.begin(); i != x.seq_.end(); ++i) { integer z = *this; z.mult(*i); r.add(z); seq_.push_front(0); } std::swap(r, *this); assert (is_normalized()); return *this; } integer& integer::operator/=(const integer& x) { assert(!x.is_zero()); integer r; div(x, r); std::swap(*this, r); assert (is_normalized()); return *this; } integer& integer::operator%=(const integer& x) { assert(!x.is_zero()); integer r; return div(x, r); } integer& integer::leftshift(int s) { assert (s >= 0); if (!is_zero()) for (int i=0; i= base_); if (carry) *i -= base_; } if (!carry) return *this; for (; i != seq_.end(); ++i) if (++*i == base_) *i = 0; else return *this; seq_.push_back(1); return *this; } integer& integer::subtract(const integer& x) { assert(!abs_less(x)); It i = seq_.begin(); bool carry = false; for (Cit j = x.seq_.begin(); j != x.seq_.end(); ++j, ++i) { assert(i != seq_.end()); *i += base_ - *j; if (carry) --*i; carry = (*i < base_); if (!carry) *i -= base_; } if (carry) { assert(i != seq_.end()); while (*i == 0) { *(i++) = base_ - 1; assert(i != seq_.end()); } --*i; } while (seq_.back() == 0) if (seq_.size() == 1) { sign_ = true; return *this; } else seq_.pop_back(); return *this; } integer& integer::mult(unsigned int x) { assert (!is_zero()); if (x == 0) return *this = 0; assert(x < base_); unsigned int carry = 0; for (It i = seq_.begin(); i != seq_.end(); ++i) { carry = *i * x + carry; *i = carry % base_; carry /= base_; } if (carry > 0) seq_.push_back(carry); return *this; } integer& integer::div(const integer& x, integer& r) { if (abs_less(x)) { r = 0; return *this; } // compute sign r.sign_ = (sign_ && x.sign_ || !sign_ && !x.sign_); r.seq_.clear(); // align divisor and initialize upper and lower bound for // binary search for multiplicator integer d = x; unsigned int sh = 1; unsigned int denh = d.seq_.back(); // highest digit of denominator while (d.seq_.size() < seq_.size()) { d.seq_.push_front(0); ++sh; } if (abs_less(d)) { d.seq_.pop_front(); --sh; } do { // binary search for multiplicator in suitable range [low,upp) // there are three cases: // (a) *this < d // (b) *this >= d and both have the same size // (c) *this >= d and *this has one digit more unsigned int numh; // leading 0, 1, or 2 digits of *this if (abs_less (d)) numh = 0; // case (a) else { numh = seq_.back(); // cases (b), (c) if (d.seq_.size() < seq_.size()) numh = numh * base_ + seq_[seq_.size()-2]; // case (c) } unsigned int low = numh / (denh + 1); unsigned int upp = numh / denh + 1; if (upp > base_) upp = base_; unsigned int t; integer dt; // Invariant: multiplicator in [low, upp) do { t = (low + upp) / 2; dt = d; dt.mult(t); if (abs_less(dt)) upp = t; else low = t; } while (upp - low > 1); // subtract multiple of divisor r.seq_.push_front(low); if (t != low) { dt = d; dt.mult(low); } subtract(dt); // cut off trailing zero in divisor d.seq_.pop_front(); } while (--sh > 0); assert (is_normalized()); return *this; } bool integer::is_normalized() const { return !seq_.empty() && (seq_.size()==1 || seq_[seq_.size()-1] != 0); } bool integer::is_zero() const { return seq_.size()==1 && seq_[0] == 0; } // global operators // ---------------- bool operator==(const integer& x, const integer& y) { return x.sign_ == y.sign_ && x.seq_ == y.seq_; } bool operator!=(const integer& x, const integer& y) { return !(x == y); } bool operator<(const integer& x, const integer& y) { if (x.sign_ != y.sign_) return x.sign_ < y.sign_; if (x.sign_) return x.abs_less(y); return y.abs_less(x); } bool operator<=(const integer& x, const integer& y) { return !(y < x); } bool operator> (const integer& x, const integer& y) { return y < x; } bool operator>=(const integer& x, const integer& y) { return !(x < y); } integer operator+(const integer& x, const integer& y) { integer z = x; z += y; return z; } integer operator-(const integer& x, const integer& y) { integer z = x; z -= y; return z; } integer operator*(const integer& x, const integer& y) { integer z = x; z *= y; return z; } integer operator/(const integer& x, const integer& y) { integer z = x; z /= y; return z; } integer operator%(const integer& x, const integer& y) { integer z = x; z %= y; return z; } std::ostream& operator<<(std::ostream& o, const integer& x) { if (!x.sign_) o << "-"; bool leading_zeros = true; // need to skip them for (integer::Crit i = x.seq_.rbegin(); i != x.seq_.rend(); ++i) { std::deque decimal_digits; unsigned int decimal_number = *i; for (unsigned int j=0; j>(std::istream& i, integer& x) { const char zero = '0'; char c; for (;;) { c = i.peek(); if (std::isspace(c)) i.get(); else break; // all whitespaces eaten } // check for sign bool negative = false; if (c == '+' || c == '-') { negative = (c == '-'); i.get(); c = i.peek(); } // now c is the first digit; we collect the digits // in bunchs of integer::power_ many if (std::isdigit(c)) { x = 0; unsigned int y = 0; unsigned int read = 0; unsigned int ten_to_read = 1; do { y = 10 * y + (c-zero); i.get(); ++read; ten_to_read *= 10; if (read == integer::power_) { x.leftshift(1); x.seq_[0] = y; y = 0; read = 0; ten_to_read = 1; } c = i.peek(); } while (std::isdigit(c)); // handle remaining y if (read > 0) x = ten_to_read * x + y; if (negative) x = -x; } return i; } } // namespace math