home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / comp / lang / cplus / 16677 < prev    next >
Encoding:
Text File  |  1992-11-20  |  9.5 KB  |  291 lines

  1. Newsgroups: comp.lang.c++
  2. Path: sparky!uunet!usc!zaphod.mps.ohio-state.edu!moe.ksu.ksu.edu!mimbres.cs.unm.edu!cobra.cs.unm.edu!shapiro
  3. From: shapiro@cobra.cs.unm.edu (Henry Shapiro)
  4. Subject: Overloading postfix ++
  5. Message-ID: <By1BpF.2nC@cobra.cs.unm.edu>
  6. Sender: news@cobra.cs.unm.edu
  7. Organization: Computer Science Department, University of New Mexico
  8. Date: Fri, 20 Nov 1992 21:58:30 GMT
  9. Lines: 280
  10.  
  11. I'm reasonably new to C++, but have been programming for many years and in
  12. lots of languages.  For a book I am writing I wanted to program up an
  13. infinite precision integer package in C++.  The following code can be
  14. criticized on lots of grounds -- that is NOT the point of this mail.
  15. The point is: According to Lippman in his 2nd edition of the C++ primer,
  16. you can overload the POSTFIX ++ operator.  I have, I believe, followed
  17. his model EXACTLY.  Well.... it doesn't work.  It compiles fine, but
  18. the PREFIX ++ operator is being invoked.  It is easy to see this: 3! prints
  19. as 12 and not 6.  I've tried this on different compilers.  So either they
  20. all have a bug or I don't understand something.  I'm gambling on the latter.
  21. Can anybody straighten me out?
  22.  
  23. I don't read this newsgroup very often, so please e-mail me responses
  24. at  shapiro@unmvax.cs.unm.edu  .  If something interesting turns up I'll
  25. post the solution/conclusion.
  26.  
  27. // ======================= Factorial.c ===================================
  28. #include <stream.h>
  29. #include "Long_Arithmetic.h"
  30.  
  31. LongInt Factorial(LongInt n) {
  32.     // Compute  n! .
  33.     LongInt NFact;
  34.     LongInt i;
  35.  
  36.     NFact = 1;
  37.     for (i = 2; i <= n; i)
  38.         NFact = NFact * i++;  //IS USING PREFIX AND NOT POSTFIX ++ (try 3!)
  39.     return NFact;
  40. } //Factorial
  41.  
  42. void main() {
  43.     int n;
  44.  
  45.     cout << "For what  n  do you wish to compute  n! : "; cin >> n;
  46.  
  47.     cout << n << "! = " << Factorial(n);
  48. } // main
  49. // ======================= Long_Arithmetic.h ===================================
  50. /* Store an infinite precision natural number in an array which is just
  51.    long enough to hold it (more or less).  Numbers are stored in base 10,
  52.    one digit per element array.  Leading zeros are not part of the number,
  53.    except for zero.
  54. */
  55. class LongInt {
  56. public:
  57.     LongInt(long = 0); // allows automatic conversion to  LongInt  in a number
  58.                // of situations where this is desirable
  59.     LongInt(const LongInt&); // allows parameter passing by value to be what
  60.                  // the user expects
  61.     ~LongInt();
  62.  
  63.     LongInt& operator=(const LongInt&);
  64.  
  65.     friend int operator< (const LongInt&, const LongInt&);
  66.     friend int operator<=(const LongInt&, const LongInt&);
  67.     friend int operator> (const LongInt&, const LongInt&);
  68.     friend int operator>=(const LongInt&, const LongInt&);
  69.     friend int operator==(const LongInt&, const LongInt&);
  70.     friend int operator!=(const LongInt&, const LongInt&);
  71.  
  72.     friend LongInt operator+(const LongInt&, const LongInt&);
  73.     friend LongInt operator-(const LongInt&, const LongInt&);
  74.     friend LongInt operator*(const LongInt&, const LongInt&);
  75.     friend LongInt operator/(const LongInt&, const LongInt&);
  76.     friend LongInt operator%(const LongInt&, const LongInt&);
  77.  
  78.     friend LongInt operator++(LongInt&);     // prefix ++
  79.     friend LongInt operator++(LongInt&,int); // postfix ++
  80.  
  81.     friend ostream& operator<<(ostream&, const LongInt&);
  82.  
  83. private:
  84.     long num_digits;
  85.     char *num; // signed char num[] -- each char holds one digit.
  86.            // The low order digit is in  num[0] .
  87.     int compare(const LongInt& m2) const;
  88.     LongInt partial(int d, long shift) const;
  89. };
  90. // ======================= Long_Arithmetic.c ===================================
  91. #include <stream.h>
  92. #include "Long_Arithmetic.h"
  93.  
  94. LongInt::LongInt(long n) {
  95.     if (n < 0) n = 0; // or call an error routine
  96.     num_digits = 1;   // zero gets one digit as well
  97.  
  98.     long i;
  99.     long m = n;
  100.  
  101.     // Determine how much storage is needed.
  102.     while ((m = m/10) != 0) num_digits++;
  103.  
  104.     num = new char[num_digits];
  105.     for (i = 0; i < num_digits; i++) {
  106.     num[i] = char(n % 10);
  107.     n /= 10;
  108.     }
  109. } // LongInt(long)
  110.  
  111. LongInt::LongInt(const LongInt& n) {
  112.     num_digits = n.num_digits;
  113.     // there can't be an old one to destroy
  114.     num = new char[n.num_digits]; // get sufficient storage -- possible
  115.                   // less than used by  n
  116.  
  117.     for (long i = 0; i < num_digits; i++) num[i] = n.num[i];
  118.     //  *this = n;  won't work, as this copies only the pointer in  num .
  119. } // LongInt(const LongInt&)
  120.  
  121. LongInt::~LongInt() { delete num; }
  122.  
  123. LongInt& LongInt::operator=(const LongInt& n) {
  124.     if (&n == this) return *this; // a special case
  125.  
  126.     num_digits = n.num_digits;
  127.     delete num;                   // recover the old storage
  128.     num = new char[n.num_digits]; // get sufficient storage
  129.  
  130.     for (long i = 0; i < num_digits; i++) num[i] = n.num[i];
  131.     //  *this = n;  won't work, as this copies only the pointer in  num .
  132.  
  133.     return *this; /* This actually calls the copy-constructor, which makes
  134.              a fresh copy.  This is wasteful, since 99% of the time
  135.              it will just get thrown away anyway, but if we want
  136.              to make = a right associative operator, like it normally
  137.              is in C++, we have to do this. */
  138. } // operator=
  139.  
  140. ostream& operator<<(ostream& output, const LongInt& n) {
  141.     // Effectively, perform  writeln(n)  with commas inserted in the
  142.     // appropriate places for readability.
  143.  
  144.     /* Ground rules for pretty printing:
  145.          Commas are printed after every block of three digits.
  146.          Numbers that take more than one line to print are justified so that
  147.            the commas line up.
  148.          The short line is the last, which holds the least significant digits.
  149.          " ...more" is used to indicate a number continues on the next line.
  150.          Things can go haywire if the user has printed something on the line
  151.            before calling  WriteNum .
  152.     */
  153.  
  154.     /* The maximum line length is  4*k + 8, where  k  is the
  155.        number of blocks of three that can appear on a line.  This is
  156.        used to calculate  MAXGROUPSOFTHREE .
  157.     */
  158.     const int MAXGROUPSOFTHREE = 17; // Don't push to column 80, as some
  159.                      // terminals and printers have trouble
  160.                      // with this.
  161.     long j = n.num_digits; // number of digits left to write out -- used for
  162.                // comma placement
  163.     int i = 0; // number of groups of three written on a line
  164.  
  165.     // Write out any blanks needed to align commas on multiline numbers.
  166.     switch (n.num_digits % 3) {
  167.       case 0:                 break;
  168.       case 1: output << "  "; break;
  169.       case 2: output << " ";  break;
  170.     }
  171.     while (j--) { // count one ahead of subscript   while (j > 0) { j--; ...
  172.     output << int(n.num[j]); // print digit (field width is 1)
  173.     if (j % 3 == 0 && j != 0) { // finished a group of three and
  174.                     // didn't finish the number
  175.             output << ",";
  176.             if (++i == MAXGROUPSOFTHREE) { // another groupt of three written
  177.                 output << " ...more\n";      // is line done?
  178.                 i = 0;
  179.         }
  180.         }
  181.     }
  182.     output << "\n";
  183.  
  184.     return output;
  185. } // operator<<
  186.  
  187. int LongInt::compare(const LongInt& m2) const {
  188.     // the asymmetry is annoying, but we wish to keep it private
  189.     if (this->num_digits < m2.num_digits) return -1;
  190.     else if (this->num_digits > m2.num_digits) return 1;
  191.     else { // m1 and m2 are the same length
  192.     for (long i = this->num_digits - 1; i >= 0; i--)
  193.         if (this->num[i] < m2.num[i]) return -1;
  194.         else if (this->num[i] > m2.num[i]) return 1;
  195.     return 0;
  196.     }
  197. } // int compare(const LongInt& m2)
  198.  
  199. int operator<=(const LongInt& m1, const LongInt& m2) {
  200.     return m1.compare(m2) <= 0;
  201. }
  202.  
  203. LongInt operator+(const LongInt& m1, const LongInt& m2) {
  204.     LongInt n;
  205.     const long max =
  206.         m1.num_digits > m2.num_digits ? m1.num_digits : m2.num_digits;
  207.     const long min =
  208.         m1.num_digits < m2.num_digits ? m1.num_digits : m2.num_digits;
  209.     int carry = 0;
  210.  
  211.     delete n.num; // n was zero
  212.     n.num = new char[max+1];
  213.  
  214.     carry = 0;
  215.     for (long i = 0; i < min; i++) { // two numbers to add
  216.     n.num[i] = m1.num[i] + m2.num[i] + carry;
  217.     if (n.num[i] > 9) {
  218.         n.num[i] -= 10;
  219.         carry = 1;
  220.     } else
  221.         carry = 0;
  222.     }
  223.     for ( ; i < m1.num_digits ; i++) { // toss in leftover portion of m1
  224.     n.num[i] = m1.num[i] + carry;
  225.     if (n.num[i] > 9) {
  226.         n.num[i] -= 10;
  227.         carry = 1;
  228.     } else
  229.         carry = 0;
  230.     }
  231.     for ( ; i < m2.num_digits ; i++) { // toss in leftover portion of m1
  232.     n.num[i] = m2.num[i] + carry;
  233.     if (n.num[i] > 9) {
  234.         n.num[i] -= 10;
  235.         carry = 1;
  236.     } else
  237.         carry = 0;
  238.     }
  239.     if (carry == 1) {
  240.     n.num[i] = carry;
  241.     i++;
  242.     }
  243.     n.num_digits = i;
  244.     return n; // unfortunately, this does a copy
  245. } // operator+
  246.  
  247. LongInt LongInt::partial(int d, long shift) const {
  248.     LongInt n;
  249.     int carry = 0;
  250.     int next;
  251.  
  252.     if (d == 0) return n;
  253.     delete n.num; // n was zero
  254.     n.num = new char[this->num_digits + shift + 1]; // worst case
  255.     for (long i = 0; i < shift; i++) n.num[i] = 0;
  256.     for (long j = 0; j < this->num_digits; j++, i++) {
  257.     next = this->num[j]*d + carry;
  258.     n.num[i] = next % 10;
  259.     carry = next / 10;
  260.     }
  261.     if (carry > 0) {
  262.     n.num[i] = carry;
  263.     i++;
  264.     }
  265.     n.num_digits = i;
  266.     return n;
  267. }
  268.  
  269. LongInt operator*(const LongInt& m1, const LongInt& m2) {
  270.     LongInt n = 0; // partial product
  271.  
  272.     // 0 * anything = 0 -- a special case
  273.     if (m1.num_digits == 1 && m1.num[0] == 0) return n;
  274.  
  275.     for (long i = 0; i < m2.num_digits; i++)
  276.     n = n + m1.partial(m2.num[i],i);
  277.  
  278.     return n; // unfortunately, this does a copy
  279. } // operator*
  280.  
  281. LongInt operator++(LongInt& m1, int) {
  282.     LongInt m2 = m1;
  283.     m1 = m1 + 1;
  284.     return m2;
  285. } // operator++ (postfix)
  286.  
  287. LongInt operator++(LongInt& m1) {
  288.     m1 = m1 + 1;
  289.     return m1;
  290. } // operator++ (prefix)
  291.