Massive cleanup of the entire codebase. Notable changes include:
authorMatt McCutchen <matt@mattmccutchen.net>
Wed, 30 Jan 2008 21:31:40 +0000 (16:31 -0500)
committerMatt McCutchen <matt@mattmccutchen.net>
Wed, 30 Jan 2008 21:31:54 +0000 (16:31 -0500)
- Use templates to slash code duplication in primitive-integer constructors and
  converters.
- Remove excessively chatty and historical comments, and move some pieces of
  design discussion to the proper places.
- Improve code format.

Not everything is perfect, but this is much better, and the conversion problem
is finally fixed.  I've gotten to the point where the sample program runs
without crashing and produces the correct output.  More refinements to come.

BigInteger.cc
BigInteger.hh
BigIntegerLibrary.hh
BigIntegerUtils.cc
BigUnsigned.cc
BigUnsigned.hh
BigUnsignedInABase.cc
NumberlikeArray.hh
README
sample.cc

index 8fe0d3b..2651ab7 100644 (file)
@@ -1,8 +1,5 @@
 #include "BigInteger.hh"
 
-// MANAGEMENT
-
-// Assignment operator
 void BigInteger::operator =(const BigInteger &x) {
        // Calls like a = a have no effect
        if (this == &x)
@@ -10,274 +7,135 @@ void BigInteger::operator =(const BigInteger &x) {
        // Copy sign
        sign = x.sign;
        // Copy the rest
-       BigUnsigned::operator =(x);
+       mag = x.mag;
 }
 
-// Constructor from an array of blocks and a sign
-BigInteger::BigInteger(const Blk *b, Index l, Sign s) : BigUnsigned(b, l) {
+BigInteger::BigInteger(const Blk *b, Index blen, Sign s) : mag(b, blen) {
        switch (s) {
-               case zero:
-               case positive:
-               case negative:
-               sign = (len == 0) ? zero : s;
+       case zero:
+       case positive:
+       case negative:
+               sign = mag.isZero() ? zero : s;
                break;
-               default:
-               throw "BigInteger::BigInteger(Blk *, Index, Sign): Invalid sign";
+       default:
+               throw "BigInteger::BigInteger(const Blk *, Index, Sign): Invalid sign";
        }
 }
 
-// Constructor from a BigUnsigned and a sign
-BigInteger::BigInteger(const BigUnsigned &x, Sign s) : BigUnsigned(x) {
+BigInteger::BigInteger(const BigUnsigned &x, Sign s) : mag(x) {
        switch (s) {
-               case zero:
-               case positive:
-               case negative:
-               sign = (len == 0) ? zero : s;
+       case zero:
+       case positive:
+       case negative:
+               sign = mag.isZero() ? zero : s;
                break;
-               default:
+       default:
                throw "BigInteger::BigInteger(Blk *, Index, Sign): Invalid sign";
        }
 }
 
-/*
- * The steps for construction of a BigInteger
- * from an integral value x are as follows:
- * 1. If x is zero, create an empty BigInteger and stop.
- * 2. Allocate a one-block number array.
- * 3. If x is positive (or of an unsigned type), set the
- *    sign of the BigInteger to positive.
- * 4. If x is of a signed type and is negative, set the
- *    sign of the BigInteger to negative.
- * 5. If x is of a signed type, convert x (or -x if x < 0)
- *    to the unsigned type of the same length.
- * 6. Expand x (or the result of step 5) to a Blk,
- *    and store it in the number array.
- *
- * See remarks in `BigUnsigned.cc' and `NumberlikeArray.hh'
- * about new handling of zero-length arrays.
- */
+/* CONSTRUCTION FROM PRIMITIVE INTEGERS
+ * Same idea as in BigUnsigned.cc, except that negative input results in a
+ * negative BigInteger instead of an exception. */
 
-BigInteger::BigInteger(unsigned long x) {
-       if (x == 0)
-               sign = zero; // NumberlikeArray did the rest
-       else {
-               cap = 1;
-               blk = new Blk[1];
-               sign = positive;
-               len = 1;
-               blk[0] = Blk(x);
-       }
+// Done longhand to let us use initialization.
+BigInteger::BigInteger(unsigned long x) : mag(x) {
+       sign = mag.isZero() ? zero : positive;
 }
-
-BigInteger::BigInteger(long x) {
-       if (x > 0) {
-               cap = 1;
-               blk = new Blk[1];
-               sign = positive;
-               len = 1;
-               blk[0] = Blk(x);
-       } else if (x < 0) {
-               cap = 1;
-               blk = new Blk[1];
-               sign = negative;
-               len = 1;
-               blk[0] = Blk(-x);
-       } else
-       sign = zero;
+BigInteger::BigInteger(unsigned int x) : mag(x) {
+       sign = mag.isZero() ? zero : positive;
 }
-
-BigInteger::BigInteger(unsigned int x) {
-       if (x == 0)
-               sign = zero;
-       else {
-               cap = 1;
-               blk = new Blk[1];
-               sign = positive;
-               len = 1;
-               blk[0] = Blk(x);
-       }
+BigInteger::BigInteger(unsigned short x) : mag(x) {
+       sign = mag.isZero() ? zero : positive;
 }
 
-BigInteger::BigInteger(int x) {
-       if (x > 0) {
-               cap = 1;
-               blk = new Blk[1];
-               sign = positive;
-               len = 1;
-               blk[0] = Blk(x);
-       } else if (x < 0) {
-               cap = 1;
-               blk = new Blk[1];
-               sign = negative;
-               len = 1;
-               blk[0] = Blk(-x);
-       } else
-       sign = zero;
-}
+// For signed input, determine the desired magnitude and sign separately.
 
-BigInteger::BigInteger(unsigned short x) {
-       if (x == 0)
-               sign = zero;
-       else {
-               cap = 1;
-               blk = new Blk[1];
-               sign = positive;
-               len = 1;
-               blk[0] = Blk(x);
+namespace {
+       template <class X, class UX>
+       BigInteger::Blk magOf(X x) {
+               /* UX(...) cast needed to stop short(-2^15), which negates to
+                * itself, from sign-extending in the conversion to Blk. */
+               return BigInteger::Blk(x < 0 ? UX(-x) : x);
+       }
+       template <class X>
+       BigInteger::Sign signOf(X x) {
+               return (x == 0) ? BigInteger::zero
+                       : (x > 0) ? BigInteger::positive
+                       : BigInteger::negative;
        }
 }
 
-BigInteger::BigInteger(short x) {
-       if (x > 0) {
-               cap = 1;
-               blk = new Blk[1];
-               sign = positive;
-               len = 1;
-               blk[0] = Blk(x);
-       } else if (x < 0) {
-               cap = 1;
-               blk = new Blk[1];
-               sign = negative;
-               len = 1;
-               blk[0] = Blk(-x);
-       } else
-       sign = zero;
+BigInteger::BigInteger(long x) : sign(signOf(x)),
+       mag(magOf<long, unsigned long>(x)) {}
+BigInteger::BigInteger(int x) : sign(signOf(x)),
+       mag(magOf<int, unsigned int>(x)) {}
+BigInteger::BigInteger(short x) : sign(signOf(x)),
+       mag(magOf<short, unsigned short>(x)) {}
+
+// CONVERSION TO PRIMITIVE INTEGERS
+
+/* Reuse BigUnsigned's conversion to an unsigned primitive integer.
+ * The friend is a separate function rather than
+ * BigInteger::convertToUnsignedPrimitive to avoid requiring BigUnsigned to
+ * declare BigInteger. */
+template <class X>
+inline X convertBigUnsignedToPrimitiveAccess(const BigUnsigned &a) {
+       return a.convertToPrimitive<X>();
 }
 
-// CONVERTERS
-/*
- * The steps for conversion of a BigInteger to an
- * integral type are as follows:
- * 1. If the BigInteger is zero, return zero.
- * 2. If the BigInteger is positive:
- *    3. If it is more than one block long or its lowest
- *       block has bits set out of the range of the target
- *       type, throw an exception.
- *    4. Otherwise, convert the lowest block to the
- *       target type and return it.
- * 5. If the BigInteger is negative:
- *    6. If the target type is unsigned, throw an exception.
- *    7. If it is more than one block long or its lowest
- *       block has bits set out of the range of the target
- *       type, throw an exception.
- *    8. Otherwise, convert the lowest block to the
- *       target type, negate it, and return it.
- */
-
-namespace {
-       // These masks are used to test whether a Blk has bits
-       // set out of the range of a smaller integral type.  Note
-       // that this range is not considered to include the sign bit.
-       const BigUnsigned::Blk  lMask = ~0 >> 1;
-       const BigUnsigned::Blk uiMask = (unsigned int)(~0);
-       const BigUnsigned::Blk  iMask = uiMask >> 1;
-       const BigUnsigned::Blk usMask = (unsigned short)(~0);
-       const BigUnsigned::Blk  sMask = usMask >> 1;
+template <class X>
+X BigInteger::convertToUnsignedPrimitive() const {
+       if (sign == negative)
+               throw "BigInteger::to<Primitive>: "
+                       "Cannot convert a negative integer to an unsigned type";
+       else
+               return convertBigUnsignedToPrimitiveAccess<X>(mag);
 }
 
-BigInteger::operator unsigned long() const {
-       switch (sign) {
-               case zero:
+/* Similar to BigUnsigned::convertToPrimitive, but split into two cases for
+ * nonnegative and negative numbers. */
+template <class X, class UX>
+X BigInteger::convertToSignedPrimitive() const {
+       if (sign == zero)
                return 0;
-               case positive:
-               if (len == 1)
-                       return blk[0];
-               else
-                       throw "BigInteger operator unsigned long() const: Value is too big for an unsigned long";
-               case negative:
-               throw "BigInteger operator unsigned long() const: Cannot convert a negative integer to an unsigned type";
-               default:
-               throw "BigInteger: Internal error";
+       else if (mag.getLength() == 1) {
+               // The single block might fit in an X.  Try the conversion.
+               Blk b = mag.getBlock(0);
+               if (sign == positive) {
+                       X x = X(b);
+                       if (x >= 0 && Blk(x) == b)
+                               return x;
+               } else {
+                       X x = -X(b);
+                       /* UX(...) needed to avoid rejecting conversion of
+                        * -2^15 to a short. */
+                       if (x < 0 && Blk(UX(-x)) == b)
+                               return x;
+               }
+               // Otherwise fall through.
        }
+       throw "BigInteger::to<Primitive>: "
+               "Value is too big to fit in the requested type";
 }
 
-BigInteger::operator long() const {
-       switch (sign) {
-               case zero:
-               return 0;
-               case positive:
-               if (len == 1 && (blk[0] & ~lMask) == 0)
-                       return long(blk[0]);
-               else
-                       throw "BigInteger operator long() const: Value is too big for a long";
-               case negative:
-               if (len == 1 && (blk[0] & ~lMask) == 0)
-                       return -long(blk[0]);
-               else
-                       throw "BigInteger operator long() const: Value is too big for a long";
-               default:
-               throw "BigInteger: Internal error";
-       }
+unsigned long BigInteger::toUnsignedLong() const {
+       return convertToUnsignedPrimitive<unsigned long>();
 }
-
-BigInteger::operator unsigned int() const {
-       switch (sign) {
-               case zero:
-               return 0;
-               case positive:
-               if (len == 1 && (blk[0] & ~uiMask) == 0)
-                       return (unsigned int)(blk[0]);
-               else
-                       throw "BigInteger operator unsigned int() const: Value is too big for an unsigned int";
-               case negative:
-               throw "BigInteger operator unsigned int() const: Cannot convert a negative integer to an unsigned type";
-               default:
-               throw "BigInteger: Internal error";
-       }
+unsigned int BigInteger::toUnsignedInt() const {
+       return convertToUnsignedPrimitive<unsigned int>();
 }
-
-BigInteger::operator int() const {
-       switch (sign) {
-               case zero:
-               return 0;
-               case positive:
-               if (len == 1 && (blk[0] & ~iMask) == 0)
-                       return int(blk[0]);
-               else
-                       throw "BigInteger operator int() const: Value is too big for an int";
-               case negative:
-               if (len == 1 && (blk[0] & ~iMask) == 0)
-                       return -int(blk[0]);
-               else
-                       throw "BigInteger operator int() const: Value is too big for an int";
-               default:
-               throw "BigInteger: Internal error";
-       }
+unsigned short BigInteger::toUnsignedShort() const {
+       return convertToUnsignedPrimitive<unsigned short>();
 }
-
-BigInteger::operator unsigned short() const {
-       switch (sign) {
-               case zero:
-               return 0;
-               case positive:
-               if (len == 1 && (blk[0] & ~usMask) == 0)
-                       return (unsigned short)(blk[0]);
-               else
-                       throw "BigInteger operator unsigned short() const: Value is too big for an unsigned short";
-               case negative:
-               throw "BigInteger operator unsigned short() const: Cannot convert a negative integer to an unsigned type";
-               default:
-               throw "BigInteger: Internal error";
-       }
+long BigInteger::toLong() const {
+       return convertToSignedPrimitive<long, unsigned long>();
 }
-
-BigInteger::operator short() const {
-       switch (sign) {
-               case zero:
-               return 0;
-               case positive:
-               if (len == 1 && (blk[0] & ~sMask) == 0)
-                       return short(blk[0]);
-               else
-                       throw "BigInteger operator short() const: Value is too big for a short";
-               case negative:
-               if (len == 1 && (blk[0] & ~sMask) == 0)
-                       return -short(blk[0]);
-               else
-                       throw "BigInteger operator short() const: Value is too big for a short";
-               default:
-               throw "BigInteger: Internal error";
-       }
+int BigInteger::toInt() const {
+       return convertToSignedPrimitive<int, unsigned int>();
+}
+short BigInteger::toShort() const {
+       return convertToSignedPrimitive<short, unsigned short>();
 }
 
 // COMPARISON
@@ -289,22 +147,22 @@ BigInteger::CmpRes BigInteger::compareTo(const BigInteger &x) const {
                return greater;
        else switch (sign) {
                // If the signs are the same...
-               case zero:
+       case zero:
                return equal; // Two zeros are equal
-               case positive:
+       case positive:
                // Compare the magnitudes
-               return BigUnsigned::compareTo(x);
-               case negative:
+               return mag.compareTo(x.mag);
+       case negative:
                // Compare the magnitudes, but return the opposite result
-               return CmpRes(-BigUnsigned::compareTo(x));
-               default:
-               throw "BigInteger: Internal error";
+               return CmpRes(-mag.compareTo(x.mag));
+       default:
+               throw "BigInteger internal error";
        }
 }
 
-// PUT-HERE OPERATIONS
-// These do some messing around to determine the sign of the result,
-// then call one of BigUnsigned's put-heres.
+/* COPY-LESS OPERATIONS
+ * These do some messing around to determine the sign of the result,
+ * then call one of BigUnsigned's copy-less operations. */
 
 // See remarks about aliased calls in BigUnsigned.cc .
 #define DTRT_ALIASED(cond, op) \
@@ -315,7 +173,6 @@ BigInteger::CmpRes BigInteger::compareTo(const BigInteger &x) const {
                return; \
        }
 
-// Addition
 void BigInteger::add(const BigInteger &a, const BigInteger &b) {
        DTRT_ALIASED(this == &a || this == &b, add(a, b));
        // If one argument is zero, copy the other.
@@ -327,37 +184,36 @@ void BigInteger::add(const BigInteger &a, const BigInteger &b) {
        // common sign and add their magnitudes.
        else if (a.sign == b.sign) {
                sign = a.sign;
-               BigUnsigned::add(a, b);
+               mag.add(a.mag, b.mag);
        } else {
                // Otherwise, their magnitudes must be compared.
-               switch (a.BigUnsigned::compareTo(b)) {
+               switch (a.mag.compareTo(b.mag)) {
+               case equal:
                        // If their magnitudes are the same, copy zero.
-                       case equal:
-                       len = 0;
+                       mag = 0;
                        sign = zero;
                        break;
                        // Otherwise, take the sign of the greater, and subtract
                        // the lesser magnitude from the greater magnitude.
-                       case greater:
+               case greater:
                        sign = a.sign;
-                       BigUnsigned::subtract(a, b);
+                       mag.subtract(a.mag, b.mag);
                        break;
-                       case less:
+               case less:
                        sign = b.sign;
-                       BigUnsigned::subtract(b, a);
+                       mag.subtract(b.mag, a.mag);
                        break;
                }
        }
 }
 
-// Subtraction
 void BigInteger::subtract(const BigInteger &a, const BigInteger &b) {
        // Notice that this routine is identical to BigInteger::add,
        // if one replaces b.sign by its opposite.
        DTRT_ALIASED(this == &a || this == &b, subtract(a, b));
        // If a is zero, copy b and flip its sign.  If b is zero, copy a.
        if (a.sign == zero) {
-               BigUnsigned::operator =(b);
+               mag = b.mag;
                // Take the negative of _b_'s, sign, not ours.
                // Bug pointed out by Sam Larkin on 2005.03.30.
                sign = Sign(-b.sign);
@@ -366,45 +222,44 @@ void BigInteger::subtract(const BigInteger &a, const BigInteger &b) {
        // If their signs differ, take a.sign and add the magnitudes.
        else if (a.sign != b.sign) {
                sign = a.sign;
-               BigUnsigned::add(a, b);
+               mag.add(a.mag, b.mag);
        } else {
                // Otherwise, their magnitudes must be compared.
-               switch (a.BigUnsigned::compareTo(b)) {
+               switch (a.mag.compareTo(b.mag)) {
                        // If their magnitudes are the same, copy zero.
-                       case equal:
-                       len = 0;
+               case equal:
+                       mag = 0;
                        sign = zero;
                        break;
                        // If a's magnitude is greater, take a.sign and
                        // subtract a from b.
-                       case greater:
+               case greater:
                        sign = a.sign;
-                       BigUnsigned::subtract(a, b);
+                       mag.subtract(a.mag, b.mag);
                        break;
                        // If b's magnitude is greater, take the opposite
                        // of b.sign and subtract b from a.
-                       case less:
+               case less:
                        sign = Sign(-b.sign);
-                       BigUnsigned::subtract(b, a);
+                       mag.subtract(b.mag, a.mag);
                        break;
                }
        }
 }
 
-// Multiplication
 void BigInteger::multiply(const BigInteger &a, const BigInteger &b) {
        DTRT_ALIASED(this == &a || this == &b, multiply(a, b));
        // If one object is zero, copy zero and return.
        if (a.sign == zero || b.sign == zero) {
                sign = zero;
-               len = 0;
+               mag = 0;
                return;
        }
        // If the signs of the arguments are the same, the result
        // is positive, otherwise it is negative.
        sign = (a.sign == b.sign) ? positive : negative;
        // Multiply the magnitudes.
-       BigUnsigned::multiply(a, b);
+       mag.multiply(a.mag, b.mag);
 }
 
 /*
@@ -442,13 +297,13 @@ void BigInteger::divideWithRemainder(const BigInteger &b, BigInteger &q) {
 
        // Division by zero gives quotient 0 and remainder *this
        if (b.sign == zero) {
-               q.len = 0;
+               q.mag = 0;
                q.sign = zero;
                return;
        }
        // 0 / b gives quotient 0 and remainder 0
        if (sign == zero) {
-               q.len = 0;
+               q.mag = 0;
                q.sign = zero;
                return;
        }
@@ -463,7 +318,7 @@ void BigInteger::divideWithRemainder(const BigInteger &b, BigInteger &q) {
                // No: harder case.  Quotient is negative.
                q.sign = negative;
                // Decrease the magnitude of the dividend by one.
-               BigUnsigned::operator --();
+               mag--;
                /*
                 * We tinker with the dividend before and with the
                 * quotient and remainder after so that the result
@@ -487,25 +342,24 @@ void BigInteger::divideWithRemainder(const BigInteger &b, BigInteger &q) {
        }
 
        // Divide the magnitudes.
-       BigUnsigned::divideWithRemainder(b, q);
+       mag.divideWithRemainder(b.mag, q.mag);
 
        if (sign != b.sign) {
                // More for the harder case (as described):
                // Increase the magnitude of the quotient by one.
-               q.BigUnsigned::operator ++();
+               q.mag++;
                // Modify the remainder.
-               BigUnsigned temp(*this);
-               BigUnsigned::subtract(b, temp);
-               BigUnsigned::operator --();
+               mag.subtract(b.mag, mag);
+               mag--;
        }
 
        // Sign of the remainder is always the sign of the divisor b.
        sign = b.sign;
 
        // Set signs to zero as necessary.  (Thanks David Allen!)
-       if (len == 0)
+       if (mag.isZero())
                sign = zero;
-       if (q.len == 0)
+       if (q.mag.isZero())
                q.sign = zero;
 
        // WHEW!!!
@@ -515,7 +369,7 @@ void BigInteger::divideWithRemainder(const BigInteger &b, BigInteger &q) {
 void BigInteger::negate(const BigInteger &a) {
        DTRT_ALIASED(this == &a, negate(a));
        // Copy a's magnitude
-       BigUnsigned::operator =(a);
+       mag = a.mag;
        // Copy the opposite of a.sign
        sign = Sign(-a.sign);
 }
@@ -524,21 +378,13 @@ void BigInteger::negate(const BigInteger &a) {
 
 // Prefix increment
 void BigInteger::operator ++() {
-       switch (sign) {
-               case zero:
-               allocate(1);
-               sign = positive;
-               len = 1;
-               blk[0] = 1;
-               break;
-               case positive:
-               BigUnsigned::operator ++();
-               break;
-               case negative:
-               BigUnsigned::operator --();
-               if (len == 0)
+       if (sign == negative) {
+               mag--;
+               if (mag == 0)
                        sign = zero;
-               break;
+       } else {
+               mag++;
+               sign = positive; // if not already
        }
 }
 
@@ -549,21 +395,13 @@ void BigInteger::operator ++(int) {
 
 // Prefix decrement
 void BigInteger::operator --() {
-       switch (sign) {
-               case zero:
-               allocate(1);
-               sign = negative;
-               len = 1;
-               blk[0] = 1;
-               break;
-               case negative:
-               BigUnsigned::operator ++();
-               break;
-               case positive:
-               BigUnsigned::operator --();
-               if (len == 0)
+       if (sign == positive) {
+               mag--;
+               if (mag == 0)
                        sign = zero;
-               break;
+       } else {
+               mag++;
+               sign = negative;
        }
 }
 
index bfe3190..11be062 100644 (file)
@@ -3,81 +3,99 @@
 
 #include "BigUnsigned.hh"
 
-/*
- * A BigInteger object represents a signed integer of size
- * limited only by available memory.  A BigInteger can be
- * created from and converted back to most integral types,
- * and many math operations are defined on BigIntegers.
- *
- * The number is stored as a series of blocks in a
- * dynamically allocated array.  It is as if the number
- * were written digit by digit in base 2 ^ N, **where N is the
- * number of bits in an unsigned long.**
+/* A BigInteger object represents a signed integer of size limited only by
+ * available memory.  BigUnsigneds support most mathematical operators and can
+ * be converted to and from most primitive integer types.
  *
- * This class is derived from BigUnsigned, which represents
- * a large nonnegative integer.  BigUnsigned should be studied
- * first, as only new or different things are declared here.
- * Some things are redeclared so that they use the BigInteger
- * versions of methods, rather than the BigUnsigned versions.
- */
-
-class BigInteger : public BigUnsigned {
+ * A BigInteger is just an aggregate of a BigUnsigned and a sign.  (It is no
+ * longer derived from BigUnsigned because that led to harmful implicit
+ * conversions.) */
+class BigInteger {
 
-       // TYPES & CONSTANTS
 public:
-       enum Sign { negative = -1, zero = 0, positive = 1 }; // Enumeration for the sign of a BigInteger
+       typedef BigUnsigned::Blk Blk;
+       typedef BigUnsigned::Index Index;
+       typedef BigUnsigned::CmpRes CmpRes;
+       static const CmpRes
+               less    = BigUnsigned::less   ,
+               equal   = BigUnsigned::equal  ,
+               greater = BigUnsigned::greater;
+       // Enumeration for the sign of a BigInteger.
+       enum Sign { negative = -1, zero = 0, positive = 1 };
 
-       // FIELDS
 protected:
-       Sign sign; // The sign of this BigInteger
+       Sign sign;
+       BigUnsigned mag;
 
-       // MANAGEMENT
-protected:
-       BigInteger(Sign s, Index c) : BigUnsigned(0, c), sign(s) {}; // Creates a BigInteger with a sign and capacity
 public:
+       // Constructs zero.
+       BigInteger() : sign(zero), mag() {}
+
+       // Copy constructor
+       BigInteger(const BigInteger &x) : sign(x.sign), mag(x.mag) {};
+
+       // Assignment operator
+       void operator=(const BigInteger &x);
+
+       // Constructor that copies from a given array of blocks with a sign.
+       BigInteger(const Blk *b, Index blen, Sign s);
 
-       BigInteger() : BigUnsigned(), sign(zero) {} // Default constructor (value is 0)
-       BigInteger(const BigInteger &x) : BigUnsigned(x), sign(x.sign) {}; // Copy constructor
-       void operator=(const BigInteger &x); // Assignment operator
-       BigInteger(const Blk *b, Index l) : BigUnsigned(b, l) { // Constructor from an array of blocks
-               sign = (len == 0) ? zero : positive;
+       // Nonnegative constructor that copies from a given array of blocks.
+       BigInteger(const Blk *b, Index blen) : mag(b, blen) {
+               sign = mag.isZero() ? zero : positive;
        }
-       BigInteger(const Blk *b, Index l, Sign s); // Constructor from an array of blocks and a sign
-       BigInteger(const BigUnsigned &x) : BigUnsigned(x) { // Constructor from a BigUnsigned
-               sign = (len == 0) ? zero : positive;
+
+       // Constructor from a BigUnsigned and a sign
+       BigInteger(const BigUnsigned &x, Sign s);
+
+       // Nonnegative constructor from a BigUnsigned
+       BigInteger(const BigUnsigned &x) : mag(x) {
+               sign = mag.isZero() ? zero : positive;
        }
-       BigInteger(const BigUnsigned &x, Sign s); // Constructor from a BigUnsigned and a sign
-       // Constructors from integral types
+
+       // Constructors from primitive integer types
        BigInteger(unsigned long  x);
        BigInteger(         long  x);
        BigInteger(unsigned int   x);
        BigInteger(         int   x);
        BigInteger(unsigned short x);
        BigInteger(         short x);
-       // Note that a BigInteger can be converted to a BigUnsigned
-       // automatically; this takes its absolute value.
 
-       // CONVERTERS to integral types
-public:
-       operator unsigned long () const;
-       operator          long () const;
-       operator unsigned int  () const;
-       operator          int  () const;
-       operator unsigned short() const;
-       operator          short() const;
-
-       // PICKING APART
-       // These accessors can be used to get the pieces of the number
+       /* Converters to primitive integer types
+        * The implicit conversion operators caused trouble, so these are now
+        * named. */
+       unsigned long  toUnsignedLong () const;
+       long           toLong         () const;
+       unsigned int   toUnsignedInt  () const;
+       int            toInt          () const;
+       unsigned short toUnsignedShort() const;
+       short          toShort        () const;
+protected:
+       // Helper
+       template <class X> X convertToUnsignedPrimitive() const;
+       template <class X, class UX> X convertToSignedPrimitive() const;
 public:
-       Sign getSign() const;
+
+       // ACCESSORS
+       Sign getSign() const { return sign; }
+       /* The client can't do any harm by holding a read-only reference to the
+        * magnitude. */
+       const BigUnsigned &getMagnitude() const { return mag; }
+
+       // Some accessors that go through to the magnitude
+       Index getLength() const { return mag.getLength(); }
+       Index getCapacity() const { return mag.getCapacity(); }
+       Blk getBlock(Index i) const { return mag.getBlock(i); }
+       bool isZero() const { return sign == zero; } // A bit special
 
        // COMPARISONS
-public:
+
        // Compares this to x like Perl's <=>
        CmpRes compareTo(const BigInteger &x) const;
-       // Normal comparison operators
+
+       // Ordinary comparison operators
        bool operator ==(const BigInteger &x) const {
-               return sign == x.sign && BigUnsigned::operator ==(x);
+               return sign == x.sign && mag == x.mag;
        }
        bool operator !=(const BigInteger &x) const { return !operator ==(x); };
        bool operator < (const BigInteger &x) const { return compareTo(x) == less   ; }
@@ -85,78 +103,40 @@ public:
        bool operator >=(const BigInteger &x) const { return compareTo(x) != less   ; }
        bool operator > (const BigInteger &x) const { return compareTo(x) == greater; }
 
-       // PUT-HERE OPERATIONS
-       /* These store the result of the operation on the arguments into this.
-        * a.add(b, c) is equivalent to, but faster than, a = b + c.
-        * See explanation of "put-here operations" in BigUnsigned.cc . */
-public:
-       void add     (const BigInteger &a, const BigInteger &b); // Addition
-       void subtract(const BigInteger &a, const BigInteger &b); // Subtraction
-       void multiply(const BigInteger &a, const BigInteger &b); // Multiplication
-       /* Divisive stuff
-        * `a.divideWithRemainder(b, q)' is like `q = a / b, a %= b'.
-        * Semantics similar to Donald E. Knuth's are used for / and %,
-        * and these usually differ from the semantics of primitive-type
-        * / and % when negatives and/or zeroes are involved.
-        * Look in `BigInteger.cc' for details.
-        * `a.divideWithRemainder(b, a)' causes an exception: it doesn't make
-        * sense to write quotient and remainder into the same variable.
-        */
+       // OPERATORS -- See the discussion in BigUnsigned.hh.
+       void add     (const BigInteger &a, const BigInteger &b);
+       void subtract(const BigInteger &a, const BigInteger &b);
+       void multiply(const BigInteger &a, const BigInteger &b);
+       /* See the comment on BigUnsigned::divideWithRemainder.  Semantics
+        * differ from those of primitive integers when negatives and/or zeros
+        * are involved. */
        void divideWithRemainder(const BigInteger &b, BigInteger &q);
-       void divide(const BigInteger &a, const BigInteger &b) {
-               BigInteger a2(a);
-               a2.divideWithRemainder(b, *this);
-               // quotient now in *this
-               // don't care about remainder left in a2
-       }
-       void modulo(const BigInteger &a, const BigInteger &b) {
-               *this = a;
-               BigInteger q;
-               divideWithRemainder(b, q);
-               // remainder now in *this
-               // don't care about quotient left in q
-       }
-       void negate(const BigInteger &a); // Negative
-       // Some operations are inherently unsigned and are not
-       // redefined for BigIntegers.  Calling one of these on
-       // a BigInteger will convert it to a BigUnsigned,
-       // which takes its absolute value.
-
-       // NORMAL OPERATORS
-       // These perform the operation on this (to the left of the operator)
-       // and x (to the right of the operator) and return a new BigInteger with the result.
-public:
-       BigInteger operator +(const BigInteger &x) const; // Addition
-       BigInteger operator -(const BigInteger &x) const; // Subtraction
-       BigInteger operator *(const BigInteger &x) const; // Multiplication
-       BigInteger operator /(const BigInteger &x) const; // Division
-       BigInteger operator %(const BigInteger &x) const; // Modular reduction
-       BigInteger operator -(                   ) const; // Negative
-
-       // ASSIGNMENT OPERATORS
-       // These perform the operation on this and x, storing the result into this.
-public:
-       void operator +=(const BigInteger &x); // Addition
-       void operator -=(const BigInteger &x); // Subtraction
-       void operator *=(const BigInteger &x); // Multiplication
-       void operator /=(const BigInteger &x); // Division
-       void operator %=(const BigInteger &x); // Modular reduction
-       void flipSign();                       // Negative
+       void negate(const BigInteger &a);
+       
+       /* Bitwise operators are not provided for BigIntegers.  Use
+        * getMagnitude to get the magnitude and operate on that instead. */
+
+       BigInteger operator +(const BigInteger &x) const;
+       BigInteger operator -(const BigInteger &x) const;
+       BigInteger operator *(const BigInteger &x) const;
+       BigInteger operator /(const BigInteger &x) const;
+       BigInteger operator %(const BigInteger &x) const;
+       BigInteger operator -() const;
+
+       void operator +=(const BigInteger &x);
+       void operator -=(const BigInteger &x);
+       void operator *=(const BigInteger &x);
+       void operator /=(const BigInteger &x);
+       void operator %=(const BigInteger &x);
+       void flipSign();
 
        // INCREMENT/DECREMENT OPERATORS
-       // These increase or decrease the number by 1.  To discourage side effects,
-       // these do not return *this, so prefix and postfix behave the same.
-public:
-       void operator ++(   ); // Prefix  increment
-       void operator ++(int); // Postfix decrement
-       void operator --(   ); // Prefix  increment
-       void operator --(int); // Postfix decrement
-
+       void operator ++(   );
+       void operator ++(int);
+       void operator --(   );
+       void operator --(int);
 };
 
-// PICKING APART
-inline BigInteger::Sign BigInteger::getSign() const { return sign; }
-
 // NORMAL OPERATORS
 /* These create an object to hold the result and invoke
  * the appropriate put-here operation on it, passing
@@ -177,14 +157,16 @@ inline BigInteger BigInteger::operator *(const BigInteger &x) const {
        return ans;
 }
 inline BigInteger BigInteger::operator /(const BigInteger &x) const {
-       BigInteger ans;
-       ans.divide(*this, x);
-       return ans;
+       BigInteger q, r;
+       r = *this;
+       r.divideWithRemainder(x, q);
+       return q;
 }
 inline BigInteger BigInteger::operator %(const BigInteger &x) const {
-       BigInteger ans;
-       ans.modulo(*this, x);
-       return ans;
+       BigInteger q, r;
+       r = *this;
+       r.divideWithRemainder(x, q);
+       return r;
 }
 inline BigInteger BigInteger::operator -() const {
        BigInteger ans;
index 47c969b..ea38cfe 100644 (file)
@@ -1,4 +1,4 @@
-// This header file includes all the other header files.
+// This header file includes all of the library header files.
 
 #include "NumberlikeArray.hh"
 #include "BigUnsigned.hh"
index 87eb50b..3ac75dc 100644 (file)
@@ -12,8 +12,9 @@ std::string easyBUtoString(const BigUnsigned &x) {
 }
 
 std::string easyBItoString(const BigInteger &x) {
-       return (x.getSign() == BigInteger::negative) ?
-               (std::string("-") + easyBUtoString(x)) : (easyBUtoString(x));
+       return (x.getSign() == BigInteger::negative)
+               ? (std::string("-") + easyBUtoString(x.getMagnitude()))
+               : (easyBUtoString(x.getMagnitude()));
 }
 
 BigUnsigned easyStringToBU(const std::string &s) {
@@ -51,6 +52,6 @@ std::ostream &operator <<(std::ostream &os, const BigUnsigned &x) {
 std::ostream &operator <<(std::ostream &os, const BigInteger &x) {
        if (x.getSign() == BigInteger::negative)
                os << '-';
-       os << (const BigUnsigned &)(x);
+       os << x.getMagnitude();
        return os;
 }
index f9edfee..db407c5 100644 (file)
@@ -1,75 +1,20 @@
 #include "BigUnsigned.hh"
 
-// The "management" routines that used to be here are now in NumberlikeArray.hh.
+// Memory management definitions have moved to the bottom of NumberlikeArray.hh.
 
-/*
- * The steps for construction of a BigUnsigned
- * from an integral value x are as follows:
- * 1. If x is zero, create an empty BigUnsigned and stop.
- * 2. If x is negative, throw an exception.
- * 3. Allocate a one-block number array.
- * 4. If x is of a signed type, convert x to the unsigned
- *    type of the same length.
- * 5. Expand x to a Blk, and store it in the number array.
- *
- * Since 2005.01.06, NumberlikeArray uses `NULL' rather
- * than a real array if one of zero length is needed.
- * These constructors implicitly call NumberlikeArray's
- * default constructor, which sets `blk = NULL, cap = len = 0'.
- * So if the input number is zero, they can just return.
- * See remarks in `NumberlikeArray.hh'.
- */
-
-BigUnsigned::BigUnsigned(unsigned long x) {
-       if (x == 0)
-               ; // NumberlikeArray already did all the work
-       else {
-               cap = 1;
-               blk = new Blk[1];
-               len = 1;
-               blk[0] = Blk(x);
-       }
-}
-
-BigUnsigned::BigUnsigned(long x) {
-       if (x == 0)
-               ;
-       else if (x > 0) {
-               cap = 1;
-               blk = new Blk[1];
-               len = 1;
-               blk[0] = Blk(x);
-       } else
-       throw "BigUnsigned::BigUnsigned(long): Cannot construct a BigUnsigned from a negative number";
-}
-
-BigUnsigned::BigUnsigned(unsigned int x) {
-       if (x == 0)
-               ;
-       else {
-               cap = 1;
-               blk = new Blk[1];
-               len = 1;
-               blk[0] = Blk(x);
-       }
-}
+// CONSTRUCTION FROM PRIMITIVE INTEGERS
 
-BigUnsigned::BigUnsigned(int x) {
+/* Initialize this BigUnsigned from the given primitive integer.  The same
+ * pattern works for all primitive integer types, so I put it into a template to
+ * reduce code duplication.  (Don't worry: this is protected and we instantiate
+ * it only with primitive integer types.)  Type X could be signed, but x is
+ * known to be nonnegative. */
+template <class X>
+void BigUnsigned::initFromPrimitive(X x) {
        if (x == 0)
-               ;
-       else if (x > 0) {
-               cap = 1;
-               blk = new Blk[1];
-               len = 1;
-               blk[0] = Blk(x);
-       } else
-       throw "BigUnsigned::BigUnsigned(int): Cannot construct a BigUnsigned from a negative number";
-}
-
-BigUnsigned::BigUnsigned(unsigned short x) {
-       if (x == 0)
-               ;
+               ; // NumberlikeArray already initialized us to zero.
        else {
+               // Create a single block.  blk is NULL; no need to delete it.
                cap = 1;
                blk = new Blk[1];
                len = 1;
@@ -77,93 +22,80 @@ BigUnsigned::BigUnsigned(unsigned short x) {
        }
 }
 
-BigUnsigned::BigUnsigned(short x) {
-       if (x == 0)
-               ;
-       else if (x > 0) {
-               cap = 1;
-               blk = new Blk[1];
-               len = 1;
-               blk[0] = Blk(x);
-       } else
-       throw "BigUnsigned::BigUnsigned(short): Cannot construct a BigUnsigned from a negative number";
+/* Ditto, but first check that x is nonnegative.  I could have put the check in
+ * initFromPrimitive and let the compiler optimize it out for unsigned-type
+ * instantiations, but I wanted to avoid the warning stupidly issued by g++ for
+ * a condition that is constant in *any* instantiation, even if not in all. */
+template <class X>
+void BigUnsigned::initFromSignedPrimitive(X x) {
+       if (x < 0)
+               throw "BigUnsigned constructor: "
+                       "Cannot construct a BigUnsigned from a negative number";
+       else
+               initFromPrimitive(x);
 }
 
-// CONVERTERS
-/*
- * The steps for conversion of a BigUnsigned to an
- * integral type are as follows:
- * 1. If the BigUnsigned is zero, return zero.
- * 2. If it is more than one block long or its lowest
- *    block has bits set out of the range of the target
- *    type, throw an exception.
- * 3. Otherwise, convert the lowest block to the
- *    target type and return it.
- */
+BigUnsigned::BigUnsigned(unsigned long  x) { initFromPrimitive      (x); }
+BigUnsigned::BigUnsigned(unsigned int   x) { initFromPrimitive      (x); }
+BigUnsigned::BigUnsigned(unsigned short x) { initFromPrimitive      (x); }
+BigUnsigned::BigUnsigned(         long  x) { initFromSignedPrimitive(x); }
+BigUnsigned::BigUnsigned(         int   x) { initFromSignedPrimitive(x); }
+BigUnsigned::BigUnsigned(         short x) { initFromSignedPrimitive(x); }
 
-namespace {
-       // These masks are used to test whether a Blk has bits
-       // set out of the range of a smaller integral type.  Note
-       // that this range is not considered to include the sign bit.
-       const BigUnsigned::Blk  lMask = ~0 >> 1;
-       const BigUnsigned::Blk uiMask = (unsigned int)(~0);
-       const BigUnsigned::Blk  iMask = uiMask >> 1;
-       const BigUnsigned::Blk usMask = (unsigned short)(~0);
-       const BigUnsigned::Blk  sMask = usMask >> 1;
-}
+// CONVERSION TO PRIMITIVE INTEGERS
 
-BigUnsigned::operator unsigned long() const {
+/* Template with the same idea as initFromPrimitive.  This might be slightly
+ * slower than the previous version with the masks, but it's much shorter and
+ * clearer, which is the library's stated goal. */
+template <class X>
+X BigUnsigned::convertToPrimitive() const {
        if (len == 0)
+               // The number is zero; return zero.
                return 0;
-       else if (len == 1)
-               return (unsigned long) blk[0];
-       else
-               throw "BigUnsigned::operator unsigned long: Value is too big for an unsigned long";
+       else if (len == 1) {
+               // The single block might fit in an X.  Try the conversion.
+               X x = X(blk[0]);
+               // Make sure the result accurately represents the block.
+               if (Blk(x) == blk[0])
+                       // Successful conversion.
+                       return x;
+               // Otherwise fall through.
+       }
+       throw "BigUnsigned::to<Primitive>: "
+               "Value is too big to fit in the requested type";
 }
 
-BigUnsigned::operator long() const {
-       if (len == 0)
-               return 0;
-       else if (len == 1 && (blk[0] & lMask) == blk[0])
-               return (long) blk[0];
+/* Wrap the above in an x >= 0 test to make sure we got a nonnegative result,
+ * not a negative one that happened to convert back into the correct nonnegative
+ * one.  (E.g., catch incorrect conversion of 2^31 to the long -2^31.)  Again,
+ * separated to avoid a g++ warning. */
+template <class X>
+X BigUnsigned::convertToSignedPrimitive() const {
+       X x = convertToPrimitive<X>();
+       if (x >= 0)
+               return x;
        else
-               throw "BigUnsigned::operator long: Value is too big for a long";
+               throw "BigUnsigned::to(Primitive): "
+                       "Value is too big to fit in the requested type";
 }
 
-BigUnsigned::operator unsigned int() const {
-       if (len == 0)
-               return 0;
-       else if (len == 1 && (blk[0] & uiMask) == blk[0])
-               return (unsigned int) blk[0];
-       else
-               throw "BigUnsigned::operator unsigned int: Value is too big for an unsigned int";
+unsigned long BigUnsigned::toUnsignedLong() const {
+       return convertToPrimitive<unsigned long>();
 }
-
-BigUnsigned::operator int() const {
-       if (len == 0)
-               return 0;
-       else if (len == 1 && (blk[0] & iMask) == blk[0])
-               return (int) blk[0];
-       else
-               throw "BigUnsigned::operator int: Value is too big for an int";
+unsigned int BigUnsigned::toUnsignedInt() const {
+       return convertToPrimitive<unsigned int>();
 }
-
-BigUnsigned::operator unsigned short() const {
-       if (len == 0)
-               return 0;
-       else if (len == 1 && (blk[0] & usMask) == blk[0])
-               return (unsigned short) blk[0];
-       else
-               throw "BigUnsigned::operator unsigned short: Value is too big for an unsigned short";
+unsigned short BigUnsigned::toUnsignedShort() const {
+       return convertToPrimitive<unsigned short>();
 }
-
-BigUnsigned::operator short() const {
-       if (len == 0)
-               return 0;
-       else if (len == 1 && (blk[0] & sMask) == blk[0])
-               return (short) blk[0];
-       else
-               throw "BigUnsigned::operator short: Value is too big for a short";
+long BigUnsigned::toLong() const {
+       return convertToSignedPrimitive<long>();
+}
+int BigUnsigned::toInt() const {
+       return convertToSignedPrimitive<int>();
+}
+short BigUnsigned::toShort() const {
+       return convertToSignedPrimitive<short>();
 }
 
 // COMPARISON
@@ -190,32 +122,10 @@ BigUnsigned::CmpRes BigUnsigned::compareTo(const BigUnsigned &x) const {
        }
 }
 
-// PUT-HERE OPERATIONS
-
-/*
- * Below are implementations of the four basic arithmetic operations
- * for `BigUnsigned's.  Their purpose is to use a mechanism that can
- * calculate the sum, difference, product, and quotient/remainder of
- * two individual blocks in order to calculate the sum, difference,
- * product, and quotient/remainder of two multi-block BigUnsigned
- * numbers.
- *
- * As alluded to in the comment before class `BigUnsigned',
- * these algorithms bear a remarkable similarity (in purpose, if
- * not in implementation) to the way humans operate on big numbers.
- * The built-in `+', `-', `*', `/' and `%' operators are analogous
- * to elementary-school ``math facts'' and ``times tables''; the
- * four routines below are analogous to ``long division'' and its
- * relatives.  (Only a computer can ``memorize'' a times table with
- * 18446744073709551616 entries!  (For 32-bit blocks.))
- *
- * The discovery of these four algorithms, called the ``classical
- * algorithms'', marked the beginning of the study of computer science.
- * See Section 4.3.1 of Knuth's ``The Art of Computer Programming''.
- */
+// COPY-LESS OPERATIONS
 
 /*
- * On most calls to put-here operations, it's safe to read the inputs little by
+ * On most calls to copy-less operations, it's safe to read the inputs little by
  * little and write the outputs little by little.  However, if one of the
  * inputs is coming from the same variable into which the output is to be
  * stored (an "aliased" call), we risk overwriting the input before we read it.
@@ -242,7 +152,8 @@ BigUnsigned::CmpRes BigUnsigned::compareTo(const BigUnsigned &x) const {
                return; \
        }
 
-// Addition
+
+
 void BigUnsigned::add(const BigUnsigned &a, const BigUnsigned &b) {
        DTRT_ALIASED(this == &a || this == &b, add(a, b));
        // If one argument is zero, copy the other.
@@ -303,15 +214,16 @@ void BigUnsigned::add(const BigUnsigned &a, const BigUnsigned &b) {
                len--;
 }
 
-// Subtraction
 void BigUnsigned::subtract(const BigUnsigned &a, const BigUnsigned &b) {
        DTRT_ALIASED(this == &a || this == &b, subtract(a, b));
-       // If b is zero, copy a.  If a is shorter than b, the result is negative.
        if (b.len == 0) {
+               // If b is zero, copy a.
                operator =(a);
                return;
        } else if (a.len < b.len)
-       throw "BigUnsigned::subtract: Negative result in unsigned calculation";
+               // If a is shorter than b, the result is negative.
+               throw "BigUnsigned::subtract: "
+                       "Negative result in unsigned calculation";
        // Some variables...
        bool borrowIn, borrowOut;
        Blk temp;
@@ -322,7 +234,8 @@ void BigUnsigned::subtract(const BigUnsigned &a, const BigUnsigned &b) {
        // For each block index that is present in both inputs...
        for (i = 0, borrowIn = false; i < b.len; i++) {
                temp = a.blk[i] - b.blk[i];
-               // If a reverse rollover occurred, the result is greater than the block from a.
+               // If a reverse rollover occurred,
+               // the result is greater than the block from a.
                borrowOut = (temp > a.blk[i]);
                // Handle an incoming borrow
                if (borrowIn) {
@@ -338,14 +251,16 @@ void BigUnsigned::subtract(const BigUnsigned &a, const BigUnsigned &b) {
                borrowIn = (a.blk[i] == 0);
                blk[i] = a.blk[i] - 1;
        }
-       // If there's still a borrow, the result is negative.
-       // Throw an exception, but zero out this object first just in case.
+       /* If there's still a borrow, the result is negative.
+        * Throw an exception, but zero out this object so as to leave it in a
+        * predictable state. */
        if (borrowIn) {
                len = 0;
                throw "BigUnsigned::subtract: Negative result in unsigned calculation";
-       } else // Copy over the rest of the blocks
-       for (; i < a.len; i++)
-               blk[i] = a.blk[i];
+       } else
+               // Copy over the rest of the blocks
+               for (; i < a.len; i++)
+                       blk[i] = a.blk[i];
        // Zap leading zeros
        zapLeadingZeros();
 }
@@ -353,7 +268,7 @@ void BigUnsigned::subtract(const BigUnsigned &a, const BigUnsigned &b) {
 /*
  * About the multiplication and division algorithms:
  *
- * I searched unsucessfully for fast built-in operations like the `b_0'
+ * I searched unsucessfully for fast C++ built-in operations like the `b_0'
  * and `c_0' Knuth describes in Section 4.3.1 of ``The Art of Computer
  * Programming'' (replace `place' by `Blk'):
  *
@@ -415,7 +330,6 @@ inline BigUnsigned::Blk getShiftedBlock(const BigUnsigned &num,
        return part1 | part2;
 }
 
-// Multiplication
 void BigUnsigned::multiply(const BigUnsigned &a, const BigUnsigned &b) {
        DTRT_ALIASED(this == &a || this == &b, multiply(a, b));
        // If either a or b is zero, set to zero.
@@ -489,35 +403,25 @@ void BigUnsigned::multiply(const BigUnsigned &a, const BigUnsigned &b) {
 
 /*
  * DIVISION WITH REMAINDER
- * The functionality of divide, modulo, and %= is included in this one monstrous call,
- * which deserves some explanation.
- *
- * The division *this / b is performed.
- * Afterwards, q has the quotient, and *this has the remainder.
- * Thus, a call is like q = *this / b, *this %= b.
- *
- * This seemingly bizarre pattern of inputs and outputs has a justification.  The
- * ``put-here operations'' are supposed to be fast.  Therefore, they accept inputs
- * and provide outputs in the most convenient places so that no value ever needs
- * to be copied in its entirety.  That way, the client can perform exactly the
- * copying it needs depending on where the inputs are and where it wants the output.
- * A better name for this function might be "modWithQuotient", but I would rather
- * not change the name now.
+ * This monstrous function mods *this by the given divisor b while storing the
+ * quotient in the given object q; at the end, *this contains the remainder.
+ * The seemingly bizarre pattern of inputs and outputs was chosen so that the
+ * function copies as little as possible (since it is implemented by repeated
+ * subtraction of multiples of b from *this).
+ * 
+ * "modWithQuotient" might be a better name for this function, but I would
+ * rather not change the name now.
  */
 void BigUnsigned::divideWithRemainder(const BigUnsigned &b, BigUnsigned &q) {
-       /*
-        * Defending against aliased calls is a bit tricky because we are
-        * writing to both *this and q.
+       /* Defending against aliased calls is more complex than usual because we
+        * are writing to both *this and q.
         * 
         * It would be silly to try to write quotient and remainder to the
-        * same variable.  Rule that out right away.
-        */
+        * same variable.  Rule that out right away. */
        if (this == &q)
                throw "BigUnsigned::divideWithRemainder: Cannot write quotient and remainder into the same variable";
-       /*
-        * Now *this and q are separate, so the only concern is that b might be
-        * aliased to one of them.  If so, use a temporary copy of b.
-        */
+       /* Now *this and q are separate, so the only concern is that b might be
+        * aliased to one of them.  If so, use a temporary copy of b. */
        if (this == &b || &q == &b) {
                BigUnsigned tmpB(b);
                divideWithRemainder(tmpB, q);
@@ -525,13 +429,13 @@ void BigUnsigned::divideWithRemainder(const BigUnsigned &b, BigUnsigned &q) {
        }
 
        /*
-        * Note that the mathematical definition of mod (I'm trusting Knuth) is somewhat
-        * different from the way the normal C++ % operator behaves in the case of division by 0.
-        * This function does it Knuth's way.
+        * Knuth's definition of mod (which this function uses) is somewhat
+        * different from the C++ definition of % in case of division by 0.
         *
-        * We let a / 0 == 0 (it doesn't matter) and a % 0 == a, no exceptions thrown.
-        * This allows us to preserve both Knuth's demand that a mod 0 == a
-        * and the useful property that (a / b) * b + (a % b) == a.
+        * We let a / 0 == 0 (it doesn't matter much) and a % 0 == a, no
+        * exceptions thrown.  This allows us to preserve both Knuth's demand
+        * that a mod 0 == a and the useful property that
+        * (a / b) * b + (a % b) == a.
         */
        if (b.len == 0) {
                q.len = 0;
@@ -547,36 +451,28 @@ void BigUnsigned::divideWithRemainder(const BigUnsigned &b, BigUnsigned &q) {
                return;
        }
 
-       /*
-        * At this point we know *this > b > 0.  (Whew!)
-        */
+       // At this point we know (*this).len >= b.len > 0.  (Whew!)
 
        /*
         * Overall method:
         *
         * For each appropriate i and i2, decreasing:
-        *    Try to subtract (b << (i blocks and i2 bits)) from *this.
-        *        (`work2' holds the result of this subtraction.)
-        *    If the result is nonnegative:
+        *    Subtract (b << (i blocks and i2 bits)) from *this, storing the
+        *      result in subtractBuf.
+        *    If the subtraction succeeds with a nonnegative result:
         *        Turn on bit i2 of block i of the quotient q.
-        *        Save the result of the subtraction back into *this.
-        *    Otherwise:
-        *        Bit i2 of block i remains off, and *this is unchanged.
+        *        Copy subtractBuf back into *this.
+        *    Otherwise bit i2 of block i remains off, and *this is unchanged.
         * 
         * Eventually q will contain the entire quotient, and *this will
         * be left with the remainder.
         *
-        * We use work2 to temporarily store the result of a subtraction.
-        * work2[x] corresponds to blk[x], not blk[x+i], since 2005.01.11.
-        * If the subtraction is successful, we copy work2 back to blk.
-        * (There's no `work1'.  In a previous version, when division was
-        * coded for a read-only dividend, `work1' played the role of
-        * the here-modifiable `*this' and got the remainder.)
-        *
-        * We never touch the i lowest blocks of either blk or work2 because
-        * they are unaffected by the subtraction: we are subtracting
-        * (b << (i blocks and i2 bits)), which ends in at least `i' zero blocks.
-        */
+        * subtractBuf[x] corresponds to blk[x], not blk[x+i], since 2005.01.11.
+        * But on a single iteration, we don't touch the i lowest blocks of blk
+        * (and don't use those of subtractBuf) because these blocks are
+        * unaffected by the subtraction: we are subtracting
+        * (b << (i blocks and i2 bits)), which ends in at least `i' zero
+        * blocks. */
        // Variables for the calculation
        Index i, j, k;
        unsigned int i2;
@@ -591,19 +487,17 @@ void BigUnsigned::divideWithRemainder(const BigUnsigned &b, BigUnsigned &q) {
         * and then we'll try to compare these extra bits with
         * a nonexistent block to the left of the dividend.  The
         * extra zero block ensures sensible behavior; we need
-        * an extra block in `work2' for exactly the same reason.
-        *
-        * See below `divideWithRemainder' for the interesting and
-        * amusing story of this section of code.
+        * an extra block in `subtractBuf' for exactly the same reason.
         */
        Index origLen = len; // Save real length.
-       // 2006.05.03: Copy the number and then change the length!
-       allocateAndCopy(len + 1); // Get the space.
-       len++; // Increase the length.
-       blk[origLen] = 0; // Zero the extra block.
+       /* To avoid an out-of-bounds access in case of reallocation, allocate
+        * first and then increment the logical length. */
+       allocateAndCopy(len + 1);
+       len++;
+       blk[origLen] = 0; // Zero the added block.
 
-       // work2 holds part of the result of a subtraction; see above.
-       Blk *work2 = new Blk[len];
+       // subtractBuf holds part of the result of a subtraction; see above.
+       Blk *subtractBuf = new Blk[len];
 
        // Set preliminary length for quotient and make room
        q.len = origLen - b.len + 1;
@@ -624,7 +518,7 @@ void BigUnsigned::divideWithRemainder(const BigUnsigned &b, BigUnsigned &q) {
                        i2--;
                        /*
                         * Subtract b, shifted left i blocks and i2 bits, from *this,
-                        * and store the answer in work2.  In the for loop, `k == i + j'.
+                        * and store the answer in subtractBuf.  In the for loop, `k == i + j'.
                         *
                         * Compare this to the middle section of `multiply'.  They
                         * are in many ways analogous.  See especially the discussion
@@ -637,31 +531,31 @@ void BigUnsigned::divideWithRemainder(const BigUnsigned &b, BigUnsigned &q) {
                                        borrowOut |= (temp == 0);
                                        temp--;
                                }
-                               // Since 2005.01.11, indices of `work2' directly match those of `blk', so use `k'.
-                               work2[k] = temp; 
+                               // Since 2005.01.11, indices of `subtractBuf' directly match those of `blk', so use `k'.
+                               subtractBuf[k] = temp; 
                                borrowIn = borrowOut;
                        }
                        // No more extra iteration to deal with `bHigh'.
                        // Roll-over a borrow as necessary.
                        for (; k < origLen && borrowIn; k++) {
                                borrowIn = (blk[k] == 0);
-                               work2[k] = blk[k] - 1;
+                               subtractBuf[k] = blk[k] - 1;
                        }
                        /*
                         * If the subtraction was performed successfully (!borrowIn),
                         * set bit i2 in block i of the quotient.
                         *
-                        * Then, copy the portion of work2 filled by the subtraction
+                        * Then, copy the portion of subtractBuf filled by the subtraction
                         * back to *this.  This portion starts with block i and ends--
                         * where?  Not necessarily at block `i + b.len'!  Well, we
-                        * increased k every time we saved a block into work2, so
-                        * the region of work2 we copy is just [i, k).
+                        * increased k every time we saved a block into subtractBuf, so
+                        * the region of subtractBuf we copy is just [i, k).
                         */
                        if (!borrowIn) {
                                q.blk[i] |= (Blk(1) << i2);
                                while (k > i) {
                                        k--;
-                                       blk[k] = work2[k];
+                                       blk[k] = subtractBuf[k];
                                }
                        } 
                }
@@ -671,55 +565,18 @@ void BigUnsigned::divideWithRemainder(const BigUnsigned &b, BigUnsigned &q) {
                q.len--;
        // Zap any/all leading zeros in remainder
        zapLeadingZeros();
-       // Deallocate temporary array.
+       // Deallocate subtractBuf.
        // (Thanks to Brad Spencer for noticing my accidental omission of this!)
-       delete [] work2;
-
+       delete [] subtractBuf;
 }
-/*
- * The out-of-bounds accesses story:
- * 
- * On 2005.01.06 or 2005.01.07 (depending on your time zone),
- * Milan Tomic reported out-of-bounds memory accesses in
- * the Big Integer Library.  To investigate the problem, I
- * added code to bounds-check every access to the `blk' array
- * of a `NumberlikeArray'.
- *
- * This gave me warnings that fell into two categories of false
- * positives.  The bounds checker was based on length, not
- * capacity, and in two places I had accessed memory that I knew
- * was inside the capacity but that wasn't inside the length:
- * 
- * (1) The extra zero block at the left of `*this'.  Earlier
- * versions said `allocateAndCopy(len + 1); blk[len] = 0;'
- * but did not increment `len'.
- *
- * (2) The entire digit array in the conversion constructor
- * ``BigUnsignedInABase(BigUnsigned)''.  It was allocated with
- * a conservatively high capacity, but the length wasn't set
- * until the end of the constructor.
- *
- * To simplify matters, I changed both sections of code so that
- * all accesses occurred within the length.  The messages went
- * away, and I told Milan that I couldn't reproduce the problem,
- * sending a development snapshot of the bounds-checked code.
- *
- * Then, on 2005.01.09-10, he told me his debugger still found
- * problems, specifically at the line `delete [] work2'.
- * It was `work2', not `blk', that was causing the problems;
- * this possibility had not occurred to me at all.  In fact,
- * the problem was that `work2' needed an extra block just
- * like `*this'.  Go ahead and laugh at me for finding (1)
- * without seeing what was actually causing the trouble.  :-)
- *
- * The 2005.01.11 version fixes this problem.  I hope this is
- * the last of my memory-related bloopers.  So this is what
- * starts happening to your C++ code if you use Java too much!
- */
 
-// Bitwise and
+/* BITWISE OPERATORS
+ * These are straightforward blockwise operations except that they differ in
+ * the output length and the necessity of zapLeadingZeros. */
+
 void BigUnsigned::bitAnd(const BigUnsigned &a, const BigUnsigned &b) {
        DTRT_ALIASED(this == &a || this == &b, bitAnd(a, b));
+       // The bitwise & can't be longer than either operand.
        len = (a.len >= b.len) ? b.len : a.len;
        allocate(len);
        Index i;
@@ -728,7 +585,6 @@ void BigUnsigned::bitAnd(const BigUnsigned &a, const BigUnsigned &b) {
        zapLeadingZeros();
 }
 
-// Bitwise or
 void BigUnsigned::bitOr(const BigUnsigned &a, const BigUnsigned &b) {
        DTRT_ALIASED(this == &a || this == &b, bitOr(a, b));
        Index i;
@@ -746,9 +602,9 @@ void BigUnsigned::bitOr(const BigUnsigned &a, const BigUnsigned &b) {
        for (; i < a2->len; i++)
                blk[i] = a2->blk[i];
        len = a2->len;
+       // Doesn't need zapLeadingZeros.
 }
 
-// Bitwise xor
 void BigUnsigned::bitXor(const BigUnsigned &a, const BigUnsigned &b) {
        DTRT_ALIASED(this == &a || this == &b, bitXor(a, b));
        Index i;
@@ -769,7 +625,6 @@ void BigUnsigned::bitXor(const BigUnsigned &a, const BigUnsigned &b) {
        zapLeadingZeros();
 }
 
-// Bitwise shift left
 void BigUnsigned::bitShiftLeft(const BigUnsigned &a, unsigned int b) {
        DTRT_ALIASED(this == &a, bitShiftLeft(a, b));
        Index shiftBlocks = b / N;
@@ -787,7 +642,6 @@ void BigUnsigned::bitShiftLeft(const BigUnsigned &a, unsigned int b) {
                len--;
 }
 
-// Bitwise shift right
 void BigUnsigned::bitShiftRight(const BigUnsigned &a, unsigned int b) {
        DTRT_ALIASED(this == &a, bitShiftRight(a, b));
        // This calculation is wacky, but expressing the shift as a left bit shift
@@ -825,9 +679,7 @@ void BigUnsigned::operator ++() {
                carry = (blk[i] == 0);
        }
        if (carry) {
-               // Matt fixed a bug 2004.12.24: next 2 lines used to say allocateAndCopy(len + 1)
-               // Matt fixed another bug 2006.04.24:
-               // old number only has len blocks, so copy before increasing length
+               // Allocate and then increase length, as in divideWithRemainder
                allocateAndCopy(len + 1);
                len++;
                blk[i] = 1;
index d5557c7..624c87f 100644 (file)
 
 #include "NumberlikeArray.hh"
 
-/*
- * A BigUnsigned object represents a nonnegative integer of size
- * limited only by available memory.  A BigUnsigned can be
- * created from and converted back to most integral types,
- * and many math operations are defined on BigUnsigneds.
+/* A BigUnsigned object represents a nonnegative integer of size limited only by
+ * available memory.  BigUnsigneds support most mathematical operators and can
+ * be converted to and from most primitive integer types.
  *
- * The number is stored as a series of blocks in a
- * dynamically allocated array.  It is as if the number
- * were written digit by digit in base 2 ^ N, **where N is the
- * number of bits in an unsigned long.**
- *
- * The memory-management details that used to be in here have
- * been moved into NumberlikeArray, which BigUnsigned now derives from.
- * `(NlA)' means that member(s) are declared identically in NumberlikeArray.
- * Such members are either redeclared here to make them public or are
- * here, commented out, for reference.
- */
-
+ * The number is stored as a NumberlikeArray of unsigned longs as if it were
+ * written in base 256^sizeof(unsigned long).  The least significant block is
+ * first, and the length is such that the most significant block is nonzero. */
 class BigUnsigned : protected NumberlikeArray<unsigned long> {
 
-       // TYPES & CONSTANTS
 public:
-       enum CmpRes { less = -1, equal = 0, greater = 1 }; // Enumeration for the result of a comparison
-       typedef unsigned long Blk; // The number block type that BigUnsigneds are built from
-       typedef NumberlikeArray<Blk>::Index Index; // (NlA) Type for the index of a block in the array
-       NumberlikeArray<Blk>::N; // Number of bits in a Blk
+       // Enumeration for the result of a comparison.
+       enum CmpRes { less = -1, equal = 0, greater = 1 };
 
-       /*
-       // FIELDS
-protected:
-       Index cap; // (NlA) The current allocated capacity of this BigUnsigned (in blocks)
-       Index len; // (NlA) The actual length of the number stored in this BigUnsigned (in blocks)
-       Blk *blk; // (NlA) Dynamically allocated array of the number blocks
-       */
+       // BigUnsigneds are built with a Blk type of unsigned long.
+       typedef unsigned long Blk;
 
-       // MANAGEMENT
-protected:
-       // These members generally defer to those in NumberlikeArray, possibly with slight changes.
-       // It might be nice if one could request that constructors be inherited in C++.
+       typedef NumberlikeArray<Blk>::Index Index;
+       NumberlikeArray<Blk>::N;
 
-       BigUnsigned(int, Index c) : NumberlikeArray<Blk>(0, c) {} // Creates a BigUnsigned with a capacity
+protected:
+       // Creates a BigUnsigned with a capacity; for internal use.
+       BigUnsigned(int, Index c) : NumberlikeArray<Blk>(0, c) {}
 
-       void zapLeadingZeros() { // Decreases len to eliminate leading zeros
+       // Decreases len to eliminate any leading zero blocks.
+       void zapLeadingZeros() { 
                while (len > 0 && blk[len - 1] == 0)
                        len--;
        }
 
-       //void allocate(Index c); // (NlA) Ensures the number array has at least the indicated capacity, maybe discarding contents
-       //void allocateAndCopy(Index c); // (NlA) Ensures the number array has at least the indicated capacity, preserving its contents
-
 public:
-       BigUnsigned() : NumberlikeArray<Blk>() {} // Default constructor (value is 0)
-       BigUnsigned(const BigUnsigned &x) : NumberlikeArray<Blk>(x) {} // Copy constructor
+       // Constructs zero.
+       BigUnsigned() : NumberlikeArray<Blk>() {}
+
+       // Copy constructor
+       BigUnsigned(const BigUnsigned &x) : NumberlikeArray<Blk>(x) {}
 
-       void operator=(const BigUnsigned &x) { // Assignment operator
+       // Assignment operator
+       void operator=(const BigUnsigned &x) {
                NumberlikeArray<Blk>::operator =(x);
        }
 
-       BigUnsigned(const Blk *b, Index l) : NumberlikeArray<Blk>(b, l) { // Constructor from an array of blocks
+       // Constructor that copies from a given array of blocks.
+       BigUnsigned(const Blk *b, Index blen) : NumberlikeArray<Blk>(b, blen) {
+               // Eliminate any leading zeros we may have been passed.
                zapLeadingZeros();
        }
 
-       // Constructors from integral types
+       // Destructor.  NumberlikeArray does the delete for us.
+       ~BigUnsigned() {}
+       
+       // Constructors from primitive integer types
        BigUnsigned(unsigned long  x);
        BigUnsigned(         long  x);
        BigUnsigned(unsigned int   x);
        BigUnsigned(         int   x);
        BigUnsigned(unsigned short x);
        BigUnsigned(         short x);
-       ~BigUnsigned() {} // Destructor
-
-       // CONVERTERS to integral types
+protected:
+       // Helpers
+       template <class X> void initFromPrimitive(X x);
+       template <class X> void initFromSignedPrimitive(X x);
 public:
-       operator unsigned long () const;
-       operator          long () const;
-       operator unsigned int  () const;
-       operator          int  () const;
-       operator unsigned short() const;
-       operator          short() const;
-
-       // PICKING APART
-       // These accessors can be used to get the pieces of the number
+
+       /* Converters to primitive integer types
+        * The implicit conversion operators caused trouble, so these are now
+        * named. */
+       unsigned long  toUnsignedLong () const;
+       long           toLong         () const;
+       unsigned int   toUnsignedInt  () const;
+       int            toInt          () const;
+       unsigned short toUnsignedShort() const;
+       short          toShort        () const;
+protected:
+       // Helpers
+       template <class X> X convertToSignedPrimitive() const;
+       template <class X> X convertToPrimitive() const;
 public:
+
+       // ACCESSORS
+
+       // Expose these from NumberlikeArray directly.
        NumberlikeArray<Blk>::getCapacity;
        NumberlikeArray<Blk>::getLength;
-       // Note that getBlock returns 0 if the block index is beyond the length of the number.
-       // A routine that uses this accessor can safely assume a BigUnsigned has 0s infinitely to the left.
+
+       /* Returns the requested block, or 0 if it is beyond the length (as if
+        * the number had 0s infinitely to the left). */
        Blk getBlock(Index i) const { return i >= len ? 0 : blk[i]; }
-       // Note how we replace one level of abstraction with another.  Isn't that neat?
-       bool isZero() const { return NumberlikeArray<Blk>::isEmpty(); } // Often convenient for loops
+
+       // The number is zero if and only if the canonical length is zero.
+       bool isZero() const { return NumberlikeArray<Blk>::isEmpty(); }
 
        // COMPARISONS
-public:
+
        // Compares this to x like Perl's <=>
        CmpRes compareTo(const BigUnsigned &x) const;
-       // Normal comparison operators
-       // Bug fixed 2006.04.24: Only we, not the user, can pass a BigUnsigned off as a
-       // NumberlikeArray, so we have to wrap == and !=.
+
+       // Ordinary comparison operators
        bool operator ==(const BigUnsigned &x) const {
                return NumberlikeArray<Blk>::operator ==(x);
        }
@@ -117,130 +116,125 @@ public:
         * Here ``big-integer'' refers to BigInteger or BigUnsigned.
         *
         * (1) Overloaded ``return-by-value'' operators:
-        *     +, -, *, /, %, unary -.
-        * Big-integer code using these operators looks identical to
-        * code using the primitive integer types.  These operators take
-        * one or two big-integer inputs and return a big-integer result,
-        * which can then be assigned to a BigInteger variable or used
-        * in an expression.  Example:
+        *     +, -, *, /, %, unary -, &, |, ^, <<, >>.
+        * Big-integer code using these operators looks identical to code using
+        * the primitive integer types.  These operators take one or two
+        * big-integer inputs and return a big-integer result, which can then
+        * be assigned to a BigInteger variable or used in an expression.
+        * Example:
         *     BigInteger a(1), b = 1;
         *     BigInteger c = a + b;
         *
         * (2) Overloaded assignment operators:
-        *     +=, -=, *=, /=, %=, &=, |=, ^=, ++, --, flipSign.
-        * Again, these are used on big integers just like on ints.
-        * They take one writable big integer that both provides an
-        * operand and receives a result.  The first eight also take
-        * a second read-only operand.  Example:
+        *     +=, -=, *=, /=, %=, flipSign, &=, |=, ^=, <<=, >>=, ++, --.
+        * Again, these are used on big integers just like on ints.  They take
+        * one writable big integer that both provides an operand and receives a
+        * result.  Most also take a second read-only operand.
+        * Example:
         *     BigInteger a(1), b(1);
         *     a += b;
         *
-        * (3) ``Put-here'' operations: `add', `subtract', etc.
-        * Using a return-by-value or assignment operator generally involves
-        * copy constructions and/or assignments.  The ``put-here'' operations
-        * require none, but they are more of a hassle to use.  Most take two
-        * read-only operands and save the result in the calling object `*this',
-        * whose previous value is ignored.  `divideWithRemainder' is an exception.
-        * <<< NOTE >>>: Put-here operations do not return a value: they don't need to!!
+        * (3) Copy-less operations: `add', `subtract', etc.
+        * These named methods take operands as arguments and store the result
+        * in the receiver (*this), avoiding unnecessary copies and allocations.
+        * `divideWithRemainder' is special: it both takes the dividend from and
+        * stores the remainder into the receiver, and it takes a separate
+        * object in which to store the quotient.  NOTE: If you are wondering
+        * why these don't return a value, you probably mean to use the
+        * overloaded return-by-value operators instead.
+        * 
         * Examples:
         *     BigInteger a(43), b(7), c, d;
+        *
         *     c = a + b;   // Now c == 50.
-        *     c.add(a, b); // Same effect but without the two bulk-copies.
-        *     c.divideWithRemainder(b, d); // 50 / 7; now d == 7 (quotient) and c == 1 (remainder).
-        *     a.add(a, b); // ``Aliased'' calls now do the right thing using a
-        *              // temporary copy, but see note on divideWithRemainder.
+        *     c.add(a, b); // Same effect but without the two copies.
+        *
+        *     c.divideWithRemainder(b, d);
+        *     // 50 / 7; now d == 7 (quotient) and c == 1 (remainder).
+        *
+        *     // ``Aliased'' calls now do the right thing using a temporary
+        *     // copy, but see note on `divideWithRemainder'.
+        *     a.add(a, b); 
         */
 
-       // PUT-HERE OPERATIONS
-public:
-       /* These 3: Two read-only operands as arguments.  Result left in *this. */
-       void add(const BigUnsigned &a, const BigUnsigned &b); // Addition
-       void subtract(const BigUnsigned &a, const BigUnsigned &b); // Subtraction
-       void multiply(const BigUnsigned &a, const BigUnsigned &b); // Multiplication
-       /* Divisive stuff
-        * `a.divideWithRemainder(b, q)' is like `q = a / b, a %= b'.
-        * Semantics similar to Donald E. Knuth's are used for / and %,
-        * and these differ from the semantics of primitive-type
-        * / and % under division by zero.
-        * Look in `BigUnsigned.cc' for details.
-        * `a.divideWithRemainder(b, a)' causes an exception: it doesn't make
-        * sense to write quotient and remainder into the same variable.
-        */
+       // COPY-LESS OPERATIONS
+
+       // These 8: Arguments are read-only operands, result is saved in *this.
+       void add(const BigUnsigned &a, const BigUnsigned &b);
+       void subtract(const BigUnsigned &a, const BigUnsigned &b);
+       void multiply(const BigUnsigned &a, const BigUnsigned &b);
+       void bitAnd(const BigUnsigned &a, const BigUnsigned &b);
+       void bitOr(const BigUnsigned &a, const BigUnsigned &b);
+       void bitXor(const BigUnsigned &a, const BigUnsigned &b);
+       void bitShiftLeft(const BigUnsigned &a, unsigned int b);
+       void bitShiftRight(const BigUnsigned &a, unsigned int b);
+
+       /* `a.divideWithRemainder(b, q)' is like `q = a / b, a %= b'.
+        * / and % use semantics similar to Knuth's, which differ from the
+        * primitive integer semantics under division by zero.  See the
+        * implementation in BigUnsigned.cc for details.
+        * `a.divideWithRemainder(b, a)' throws an exception: it doesn't make
+        * sense to write quotient and remainder into the same variable. */
        void divideWithRemainder(const BigUnsigned &b, BigUnsigned &q);
-       void divide(const BigUnsigned &a, const BigUnsigned &b) {
-               BigUnsigned a2(a);
-               a2.divideWithRemainder(b, *this);
-               // quotient now in *this
-               // don't care about remainder left in a2
-       }
-       void modulo(const BigUnsigned &a, const BigUnsigned &b) {
-               *this = a;
-               BigUnsigned q;
-               divideWithRemainder(b, q);
-               // remainder now in *this
-               // don't care about quotient left in q
-       }
-       // Bitwise operations.  Result left in *this.
-       // These are not provided for BigIntegers; I think that using them on BigIntegers
-       // will discard the sign first.
-       void bitAnd(const BigUnsigned &a, const BigUnsigned &b); // Bitwise AND
-       void bitOr(const BigUnsigned &a, const BigUnsigned &b); // Bitwise OR
-       void bitXor(const BigUnsigned &a, const BigUnsigned &b); // Bitwise XOR
-       void bitShiftLeft(const BigUnsigned &a, unsigned int b); // Bitwise left shift
-       void bitShiftRight(const BigUnsigned &a, unsigned int b); // Bitwise right shift
-
-       // NORMAL OPERATORS
-       // These perform the operation on this (to the left of the operator)
-       // and x (to the right of the operator) and return a new BigUnsigned with the result.
-public:
-       BigUnsigned operator +(const BigUnsigned &x) const; // Addition
-       BigUnsigned operator -(const BigUnsigned &x) const; // Subtraction
-       BigUnsigned operator *(const BigUnsigned &x) const; // Multiplication
-       BigUnsigned operator /(const BigUnsigned &x) const; // Division
-       BigUnsigned operator %(const BigUnsigned &x) const; // Modular reduction
-       BigUnsigned operator &(const BigUnsigned &x) const; // Bitwise AND
-       BigUnsigned operator |(const BigUnsigned &x) const; // Bitwise OR
-       BigUnsigned operator ^(const BigUnsigned &x) const; // Bitwise XOR
-       BigUnsigned operator <<(unsigned int b) const; // Bitwise left shift
-       BigUnsigned operator >>(unsigned int b) const; // Bitwise right shift
+
+       /* `divide' and `modulo' are no longer offered.  Use
+        * `divideWithRemainder' instead. */
+
+       // OVERLOADED RETURN-BY-VALUE OPERATORS
+       BigUnsigned operator +(const BigUnsigned &x) const;
+       BigUnsigned operator -(const BigUnsigned &x) const;
+       BigUnsigned operator *(const BigUnsigned &x) const;
+       BigUnsigned operator /(const BigUnsigned &x) const;
+       BigUnsigned operator %(const BigUnsigned &x) const;
+       /* OK, maybe unary minus could succeed in one case, but it really
+        * shouldn't be used, so it isn't provided. */
+       BigUnsigned operator &(const BigUnsigned &x) const;
+       BigUnsigned operator |(const BigUnsigned &x) const;
+       BigUnsigned operator ^(const BigUnsigned &x) const;
+       BigUnsigned operator <<(unsigned int b) const;
+       BigUnsigned operator >>(unsigned int b) const;
        // Additional operators in an attempt to avoid overloading tangles.
+       // XXX Why exactly are these needed?
        BigUnsigned operator <<(int b) const;
        BigUnsigned operator >>(int b) const;
 
-       // ASSIGNMENT OPERATORS
-       // These perform the operation on this and x, storing the result into this.
-public:
-       void operator +=(const BigUnsigned &x); // Addition
-       void operator -=(const BigUnsigned &x); // Subtraction
-       void operator *=(const BigUnsigned &x); // Multiplication
-       void operator /=(const BigUnsigned &x); // Division
-       void operator %=(const BigUnsigned &x); // Modular reduction
-       void operator &=(const BigUnsigned &x); // Bitwise AND
-       void operator |=(const BigUnsigned &x); // Bitwise OR
-       void operator ^=(const BigUnsigned &x); // Bitwise XOR
-       void operator <<=(unsigned int b); // Bitwise left shift
-       void operator >>=(unsigned int b); // Bitwise right shift
+       // OVERLOADED ASSIGNMENT OPERATORS
+       void operator +=(const BigUnsigned &x);
+       void operator -=(const BigUnsigned &x);
+       void operator *=(const BigUnsigned &x);
+       void operator /=(const BigUnsigned &x);
+       void operator %=(const BigUnsigned &x);
+       void operator &=(const BigUnsigned &x);
+       void operator |=(const BigUnsigned &x);
+       void operator ^=(const BigUnsigned &x);
+       void operator <<=(unsigned int b);
+       void operator >>=(unsigned int b);
        // Additional operators in an attempt to avoid overloading tangles.
+       // XXX Why exactly are these needed?
        void operator <<=(int b);
        void operator >>=(int b);
 
-       // INCREMENT/DECREMENT OPERATORS
-       // These increase or decrease the number by 1.  To discourage side effects,
-       // these do not return *this, so prefix and postfix behave the same.
-public:
-       void operator ++(   ); // Prefix  increment
-       void operator ++(int); // Postfix decrement
-       void operator --(   ); // Prefix  increment
-       void operator --(int); // Postfix decrement
+       /* INCREMENT/DECREMENT OPERATORS
+        * To discourage messy coding, these do not return *this, so prefix
+        * and postfix behave the same. */
+       void operator ++(   );
+       void operator ++(int);
+       void operator --(   );
+       void operator --(int);
 
        // Helper function that needs access to BigUnsigned internals
-       friend Blk getShiftedBlock(const BigUnsigned &num, Index x, unsigned int y);
+       friend Blk getShiftedBlock(const BigUnsigned &num, Index x,
+                       unsigned int y);
+
+       // See BigInteger.cc.
+       template <class X>
+       friend X convertBigUnsignedToPrimitiveAccess(const BigUnsigned &a);
 };
 
-// NORMAL OPERATORS
-/* These create an object to hold the result and invoke
- * the appropriate put-here operation on it, passing
- * this and x.  The new object is then returned. */
+/* Implementing the return-by-value and assignment operators in terms of the
+ * copy-less operations.  The copy-less operations are responsible for making
+ * any necessary temporary copies to work around aliasing. */
+
 inline BigUnsigned BigUnsigned::operator +(const BigUnsigned &x) const {
        BigUnsigned ans;
        ans.add(*this, x);
@@ -257,14 +251,16 @@ inline BigUnsigned BigUnsigned::operator *(const BigUnsigned &x) const {
        return ans;
 }
 inline BigUnsigned BigUnsigned::operator /(const BigUnsigned &x) const {
-       BigUnsigned ans;
-       ans.divide(*this, x);
-       return ans;
+       BigUnsigned q, r;
+       r = *this;
+       r.divideWithRemainder(x, q);
+       return q;
 }
 inline BigUnsigned BigUnsigned::operator %(const BigUnsigned &x) const {
-       BigUnsigned ans;
-       ans.modulo(*this, x);
-       return ans;
+       BigUnsigned q, r;
+       r = *this;
+       r.divideWithRemainder(x, q);
+       return r;
 }
 inline BigUnsigned BigUnsigned::operator &(const BigUnsigned &x) const {
        BigUnsigned ans;
@@ -293,24 +289,15 @@ inline BigUnsigned BigUnsigned::operator >>(unsigned int b) const {
 }
 inline BigUnsigned BigUnsigned::operator <<(int b) const {
        if (b < 0)
-               throw "BigUnsigned::operator <<(int): Negative shift amounts are not supported";
+               throw "BigUnsigned::operator <<(int): Negative shift amounts are not allowed";
        return *this << (unsigned int)(b);
 }
 inline BigUnsigned BigUnsigned::operator >>(int b) const {
        if (b < 0)
-               throw "BigUnsigned::operator >>(int): Negative shift amounts are not supported";
+               throw "BigUnsigned::operator >>(int): Negative shift amounts are not allowed";
        return *this >> (unsigned int)(b);
 }
 
-/*
- * ASSIGNMENT OPERATORS
- * 
- * Now the responsibility for making a temporary copy if necessary
- * belongs to the put-here operations.  I made this change on 2007.02.13 after
- * Boris Dessy pointed out that the old implementation handled calls like
- * "a *= a" badly: it translated them to essentially "a.multiply(aCopy, a)",
- * which threw an exception.
- */
 inline void BigUnsigned::operator +=(const BigUnsigned &x) {
        add(*this, x);
 }
@@ -321,18 +308,17 @@ inline void BigUnsigned::operator *=(const BigUnsigned &x) {
        multiply(*this, x);
 }
 inline void BigUnsigned::operator /=(const BigUnsigned &x) {
-       // Updated for divideWithRemainder
-       BigUnsigned thisCopy(*this);
-       thisCopy.divideWithRemainder(x, *this);
-       // quotient left in *this
-       // don't care about remainder left in thisCopy
+       /* The following technique is slightly faster than copying *this first
+        * when x is large. */
+       BigUnsigned q;
+       divideWithRemainder(x, q);
+       // *this contains the remainder, but we overwrite it with the quotient.
+       *this = q;
 }
 inline void BigUnsigned::operator %=(const BigUnsigned &x) {
-       // Shortcut (woohoo!)
        BigUnsigned q;
+       // Mods *this by x.  Don't care about quotient left in q.
        divideWithRemainder(x, q);
-       // remainder left in *this
-       // don't care about quotient left in q
 }
 inline void BigUnsigned::operator &=(const BigUnsigned &x) {
        bitAnd(*this, x);
index b2881e0..41bbfba 100644 (file)
@@ -36,7 +36,7 @@ BigUnsignedInABase::BigUnsignedInABase(const BigUnsigned &x, Base base) {
        int maxBitLenOfX = x.getLength() * BigUnsigned::N;
        int minBitsPerDigit = bitLen(base) - 1;
        int maxDigitLenOfX = ceilingDiv(maxBitLenOfX, minBitsPerDigit);
-       len = maxDigitLenOfX; // Another change to comply with `staying in bounds'; see `BigUnsigned::divideWithRemainder'.
+       len = maxDigitLenOfX; // Another change to comply with `staying in bounds'.
        allocate(len); // Get the space
 
        BigUnsigned x2(x), buBase(base);
@@ -47,7 +47,7 @@ BigUnsignedInABase::BigUnsignedInABase(const BigUnsigned &x, Base base) {
                BigUnsigned lastDigit(x2);
                lastDigit.divideWithRemainder(buBase, x2);
                // Save the digit.
-               blk[digitNum] = Digit(lastDigit); // invokes `BigUnsigned ==> unsigned short' converter
+               blk[digitNum] = lastDigit.toUnsignedShort();
                // Move on.  We can't run out of room: we figured it out above.
                digitNum++;
        }
index 8fa52d7..53c8e5b 100644 (file)
-/*
- * This mechanism prevents files from being included twice.
- * Each file gets its own `id' (here `NUMBERLIKEARRAY').
- * When `#include'd, this file checks whether its `id' has
- * already been flagged.  If not, it flags the `id' and
- * loads the declarations.
- */
 #ifndef NUMBERLIKEARRAY_H
 #define NUMBERLIKEARRAY_H
 
-// An essential memory-management constant.
-// I wish this were built into C++ just as it is in Java.
+// Make sure we have NULL.
 #ifndef NULL
 #define NULL 0
 #endif
 
-/*
- * A NumberlikeArray<Blk> object holds a dynamically
- * allocated array of Blk.  It provides certain basic
- * memory management features needed by both BigUnsigned
- * and BigUnsignedInABase, which are both derived from it.
+/* A NumberlikeArray<Blk> object holds a heap-allocated array of Blk with a
+ * length and a capacity and provides basic memory management features.
+ * BigUnsigned and BigUnsignedInABase both subclass it.
  *
- * NumberlikeArray provides no information hiding, so make
- * sure you know what you are doing if you use it directly.
- * Classes derived from it will probably wish to pass on
- * some members of NumberlikeArray to their clients while
- * keeping some safe for themselves.  These classes should
- * use protected inheritance and manually make some members
- * public with declarations like this:
+ * NumberlikeArray provides no information hiding.  Subclasses should use
+ * nonpublic inheritance and manually expose members as desired using
+ * declarations like this:
  *
  * public:
- *     NumberlikeArray< whatever >::getLength;
+ *     NumberlikeArray< the-type-argument >::getLength;
  */
-
 template <class Blk>
 class NumberlikeArray {
 public:
 
-       typedef unsigned int Index; // Type for the index of a block in the array
-       static const unsigned int N; // The number of bits in a block, defined below.
-
-       // FIELDS
-       Index cap; // The current allocated capacity of this NumberlikeArray (in blocks)
-       Index len; // The actual length of the value stored in this NumberlikeArray (in blocks)
-       Blk *blk; // Dynamically allocated array of the blocks
-
-       /*
-        * Change made on 2005.01.06:
-        *
-        * If a zero-length NumberlikeArray is desired, no array is actually allocated.
-        * Instead, `blk' is set to `NULL', and `cap' and `len' are zero as usual.
-        *
-        * `blk' is never dereferenced if the array has zero length.  Furthermore,
-        * `delete NULL;' does nothing and causes no error. Therefore, we can use
-        * `NULL' as if it were a zero-length array from `new'.
-        *
-        * This is a great convenience because the only code that need be changed
-        * is the array allocation code.  All other code will still work fine.
-        */
-
-       // MANAGEMENT
-       NumberlikeArray(Index c) : cap(c), len(0) { // Creates a NumberlikeArray with a capacity
+       // Type for the index of a block in the array
+       typedef unsigned int Index;
+       // The number of bits in a block, defined below.
+       static const unsigned int N;
+
+       // The current allocated capacity of this NumberlikeArray (in blocks)
+       Index cap;
+       // The actual length of the value stored in this NumberlikeArray (in blocks)
+       Index len;
+       // Heap-allocated array of the blocks (can be NULL if len == 0)
+       Blk *blk;
+
+       // Constructs a ``zero'' NumberlikeArray with the given capacity.
+       NumberlikeArray(Index c) : cap(c), len(0) { 
                blk = (cap > 0) ? (new Blk[cap]) : NULL;
        }
-       void allocate(Index c); // Ensures the array has at least the indicated capacity, maybe discarding contents
-       void allocateAndCopy(Index c); // Ensures the array has at least the indicated capacity, preserving its contents
-
-       /*
-        * Default constructor.
-        *
-        * If a class derived from NumberlikeArray knows at initializer time what size array
-        * it wants, it can call the first constructor listed above in an initializer.
-        *
-        * Otherwise, this default constructor will be implicitly invoked, pointing `blk' to
-        * `NULL', a fake zero-length block array.  The derived class can allocate the desired
-        * array itself and overwrite `blk'; it need not `delete [] blk' first.
-        *
-        * This change fixes a memory leak reported by Milan Tomic on 2005.01.06.
-        * Integer-type-to-BigUnsigned (and BigInteger) conversion constructors have always
-        * allocated their own array of length 0 or 1 after seeing whether the input is zero.
-        * But when the NumberlikeArray transition occurred, these constructors contained an
-        * implicit initializer call to the old NumberlikeArray default constructor, which
-        * created a real `new'-allocated zero-length array.  This array would then be lost,
-        * causing a small but annoying memory leak.
-        */
+
+       /* Constructs a zero NumberlikeArray without allocating a backing array.
+        * A subclass that doesn't know the needed capacity at initialization
+        * time can use this constructor and then overwrite blk without first
+        * deleting it. */
        NumberlikeArray() : cap(0), len(0) {
                blk = NULL;
        }
-       NumberlikeArray(const NumberlikeArray<Blk> &x); // Copy constructor
-       void operator=(const NumberlikeArray<Blk> &x); // Assignment operator
-       NumberlikeArray(const Blk *b, Index l); // Constructor from an array of blocks
-       ~NumberlikeArray() { // Destructor
-               delete [] blk; // Does nothing and causes no error if `blk' is null.
+
+       // Destructor.  Note that `delete NULL' is a no-op.
+       ~NumberlikeArray() {
+               delete [] blk;
        }
 
-       // PICKING APART
-       // These accessors can be used to get the pieces of the value
-       Index getCapacity() const { return cap; }
-       Index getLength() const { return len; }
-       Blk getBlock(Index i) const { return blk[i]; };
-       bool isEmpty() const { return len == 0; }
+       /* Ensures that the array has at least the requested capacity; may
+        * destroy the contents. */
+       void allocate(Index c);
+
+       /* Ensures that the array has at least the requested capacity; does not
+        * destroy the contents. */
+       void allocateAndCopy(Index c);
+
+       // Copy constructor
+       NumberlikeArray(const NumberlikeArray<Blk> &x);
+
+       // Assignment operator
+       void operator=(const NumberlikeArray<Blk> &x);
 
-       // Equality comparison: checks if arrays have same length and matching values
-       // Derived classes may wish to override these if differing arrays can
-       // sometimes be considered equivalent.
+       // Constructor that copies from a given array of blocks
+       NumberlikeArray(const Blk *b, Index blen);
+
+       // ACCESSORS
+       Index getCapacity()     const { return cap;      }
+       Index getLength()       const { return len;      }
+       Blk   getBlock(Index i) const { return blk[i];   }
+       bool  isEmpty()         const { return len == 0; }
+
+       /* Equality comparison: checks if both objects have the same length and
+        * equal (==) array elements to that length.  Subclasses may wish to
+        * override. */
        bool operator ==(const NumberlikeArray<Blk> &x) const;
-       bool operator !=(const NumberlikeArray<Blk> &x) const { return !operator ==(x); }
 
+       bool operator !=(const NumberlikeArray<Blk> &x) const {
+               return !operator ==(x);
+       }
 };
 
-/*
- * =================================
- * BELOW THIS POINT are template definitions; above are declarations.
- *
- * Definitions would ordinarily belong in a file NumberlikeArray.cc so that they would
- * be compiled once into NumberlikeArray.o and then linked.
- *
- * However, because of the way templates are usually implemented,
- * template ``definitions'' are treated as declarations by the compiler.
- * When someone uses an instance of the template, definitions are generated,
- * and the linker is smart enough to toss duplicate definitions for the same
- * instance generated by different files.
- *
- * Thus, the template ``definitions'' for NumberlikeArray must appear in this header file
- * so other files including NumberlikeArray will be able to generate real definitions.
- */
+/* BEGIN TEMPLATE DEFINITIONS.  They are present here so that source files that
+ * include this header file can generate the necessary real definitions. */
 
 template <class Blk>
 const unsigned int NumberlikeArray<Blk>::N = 8 * sizeof(Blk);
 
-// MANAGEMENT
-
-// This routine is called to ensure the array is at least a
-// certain size before another value is written into it.
 template <class Blk>
 void NumberlikeArray<Blk>::allocate(Index c) {
        // If the requested capacity is more than the current capacity...
@@ -144,8 +102,6 @@ void NumberlikeArray<Blk>::allocate(Index c) {
        }
 }
 
-// This routine is called to ensure the array is at least a
-// certain size without losing its contents.
 template <class Blk>
 void NumberlikeArray<Blk>::allocateAndCopy(Index c) {
        // If the requested capacity is more than the current capacity...
@@ -163,9 +119,9 @@ void NumberlikeArray<Blk>::allocateAndCopy(Index c) {
        }
 }
 
-// Copy constructor
 template <class Blk>
-NumberlikeArray<Blk>::NumberlikeArray(const NumberlikeArray<Blk> &x) : len(x.len) {
+NumberlikeArray<Blk>::NumberlikeArray(const NumberlikeArray<Blk> &x)
+               : len(x.len) {
        // Create array
        cap = len;
        blk = new Blk[cap];
@@ -175,10 +131,10 @@ NumberlikeArray<Blk>::NumberlikeArray(const NumberlikeArray<Blk> &x) : len(x.len
                blk[i] = x.blk[i];
 }
 
-// Assignment operator
 template <class Blk>
 void NumberlikeArray<Blk>::operator=(const NumberlikeArray<Blk> &x) {
-       // Calls like a = a have no effect
+       /* Calls like a = a have no effect; catch them before the aliasing
+        * causes a problem */
        if (this == &x)
                return;
        // Copy length
@@ -191,9 +147,9 @@ void NumberlikeArray<Blk>::operator=(const NumberlikeArray<Blk> &x) {
                blk[i] = x.blk[i];
 }
 
-// Constructor from an array of blocks
 template <class Blk>
-NumberlikeArray<Blk>::NumberlikeArray(const Blk *b, Index l) : cap(l), len(l) {
+NumberlikeArray<Blk>::NumberlikeArray(const Blk *b, Index blen)
+               : cap(blen), len(blen) {
        // Create array
        blk = new Blk[cap];
        // Copy blocks
@@ -202,22 +158,18 @@ NumberlikeArray<Blk>::NumberlikeArray(const Blk *b, Index l) : cap(l), len(l) {
                blk[i] = b[i];
 }
 
-
-// EQUALITY TEST
-// This uses == to compare Blks for equality.
-// Therefore, Blks must have an == operator with the desired semantics.
 template <class Blk>
 bool NumberlikeArray<Blk>::operator ==(const NumberlikeArray<Blk> &x) const {
-       // Different lengths imply different objects.
        if (len != x.len)
+               // Definitely unequal.
                return false;
        else {
-               // Compare matching blocks one by one.
+               // Compare corresponding blocks one by one.
                Index i;
                for (i = 0; i < len; i++)
                        if (blk[i] != x.blk[i])
                                return false;
-               // If no blocks differed, the objects are equal.
+               // No blocks differed, so the objects are equal.
                return true;
        }
 }
diff --git a/README b/README
index 757637e..da0d604 100644 (file)
--- a/README
+++ b/README
@@ -2,9 +2,9 @@
                             C++ Big Integer Library
                           (see ChangeLog for version)
 
-                      http://www.kepreon.com/~matt/bigint/
+                        http://mattmccutchen.net/bigint/
 
-        Written and maintained by Matt McCutchen <hashproduct@gmail.com>
+       Written and maintained by Matt McCutchen <matt@mattmccutchen.net>
 
 You can use this library in a C++ program to do arithmetic on integers of size
 limited only by your computer's memory.  The library provides BigUnsigned and
@@ -24,6 +24,10 @@ To get started quickly, read the code and explanations in that file and run it.
 If you want more detail or a feature not shown in `sample.cc', consult the
 consult the actual header and source files, which are heavily commented.
 
+The code is intended to be reasonably portable across computers and modern C++
+compilers; in particular, it uses whatever word size the computer provides
+(32-bit, 64-bit, or whatever).  Please report any portability problems.
+
 Compiling programs that use the library
 ---------------------------------------
 The library consists of a folder full of C++ header files (`.hh') and source
@@ -44,8 +48,8 @@ generally fix all reported bugs.
 You are also welcome to request enhancements, but I am unlikely to do
 substantial amounts of work on enhancements at this point.  When I fix a bug you
 report or make an enhancement you request, I will generally credit you by name
-in the source code and/or the Change Log unless you request otherwise.  New
-versions of the library will be available at its Web site (above).
+in the Change Log unless you request otherwise.  New versions of the library
+will be available at its Web site (above).
 
 Note
 ----
index 0fd9ee4..149b18b 100644 (file)
--- a/sample.cc
+++ b/sample.cc
@@ -18,8 +18,8 @@ int main() {
                BigInteger a; // a is 0
                int b = 535;
 
-               a = b; // From int to BigInteger...
-               b = a; // ...and back, no casts required!
+               a = b; // From int to BigInteger implicitly...
+               b = a.toInt(); // ...and back explicitly.
                /*
                 * If a were too big for an int you'd get a runtime exception.
                 * The Big Integer Library throws C-strings (that is,
@@ -119,4 +119,4 @@ Running the sample program produces this output:
 314^9 = 29673367320587092457984
 314^10 = 9317437338664347031806976
 
- */
+*/