#include #include #include "bigint.h" //#include using namespace std; const int BASE = 10; // author: Owen Astrachan, // modified by Matt Evett to use STL vector, 9/1/00 // Modified by Matthew Evett to compile under Visual C++ v6.0, 9/20/01 // // BigInts are implemented using a vector to store // the digits of a BigInt // Currently a number like 1,234 is stored as the vector {4,3,2,1} // i.e., the least significant digit is the first digit in the vector // however all operations on digits should be done using private // helper functions: // // int getDigit(k) -- return k-th digit // void changeDigit(k,val) -- set k-th digit to val // void addSigDigit(val) -- add new most significant digit val // // by performing all ops in terms of these private functions we // make implementation changes simpler // // I/O operations are facilitated by the toString() member function // which converts a BigInt to its string (ASCII) representation static const int INITIAL_SIZE = 5; // default # digits, can change BigInt::BigInt() // postcodition: bigint initialized to 0 : myIsNegative(false), myDigits(INITIAL_SIZE,0), myNumDigits(1) { #ifdef DEBUG cerr << "default constructor called" << endl; #endif } BigInt::BigInt(int num) // postcondition: bigint initialized to num : myIsNegative(false), myDigits(INITIAL_SIZE,0), myNumDigits(0) { #ifdef DEBUG cerr << "int constructor called\t" << num << endl; #endif // check if num is negative, change state and num accordingly if (num < 0) { myIsNegative = true; num = -1 * num; } // handle least-significant digit of num (handles num == 0) addSigDigit(num % BASE); num = num / BASE; // handle remaining digits of num while (num != 0) { addSigDigit(num % BASE); num = num / BASE; } } BigInt::~BigInt() // postcondition: digit sequence cleared { #ifdef DEBUG cerr << "destructor called " << *this << endl; #endif myNumDigits = 0; } BigInt::BigInt(const BigInt & big) // copy constructor // postcondition: bigint initialized to big : myIsNegative(big.myIsNegative), myDigits(big.myDigits), myNumDigits(big.myNumDigits) { #ifdef DEBUG cerr << "\tcopy constructor called\t" << big << endl; #endif } BigInt::BigInt(const string & s) // precondition: s consists of digits only (no leading zeros) // postcondition: bigint initialized to integer represented by s : myIsNegative(false), myDigits(s.size(),0), myNumDigits(0) { #ifdef DEBUG cerr << "string constructor called\t" << s << endl; #endif int k; int limit = 0; if (s.size() == 0) { myDigits.resize(INITIAL_SIZE); addSigDigit(0); return; } if (s[0] == '-') { myIsNegative = true; limit = 1; } // start at least significant digit for(k=s.size() - 1; k >= limit; k--) { addSigDigit(s[k]-'0'); } Normalize(); } BigInt::operator int() // POST: returns an int equal in value to the BigInt, provided the // BigInt is small enough. Otherwise, the return value is undefined. { const int MAX_NUM_DIGITS = 6; // "small enough" will be 6 digits. int result=0; int k = (size() <= MAX_NUM_DIGITS ? size() : MAX_NUM_DIGITS)-1; for( ; k>=0; k--) { result = result * 10 + getDigit(k); } if (IsNeg()) result *= -1; return result; } BigInt & BigInt::operator = (const BigInt & big) // postcondition: bigint is equal to big { #ifdef DEBUG cerr << "operator = called\t" << big << endl; #endif if (this != &big) // watch for aliasing { myDigits = big.myDigits; myIsNegative = big.myIsNegative; myNumDigits = big.myNumDigits; } return *this; } BigInt & BigInt::operator -=(const BigInt & rhs) // precondition: bigint = a // postcondition: bigint = a - rhs { int diff; int borrow = 0; int k; int len = size(); if (this == &rhs) // subtracting self? { *this = 0; return *this; } // signs opposite? then x - (-y) = x + y if (IsNeg() != rhs.IsNeg()) { return operator +=(-1 * rhs); } // signs are the same, check which number is larger // since sign can change when subtracting // examples: 7 - 3 no sign change, 3 - 7 sign changes // -7 - (-3) no sign change, -3 -(-7) sign changes if (! IsNeg() && ((*this) < rhs) || IsNeg() && (*this) > rhs) { *this = rhs - *this; myIsNegative = ! myIsNegative; return *this; } for(k=0; k < len; k++) { diff = getDigit(k) - rhs.getDigit(k) - borrow; borrow = 0; if (diff < 0) { diff += 10; borrow = 1; } changeDigit(k,diff); } Normalize(); return *this; } BigInt & BigInt::operator +=(const BigInt & rhs) // precondition: bigint = a // postcondition: bigint = a + rhs, result returned { int sum; int carry = 0; int k; int len = size(); // length of larger addend if (this == &rhs) // to add self, multiply by 2 { return operator *=(2); } if (IsNeg() != rhs.IsNeg()) // signs not the same, subtract { *this -= (-1 * rhs); return *this; } // process both numbers until one is exhausted if (len < rhs.size()) { len = rhs.size(); } for(k=0; k < len; k++) { sum = getDigit(k) + rhs.getDigit(k) + carry; carry = sum / BASE; sum = sum % BASE; if (k < myNumDigits) { changeDigit(k,sum); } else { addSigDigit(sum); } } if (carry != 0) { addSigDigit(carry); } return *this; } BigInt operator +(const BigInt & lhs, const BigInt & rhs) // postcondition: return bigint == lhs + rhs { BigInt result(rhs); result += lhs; return result; } BigInt operator -(const BigInt & lhs, const BigInt & rhs) // postcondition: return bigint == lhs + rhs { BigInt result(lhs); result -= rhs; return result; } ostream & BigInt::Print(ostream & os) const // postcondition: BigInt inserted onto stream os { os << toString(); return os; } string BigInt::toString() const // postcondition: returns string equivalent of BigInt { int k; int len = size(); string s = ""; if (IsNeg()) { s = "-"; } for(k=len-1; k >= 0; k--) { s += char('0'+getDigit(k)); } return s; } ostream & operator <<(ostream & out, const BigInt & big) // postcondition: digits printed most-to-least significant { return big.Print(out); } istream & operator >> (istream & in, BigInt & big) // postcondition: big extracted from input // MUST be whitespace delimited { string s; in >> s; big = BigInt(s); return in; } bool operator == (const BigInt & lhs, const BigInt & rhs) { return lhs.equals(rhs); } bool BigInt::equals(const BigInt & rhs) const // postcondition: returns true if lhs == rhs, else return false { if (size() != rhs.size() || IsNeg() != rhs.IsNeg()) { return false; } // assert: same sign, same number of digits; int k; int len = size(); for(k=0; k < len; k++) { if (getDigit(k) != rhs.getDigit(k)) return false; } return true; } bool operator != (const BigInt & lhs, const BigInt & rhs) // postcondition: returns true if lhs != rhs, else returns false { return ! (lhs == rhs); } bool operator < (const BigInt & lhs, const BigInt & rhs) { return lhs.lessThan(rhs); } bool BigInt::lessThan(const BigInt & rhs) const // postcondition: return true if lhs < rhs, else returns false { // if signs aren't equal, lhs < rhs only if lhs is negative if (IsNeg() != rhs.IsNeg()) { return IsNeg(); } // if # digits aren't the same, lhs < rhs if lhs has fewer digits if (size() != rhs.size()) { return (size() < rhs.size() && ! IsNeg()) || (size() > rhs.size() && IsNeg()); } // assert: # digits same, signs the same int k; int len = size(); for(k=len-1; k >= 0; k--) { if (getDigit(k) < rhs.getDigit(k)) return ! IsNeg(); if (getDigit(k) > rhs.getDigit(k)) return IsNeg(); } return false; // lhs == rhs } bool operator > (const BigInt & lhs, const BigInt & rhs) // postcondition: return true if lhs > rhs, else returns false { return rhs < lhs; } bool operator <= (const BigInt & lhs, const BigInt & rhs) // postcondition: return true if lhs <= rhs, else returns false { return lhs == rhs || lhs < rhs; } bool operator >= (const BigInt & lhs, const BigInt & rhs) // postcondition: return true if lhs >= rhs, else returns false { return lhs == rhs || lhs > rhs; } BigInt & BigInt::operator %=(const BigInt & rhs) // postcondition: returns BigInt % rhs after modification { BigInt quotient,remainder; bool resultNegative = (IsNeg() != rhs.IsNeg()); myIsNegative = false; // DivideHelp does all the work if (rhs.IsNeg()) { DivideHelp(*this,-1 * rhs,quotient,remainder); } else { DivideHelp(*this,rhs,quotient,remainder); } *this = remainder; myIsNegative = resultNegative; return *this; } void BigInt::DivideHelp(const BigInt & lhs, const BigInt & rhs, BigInt & quotient, BigInt & remainder) // postcondition: quotient = lhs / rhs // remainder = lhs % rhs { if (lhs < rhs) // integer division yields 0 { // so avoid work and return quotient = 0; remainder = rhs; return; } else if (lhs == rhs) // again, avoid work in special case { quotient = 1; remainder = 0; return; } BigInt dividend(lhs); // make copies because of const-ness BigInt divisor(rhs); quotient = remainder = 0; int k,trial; int zeroCount = 0; // pad divisor with zeros until # of digits = dividend while (divisor.size() < dividend.size()) { divisor *= 10; zeroCount++; } // if we added one too many zeros chop one off if (divisor > dividend) { divisor /= 10; zeroCount--; } // algorithm: make a guess for how many times dividend part // goes into divisor, adjust the guess, subtract out and repeat int divisorSig = divisor.getDigit(divisor.size()-1); int dividendSig; BigInt hold; for(k=0; k <= zeroCount; k++) { dividendSig = dividend.getDigit(dividend.size()-1); trial = (dividendSig*10 + dividend.getDigit(dividend.size()-2)) /divisorSig; if (BASE <= trial) // stay within base { trial = BASE-1; } while ((hold = divisor * trial) > dividend) { trial--; } // accumulate quotient by adding digits to quotient // and chopping them off of divisor after adjusting dividend quotient *= 10; quotient += trial; dividend -= hold; divisor /= 10; divisorSig = divisor.getDigit(divisor.size()-1); } remainder = dividend; } BigInt & BigInt::operator /=(const BigInt & rhs) // postcondition: return BigInt / rhs after modification { BigInt quotient,remainder; bool resultNegative = (IsNeg() != rhs.IsNeg()); myIsNegative = false; // force myself positive // DivideHelp does all the work if (rhs.IsNeg()) { DivideHelp(*this,-1*rhs,quotient,remainder); } else { DivideHelp(*this,rhs,quotient,remainder); } *this = quotient; myIsNegative = resultNegative; Normalize(); return *this; } BigInt operator / (const BigInt & lhs, const BigInt & rhs) // postcondition: return lhs / rhs { BigInt result(lhs); result /= rhs; return result; } BigInt & BigInt::operator /=(int num) // precondition: 0 < num < BASE // postcondition: returns BigInt/num after modification { int carry = 0; int quotient; int k; int len = size(); if (num > BASE) // check precondition { return operator /= (BigInt(num)); } if (0 == num) // handle division by zero (not fully implemented) { myError = infinity; } else { for(k=len-1; k >= 0; k--) // once for each digit { quotient = (10*carry + getDigit(k)); carry = quotient % num; changeDigit(k, quotient / num); } } Normalize(); return *this; } void BigInt::Normalize() // postcondition: all leading zeros removed { int k; int len = size(); for(k=len-1; k >= 0; k--) // find a non-zero digit { if (getDigit(k) != 0) break; myNumDigits--; // "chop" off zeros } if (k < 0) // all zeros { myNumDigits = 1; myIsNegative = false; } } BigInt & BigInt::operator *=(int num) // precondition: 0 <= num < BASE // postcondition: returns num * value of BigInt after multiplication // note: works for values of num as long as num * one digit // does not result in overflow, precondition is overly // restrictive { int carry = 0; int product; // product of num and one digit + carry int k; int len = size(); if (0 == num) // treat zero as special case and stop { *this = 0; return *this; } if (BASE*BASE <= num) // handle pre-condition failure { *this *= BigInt(num); return *this; } // make sure that my sign is properly set: positive/negative myIsNegative = (IsNeg() && 0 < num) || (! IsNeg() && num < 0); if (1 == num) // treat one as special case, no work { return *this; } if (num < 0) // sign already changed, make positive { num = -1 * num; } for(k=0; k < len; k++) // once for each digit { product = num * getDigit(k) + carry; carry = product/BASE; changeDigit(k,product % BASE); } while (carry != 0) // carry all digits { addSigDigit(carry % BASE); carry /= BASE; } return *this; } BigInt operator *(const BigInt & a, int num) // postcondition: returns a * num { BigInt result(a); result *= num; return result; } BigInt operator /(const BigInt & a, int num) // postcondition: returns a / num { BigInt result(a); result /= num; return result; } BigInt operator %(const BigInt & lhs, const BigInt & rhs) // postcondition: returns lhs % rhs { BigInt result(lhs); result %= rhs; return result; } BigInt operator *(int num, const BigInt & a) // postcondition: returns num * a { BigInt result(a); result *= num; return result; } BigInt & BigInt::operator *=(const BigInt & big) // precondition: bigint = a // postcondition: bigint = a*big { // uses standard "grade school method" for multiplyin myIsNegative = (IsNeg() != big.IsNeg()); // is result negative? BigInt self(*this); // copy of self BigInt sum(0); // to accumulate sum int k; int len = big.size(); // # digits in multiplier for(k=0; k < len; k++) { sum += self * big.getDigit(k); // k-th digit * self self *= 10; // add a zero } *this = sum; return *this; } BigInt operator *(const BigInt & lhs, const BigInt & rhs) // postcondition: return bigint == lhs * rhs { BigInt result(lhs); result *= rhs; return result; } int BigInt::size() const // postcondition: returns # digits in BigInt { return myNumDigits; } int BigInt::getDigit(int k) const // precondition: 0 <= k < size() // postcondition: returns k-th digit // (returns 0 if precondition is false) { if (0 <= k && k < size()) { return myDigits[k] - '0'; } return 0; } void BigInt::changeDigit(int digit, int value) // precondition: 0 <= digit < size() // postcondition: digit-th digit changed to value { if (0 <= digit && digit < size()) { myDigits[digit] = char('0' + value); } else { cout << "error change " << digit << " " << myNumDigits << endl; } } void BigInt::addSigDigit(int value) // postcondition: value added to BigInt as most significant digit { if ((unsigned int)myNumDigits >= myDigits.size()) { myDigits.resize(myDigits.size() * 2); } myDigits[myNumDigits] = char('0' + value); myNumDigits++; } bool BigInt::IsNeg() const // postcondition: returns true iff BigInt is negative { return myIsNegative; }