home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.lang.c++
- Path: sparky!uunet!usc!zaphod.mps.ohio-state.edu!moe.ksu.ksu.edu!mimbres.cs.unm.edu!cobra.cs.unm.edu!shapiro
- From: shapiro@cobra.cs.unm.edu (Henry Shapiro)
- Subject: Overloading postfix ++
- Message-ID: <By1BpF.2nC@cobra.cs.unm.edu>
- Sender: news@cobra.cs.unm.edu
- Organization: Computer Science Department, University of New Mexico
- Date: Fri, 20 Nov 1992 21:58:30 GMT
- Lines: 280
-
- I'm reasonably new to C++, but have been programming for many years and in
- lots of languages. For a book I am writing I wanted to program up an
- infinite precision integer package in C++. The following code can be
- criticized on lots of grounds -- that is NOT the point of this mail.
- The point is: According to Lippman in his 2nd edition of the C++ primer,
- you can overload the POSTFIX ++ operator. I have, I believe, followed
- his model EXACTLY. Well.... it doesn't work. It compiles fine, but
- the PREFIX ++ operator is being invoked. It is easy to see this: 3! prints
- as 12 and not 6. I've tried this on different compilers. So either they
- all have a bug or I don't understand something. I'm gambling on the latter.
- Can anybody straighten me out?
-
- I don't read this newsgroup very often, so please e-mail me responses
- at shapiro@unmvax.cs.unm.edu . If something interesting turns up I'll
- post the solution/conclusion.
-
- // ======================= Factorial.c ===================================
- #include <stream.h>
- #include "Long_Arithmetic.h"
-
- LongInt Factorial(LongInt n) {
- // Compute n! .
- LongInt NFact;
- LongInt i;
-
- NFact = 1;
- for (i = 2; i <= n; i)
- NFact = NFact * i++; //IS USING PREFIX AND NOT POSTFIX ++ (try 3!)
- return NFact;
- } //Factorial
-
- void main() {
- int n;
-
- cout << "For what n do you wish to compute n! : "; cin >> n;
-
- cout << n << "! = " << Factorial(n);
- } // main
- // ======================= Long_Arithmetic.h ===================================
- /* Store an infinite precision natural number in an array which is just
- long enough to hold it (more or less). Numbers are stored in base 10,
- one digit per element array. Leading zeros are not part of the number,
- except for zero.
- */
- class LongInt {
- public:
- LongInt(long = 0); // allows automatic conversion to LongInt in a number
- // of situations where this is desirable
- LongInt(const LongInt&); // allows parameter passing by value to be what
- // the user expects
- ~LongInt();
-
- LongInt& operator=(const LongInt&);
-
- friend int operator< (const LongInt&, const LongInt&);
- friend int operator<=(const LongInt&, const LongInt&);
- friend int operator> (const LongInt&, const LongInt&);
- friend int operator>=(const LongInt&, const LongInt&);
- friend int operator==(const LongInt&, const LongInt&);
- friend int operator!=(const LongInt&, const LongInt&);
-
- friend LongInt operator+(const LongInt&, const LongInt&);
- friend LongInt operator-(const LongInt&, const LongInt&);
- friend LongInt operator*(const LongInt&, const LongInt&);
- friend LongInt operator/(const LongInt&, const LongInt&);
- friend LongInt operator%(const LongInt&, const LongInt&);
-
- friend LongInt operator++(LongInt&); // prefix ++
- friend LongInt operator++(LongInt&,int); // postfix ++
-
- friend ostream& operator<<(ostream&, const LongInt&);
-
- private:
- long num_digits;
- char *num; // signed char num[] -- each char holds one digit.
- // The low order digit is in num[0] .
- int compare(const LongInt& m2) const;
- LongInt partial(int d, long shift) const;
- };
- // ======================= Long_Arithmetic.c ===================================
- #include <stream.h>
- #include "Long_Arithmetic.h"
-
- LongInt::LongInt(long n) {
- if (n < 0) n = 0; // or call an error routine
- num_digits = 1; // zero gets one digit as well
-
- long i;
- long m = n;
-
- // Determine how much storage is needed.
- while ((m = m/10) != 0) num_digits++;
-
- num = new char[num_digits];
- for (i = 0; i < num_digits; i++) {
- num[i] = char(n % 10);
- n /= 10;
- }
- } // LongInt(long)
-
- LongInt::LongInt(const LongInt& n) {
- num_digits = n.num_digits;
- // there can't be an old one to destroy
- num = new char[n.num_digits]; // get sufficient storage -- possible
- // less than used by n
-
- for (long i = 0; i < num_digits; i++) num[i] = n.num[i];
- // *this = n; won't work, as this copies only the pointer in num .
- } // LongInt(const LongInt&)
-
- LongInt::~LongInt() { delete num; }
-
- LongInt& LongInt::operator=(const LongInt& n) {
- if (&n == this) return *this; // a special case
-
- num_digits = n.num_digits;
- delete num; // recover the old storage
- num = new char[n.num_digits]; // get sufficient storage
-
- for (long i = 0; i < num_digits; i++) num[i] = n.num[i];
- // *this = n; won't work, as this copies only the pointer in num .
-
- return *this; /* This actually calls the copy-constructor, which makes
- a fresh copy. This is wasteful, since 99% of the time
- it will just get thrown away anyway, but if we want
- to make = a right associative operator, like it normally
- is in C++, we have to do this. */
- } // operator=
-
- ostream& operator<<(ostream& output, const LongInt& n) {
- // Effectively, perform writeln(n) with commas inserted in the
- // appropriate places for readability.
-
- /* Ground rules for pretty printing:
- Commas are printed after every block of three digits.
- Numbers that take more than one line to print are justified so that
- the commas line up.
- The short line is the last, which holds the least significant digits.
- " ...more" is used to indicate a number continues on the next line.
- Things can go haywire if the user has printed something on the line
- before calling WriteNum .
- */
-
- /* The maximum line length is 4*k + 8, where k is the
- number of blocks of three that can appear on a line. This is
- used to calculate MAXGROUPSOFTHREE .
- */
- const int MAXGROUPSOFTHREE = 17; // Don't push to column 80, as some
- // terminals and printers have trouble
- // with this.
- long j = n.num_digits; // number of digits left to write out -- used for
- // comma placement
- int i = 0; // number of groups of three written on a line
-
- // Write out any blanks needed to align commas on multiline numbers.
- switch (n.num_digits % 3) {
- case 0: break;
- case 1: output << " "; break;
- case 2: output << " "; break;
- }
- while (j--) { // count one ahead of subscript while (j > 0) { j--; ...
- output << int(n.num[j]); // print digit (field width is 1)
- if (j % 3 == 0 && j != 0) { // finished a group of three and
- // didn't finish the number
- output << ",";
- if (++i == MAXGROUPSOFTHREE) { // another groupt of three written
- output << " ...more\n"; // is line done?
- i = 0;
- }
- }
- }
- output << "\n";
-
- return output;
- } // operator<<
-
- int LongInt::compare(const LongInt& m2) const {
- // the asymmetry is annoying, but we wish to keep it private
- if (this->num_digits < m2.num_digits) return -1;
- else if (this->num_digits > m2.num_digits) return 1;
- else { // m1 and m2 are the same length
- for (long i = this->num_digits - 1; i >= 0; i--)
- if (this->num[i] < m2.num[i]) return -1;
- else if (this->num[i] > m2.num[i]) return 1;
- return 0;
- }
- } // int compare(const LongInt& m2)
-
- int operator<=(const LongInt& m1, const LongInt& m2) {
- return m1.compare(m2) <= 0;
- }
-
- LongInt operator+(const LongInt& m1, const LongInt& m2) {
- LongInt n;
- const long max =
- m1.num_digits > m2.num_digits ? m1.num_digits : m2.num_digits;
- const long min =
- m1.num_digits < m2.num_digits ? m1.num_digits : m2.num_digits;
- int carry = 0;
-
- delete n.num; // n was zero
- n.num = new char[max+1];
-
- carry = 0;
- for (long i = 0; i < min; i++) { // two numbers to add
- n.num[i] = m1.num[i] + m2.num[i] + carry;
- if (n.num[i] > 9) {
- n.num[i] -= 10;
- carry = 1;
- } else
- carry = 0;
- }
- for ( ; i < m1.num_digits ; i++) { // toss in leftover portion of m1
- n.num[i] = m1.num[i] + carry;
- if (n.num[i] > 9) {
- n.num[i] -= 10;
- carry = 1;
- } else
- carry = 0;
- }
- for ( ; i < m2.num_digits ; i++) { // toss in leftover portion of m1
- n.num[i] = m2.num[i] + carry;
- if (n.num[i] > 9) {
- n.num[i] -= 10;
- carry = 1;
- } else
- carry = 0;
- }
- if (carry == 1) {
- n.num[i] = carry;
- i++;
- }
- n.num_digits = i;
- return n; // unfortunately, this does a copy
- } // operator+
-
- LongInt LongInt::partial(int d, long shift) const {
- LongInt n;
- int carry = 0;
- int next;
-
- if (d == 0) return n;
- delete n.num; // n was zero
- n.num = new char[this->num_digits + shift + 1]; // worst case
- for (long i = 0; i < shift; i++) n.num[i] = 0;
- for (long j = 0; j < this->num_digits; j++, i++) {
- next = this->num[j]*d + carry;
- n.num[i] = next % 10;
- carry = next / 10;
- }
- if (carry > 0) {
- n.num[i] = carry;
- i++;
- }
- n.num_digits = i;
- return n;
- }
-
- LongInt operator*(const LongInt& m1, const LongInt& m2) {
- LongInt n = 0; // partial product
-
- // 0 * anything = 0 -- a special case
- if (m1.num_digits == 1 && m1.num[0] == 0) return n;
-
- for (long i = 0; i < m2.num_digits; i++)
- n = n + m1.partial(m2.num[i],i);
-
- return n; // unfortunately, this does a copy
- } // operator*
-
- LongInt operator++(LongInt& m1, int) {
- LongInt m2 = m1;
- m1 = m1 + 1;
- return m2;
- } // operator++ (postfix)
-
- LongInt operator++(LongInt& m1) {
- m1 = m1 + 1;
- return m1;
- } // operator++ (prefix)
-