Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

bigint2.C

Go to the documentation of this file.
00001 #include <iostream.h>
00002 #include <stdlib.h>
00003 #include <ctype.h>
00004 #include <limits.h> 
00005 #include "bigint.h"
00006 #include "apvector.h"
00007 
00008 const int BASE = 10;
00009 
00010 // author: Owen Astrachan
00011 //
00012 //***************************************************************
00013 // modified January 9, 1998, by Chris Nevison
00014 //
00015 // modification repalces the operators +=, -=, and *= with the
00016 // early versions which do not protect against aliasing, as found
00017 // in the file bigalia2.cpp and in an appendix of the case study.
00018 //***************************************************************
00019 //
00020 // BigInts are implemented using a Vector<char> to store
00021 // the digits of a BigInt
00022 // Currently a number like 5,879 is stored as the vector {9,7,8,5}
00023 // i.e., the least significant digit is the first digit in the vector;
00024 // for example, GetDigit(0) returns 9 and getDigit(3) returns 5.
00025 // All operations on digits should be done using private
00026 // helper functions:
00027 //
00028 // int  GetDigit(k)        -- return k-th digit
00029 // void ChangeDigit(k,val) -- set k-th digit to val
00030 // void AddSigDigit(val)   -- add new most significant digit val
00031 //
00032 // by performing all ops in terms of these private functions we
00033 // make implementation changes simpler
00034 // 
00035 // I/O operations are facilitated by the ToString() member function
00036 // which converts a BigInt to its string (ASCII) representation
00037 
00038 
00039 BigInt::BigInt()
00040 // postcondition: bigint initialized to 0
00041    : mySign(positive),
00042      myDigits(1,'0'),
00043      myNumDigits(1)
00044 {
00045         // all fields initialized in initializer list
00046 }
00047 
00048 BigInt::BigInt(int num)
00049 // postcondition: bigint initialized to num
00050    : mySign(positive),
00051      myDigits(1,'0'),
00052      myNumDigits(0)
00053 { 
00054     // check if num is negative, change state and num accordingly
00055     
00056     if (num < 0)
00057     {
00058         mySign = negative;
00059         num = -1 * num;
00060     }
00061 
00062     // handle least-significant digit of num (handles num == 0)
00063     
00064     AddSigDigit(num % BASE);
00065     num = num / BASE;
00066     
00067     // handle remaining digits of num
00068     
00069     while (num != 0)
00070     {
00071         AddSigDigit(num % BASE);
00072         num = num / BASE;
00073     }
00074 }
00075 
00076 
00077 BigInt::BigInt(const apstring & s)
00078 // precondition: s consists of digits only, optionally preceded by + or - 
00079 // postcondition: bigint initialized to integer represented by s
00080 //                if s is not a well-formed BigInt (e.g., contains non-digit
00081 //                characters) then an error message is printed and abort called
00082   : mySign(positive),
00083     myDigits(s.length(),'0'),
00084     myNumDigits(0)
00085 {
00086     int k;
00087     int limit = 0;
00088 
00089     if (s.length() == 0)
00090     {
00091         myDigits.resize(1);
00092         AddSigDigit(0);
00093         return;
00094     }
00095     if (s[0] == '-')
00096     {
00097         mySign = negative;
00098         limit = 1;
00099     }
00100     if (s[0] == '+')
00101     {
00102         limit = 1;
00103     }
00104     // start at least significant digit
00105     
00106     for(k=s.length() - 1; k >= limit; k--)
00107     {
00108         if (! isdigit(s[k]))
00109         {
00110             cerr << "badly formed BigInt value = " << s << endl;
00111             abort();
00112         }
00113         AddSigDigit(s[k]-'0');
00114     }
00115     Normalize();
00116 }
00117 
00118 
00119 const BigInt & BigInt::operator +=(const BigInt & rhs)
00120 // postcondition: returns value of bigint + rhs after addition
00121 {
00122 
00123          int sum;
00124          int carry = 0;
00125 
00126          int k;
00127          int len = NumDigits();         // length of larger addend
00128 
00129    if (rhs == 0){
00130       return *this;
00131    }
00132 
00133          if (IsPositive() != rhs.IsPositive())    // signs not the same, subtract
00134          {
00135                   *this -= (-1 * rhs);
00136                   return *this;
00137          }
00138 
00139          // process both numbers until one is exhausted
00140 
00141          if (len < rhs.NumDigits())
00142          {
00143                   len = rhs.NumDigits();
00144          }
00145          for(k=0; k < len; k++)
00146          {
00147                   sum = GetDigit(k) + rhs.GetDigit(k) + carry;
00148                   carry = sum / BASE;
00149                   sum = sum % BASE;
00150 
00151                   if (k < myNumDigits)
00152                   {
00153                                 ChangeDigit(k,sum);
00154                   }
00155                   else
00156                   {
00157                                 AddSigDigit(sum);
00158                   }
00159          }
00160          if (carry != 0)
00161          {
00162                   AddSigDigit(carry);
00163          }
00164          return *this;
00165 }
00166 
00167 
00168 const BigInt & BigInt::operator -=(const BigInt & rhs)
00169 // postcondition: returns value of bigint - rhs after subtraction
00170 {
00171          int diff;
00172          int borrow = 0;
00173 
00174          int k;
00175          int len = NumDigits();
00176 
00177    if (rhs == 0){
00178       return *this;
00179    }
00180 
00181          // signs opposite? then lhs - (-rhs) = lhs + rhs
00182 
00183          if (IsNegative() != rhs.IsNegative())
00184          {
00185                   *this +=(-1 * rhs);
00186                   return *this;
00187          }
00188          // signs are the same, check which number is larger
00189          // and switch to get larger number "on top" if necessary
00190          // since sign can change when subtracting
00191          // examples: 7 - 3 no sign change,     3 - 7 sign changes
00192          //          -7 - (-3) no sign change, -3 -(-7) sign changes
00193          if (IsPositive() && (*this) < rhs ||
00194                   IsNegative() && (*this) > rhs)
00195          {
00196                   *this = rhs - *this;
00197                 if (IsPositive()) mySign = negative;
00198                 else              mySign = positive;   // toggle sign
00199                   return *this;
00200          }
00201          // same sign and larger number on top
00202 
00203          for(k=0; k < len; k++)
00204          {
00205                   diff = GetDigit(k) - rhs.GetDigit(k) - borrow;
00206                   borrow = 0;
00207                   if (diff < 0)
00208                   {
00209                                 diff += 10;
00210                                 borrow = 1;
00211                   }
00212                   ChangeDigit(k,diff);
00213          }
00214          Normalize();
00215          return *this;
00216 }
00217 
00218 BigInt operator +(const BigInt & lhs, const BigInt & rhs)
00219 // postcondition: returns a bigint whose value is lhs + rhs
00220 {
00221     BigInt result(lhs);
00222     result += rhs;   
00223     return result;
00224 }
00225 
00226 BigInt operator -(const BigInt & lhs, const BigInt & rhs)
00227 // postcondition: returns a bigint whose value is lhs + rhs
00228 {
00229     BigInt result(lhs);
00230     result -= rhs;
00231     return result;
00232 }
00233 
00234 void BigInt::Print(ostream & os) const
00235 // postcondition: BigInt inserted onto stream os
00236 {
00237     os << ToString();
00238 }
00239 
00240 apstring BigInt::ToString() const
00241 // postcondition: returns string equivalent of BigInt
00242 {
00243     int k;
00244     int len = NumDigits();    
00245     apstring s = "";
00246 
00247     if (IsNegative())
00248     {
00249                   s = '-';
00250     }
00251     for(k=len-1; k >= 0; k--)
00252     {
00253         s += char('0'+GetDigit(k));
00254     }
00255     return s;
00256 }
00257 
00258 int BigInt::ToInt() const
00259 // precondition: INT_MIN <= self <= INT_MAX
00260 // postcondition: returns int equivalent of self
00261 {
00262     int result = 0;
00263     int k;
00264     if (INT_MAX < *this) return INT_MAX;
00265     if (*this < INT_MIN) return INT_MIN;
00266     
00267     for(k=NumDigits()-1; k >= 0; k--)
00268     {
00269         result = result * 10 + GetDigit(k);
00270     }
00271     if (IsNegative())
00272     {
00273         result *= -1;
00274     }
00275     return result;
00276 }
00277 
00278 double BigInt::ToDouble() const
00279 // precondition: DBL_MIN <= self <= DLB_MAX
00280 // postcondition: returns double equivalent of self
00281 {
00282     double result = 0.0;
00283     int k;
00284     for(k=NumDigits()-1; k >= 0; k--)
00285     {
00286         result = result * 10 + GetDigit(k);
00287     }
00288     if (IsNegative())
00289     {
00290         result *= -1;
00291     }
00292     return result;
00293 }
00294 
00295 ostream & operator <<(ostream & out, const BigInt & big)
00296 // postcondition: big inserted onto stream out
00297 {
00298     big.Print(out);
00299     return out;
00300 }
00301 
00302 istream & operator >> (istream & in, BigInt & big)
00303 // postcondition: big extracted from in, must be whitespace delimited     
00304 {
00305     apstring s;
00306     in >> s;
00307     big = BigInt(s);
00308     return in;
00309 }
00310 
00311 bool operator == (const BigInt & lhs, const BigInt & rhs)
00312 // postcondition: returns true if lhs == rhs, else returns false
00313 {
00314     return lhs.Equal(rhs);
00315 }
00316 
00317 bool BigInt::Equal(const BigInt & rhs) const
00318 // postcondition: returns true if self == rhs, else returns false
00319 {
00320 
00321     if (NumDigits() != rhs.NumDigits() || IsNegative() != rhs.IsNegative())
00322     {
00323         return false;
00324     }
00325     // assert: same sign, same number of digits;
00326 
00327     int k;
00328     int len = NumDigits();
00329     for(k=0; k < len; k++)
00330     {
00331         if (GetDigit(k) != rhs.GetDigit(k)) return false;
00332     }
00333 
00334     return true;
00335 }
00336 
00337 bool operator != (const BigInt & lhs, const BigInt & rhs)
00338 // postcondition: returns true if lhs != rhs, else returns false     
00339 {
00340     return ! (lhs == rhs);
00341 }
00342 
00343 bool operator < (const BigInt & lhs, const BigInt & rhs)
00344 // postcondition: return true if lhs < rhs, else returns false     
00345 {
00346     return lhs.LessThan(rhs);
00347 }
00348 
00349 bool BigInt::LessThan(const BigInt & rhs) const
00350 // postcondition: return true if self < rhs, else returns false     
00351 {
00352     // if signs aren't equal, self < rhs only if self is negative
00353     
00354     if (IsNegative() != rhs.IsNegative())
00355     {
00356         return IsNegative();         
00357     }
00358 
00359     // if # digits aren't the same must check # digits and sign
00360     
00361     if (NumDigits() != rhs.NumDigits())
00362     {
00363         return (NumDigits() < rhs.NumDigits() && IsPositive()) ||
00364                (NumDigits() > rhs.NumDigits() && IsNegative());
00365     }
00366 
00367     // assert: # digits same, signs the same
00368 
00369     int k;
00370     int len = NumDigits();
00371 
00372     for(k=len-1; k >= 0; k--)
00373     {
00374         if (GetDigit(k) < rhs.GetDigit(k)) return IsPositive();
00375         if (GetDigit(k) > rhs.GetDigit(k)) return IsNegative();
00376     }
00377     return false;      // self == rhs
00378 }
00379 
00380 bool operator > (const BigInt & lhs, const BigInt & rhs)
00381 // postcondition: return true if lhs > rhs, else returns false
00382 {
00383     return rhs < lhs;    
00384 }
00385 
00386 bool operator <= (const BigInt & lhs, const BigInt & rhs)
00387 // postcondition: return true if lhs <= rhs, else returns false
00388 {
00389     return lhs == rhs || lhs < rhs;
00390 }
00391 bool operator >= (const BigInt & lhs, const BigInt & rhs)
00392 // postcondition: return true if lhs >= rhs, else returns false
00393 {
00394     return lhs == rhs || lhs > rhs;
00395 }
00396 
00397 void BigInt::Normalize()
00398 // postcondition: all leading zeros removed     
00399 {
00400     int k;
00401     int len = NumDigits();
00402     for(k=len-1; k >= 0; k--)        // find a non-zero digit
00403     {
00404         if (GetDigit(k) != 0) break;
00405         myNumDigits--;               // "chop" off zeros
00406     }
00407     if (k < 0)    // all zeros
00408     {
00409         myNumDigits = 1;
00410         mySign = positive;
00411     }
00412 }
00413 
00414 
00415 const BigInt & BigInt::operator *=(int num)
00416 // postcondition: returns num * value of BigInt after multiplication
00417 {
00418     int carry = 0;
00419     int product;               // product of num and one digit + carry
00420     int k;
00421     int len = NumDigits();
00422     
00423     if (0 == num)              // treat zero as special case and stop
00424     {
00425         *this = 0;
00426         return *this;
00427     }
00428 
00429          if (BASE < num|| num < 0)        // handle pre-condition failure
00430     {
00431         *this *= BigInt(num);
00432         return *this;
00433     }
00434 
00435     if (1 == num)              // treat one as special case, no work
00436     {
00437         return *this;
00438     }
00439 
00440     for(k=0; k < len; k++)     // once for each digit
00441     {
00442         product = num * GetDigit(k) + carry;
00443         carry = product/BASE;
00444         ChangeDigit(k,product % BASE);
00445     }
00446     
00447     while (carry != 0)         // carry all digits
00448     {
00449         AddSigDigit(carry % BASE);
00450         carry /= BASE;
00451     }
00452     return *this;
00453 }
00454 
00455 
00456 BigInt operator *(const BigInt & a, int num)
00457 // postcondition: returns a * num     
00458 {
00459     BigInt result(a);
00460     result *= num;
00461     return result;
00462 }
00463 
00464 BigInt operator *(int num, const BigInt & a)
00465 // postcondition: returns num * a     
00466 {
00467     BigInt result(a);
00468     result *= num;
00469     return result;
00470 }
00471 
00472 
00473 const BigInt & BigInt::operator *=(const BigInt & rhs)
00474 // postcondition: returns value of bigint * rhs after multiplication
00475 {
00476          // uses standard "grade school method" for multiplying
00477 
00478         if (IsNegative() != rhs.IsNegative())
00479         {
00480                 mySign = negative;
00481         }
00482         else
00483         {
00484                 mySign = positive;
00485         }
00486 
00487          BigInt sum(0);                             // to accumulate sum
00488          int k;
00489          int len = rhs.NumDigits();                 // # digits in multiplier
00490 
00491          for(k=0; k < len; k++)
00492          {
00493                  sum += (*this) * rhs.GetDigit(k);          // k-th digit * self
00494                  (*this) *= 10;                             // add a zero
00495          }
00496          *this = sum;
00497          return *this;
00498 }
00499 
00500 BigInt operator *(const BigInt & lhs, const BigInt & rhs)
00501 // postcondition: returns a bigint whose value is lhs * rhs
00502 {
00503     BigInt result(lhs);
00504     result *= rhs;
00505     return result;
00506 }
00507 
00508 int BigInt::NumDigits() const
00509 // postcondition: returns # digits in BigInt
00510 {
00511     return myNumDigits;
00512 }
00513 
00514 int BigInt::GetDigit(int k) const
00515 // precondition: 0 <= k < NumDigits()
00516 // postcondition: returns k-th digit 
00517 //                (0 if precondition is false)
00518 //                Note: 0th digit is least significant digit
00519 {
00520     if (0 <= k && k < NumDigits())
00521     {
00522         return myDigits[k] - '0';
00523     }
00524     return 0;
00525 }
00526 
00527 void BigInt::ChangeDigit(int k, int value)
00528 // precondition: 0 <= k < NumDigits()
00529 // postcondition: k-th digit changed to value
00530 //                Note: 0th digit is least significant digit
00531 {
00532     if (0 <= k && k < NumDigits())
00533     {
00534         myDigits[k] = char('0' + value);
00535     }
00536     else
00537     {
00538         cerr << "error changeDigit " << k << " " << myNumDigits << endl;
00539     }
00540 }
00541 
00542 void BigInt::AddSigDigit(int value)
00543 // postcondition: value added to BigInt as most significant digit
00544 //                Note: 0th digit is least significant digit     
00545 {
00546     if (myNumDigits >= myDigits.length())
00547     {
00548         myDigits.resize(myDigits.length() * 2);
00549     }
00550     myDigits[myNumDigits] = char('0' + value);
00551     myNumDigits++;
00552 }
00553 
00554 bool BigInt::IsNegative() const
00555 // postcondition: returns true iff BigInt is negative
00556 {
00557     return mySign == negative;
00558 }
00559 
00560 bool BigInt::IsPositive() const
00561 // postcondition: returns true iff BigInt is positive
00562 {
00563         return mySign == positive;
00564 }

Generated at Sun Feb 24 09:56:55 2002 for STARLAB by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001