Really rename DOTR_ALIASED -> DTRT_ALIASED.
[bigint/bigint.git] / BigInteger.cc
index 69d2dd7..00074cf 100644 (file)
@@ -1,6 +1,5 @@
 /*
 * Matt McCutchen's Big Integer Library
-* http://mysite.verizon.net/mccutchen/bigint/
 */
 
 #include "BigInteger.hh"
@@ -311,11 +310,18 @@ BigInteger::CmpRes BigInteger::compareTo(const BigInteger &x) const {
 // These do some messing around to determine the sign of the result,
 // then call one of BigUnsigned's put-heres.
 
+// See remarks about aliased calls in BigUnsigned.cc .
+#define DTRT_ALIASED(cond, op) \
+       if (cond) { \
+               BigInteger tmpThis; \
+               tmpThis.op; \
+               *this = tmpThis; \
+               return; \
+       }
+
 // Addition
 void BigInteger::add(const BigInteger &a, const BigInteger &b) {
-       // Block unsafe calls
-       if (this == &a || this == &b)
-               throw "BigInteger::add: One of the arguments is the invoked object";
+       DTRT_ALIASED(this == &a || this == &b, add(a, b));
        // If one argument is zero, copy the other.
        if (a.sign == zero)
                operator =(b);
@@ -352,15 +358,15 @@ void BigInteger::add(const BigInteger &a, const BigInteger &b) {
 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.
-       // Block unsafe calls
-       if (this == &a || this == &b)
-               throw "BigInteger::subtract: One of the arguments is the invoked object";
+       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);
-               sign = Sign(-sign);
+               // Take the negative of _b_'s, sign, not ours.
+               // Bug pointed out by Sam Larkin on 2005.03.30.
+               sign = Sign(-b.sign);
        } else if (b.sign == zero)
-    operator =(a);
+               operator =(a);
        // If their signs differ, take a.sign and add the magnitudes.
        else if (a.sign != b.sign) {
                sign = a.sign;
@@ -391,9 +397,7 @@ void BigInteger::subtract(const BigInteger &a, const BigInteger &b) {
 
 // Multiplication
 void BigInteger::multiply(const BigInteger &a, const BigInteger &b) {
-       // Block unsafe calls
-       if (this == &a || this == &b)
-               throw "BigInteger::multiply: One of the arguments is the invoked object";
+       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;
@@ -430,9 +434,16 @@ void BigInteger::multiply(const BigInteger &a, const BigInteger &b) {
 *      -4      -3      1       -1
 */
 void BigInteger::divideWithRemainder(const BigInteger &b, BigInteger &q) {
-       // Block unsafe calls
-       if (this == &b || this == &q || &b == &q)
-               throw "BigInteger::divideWithRemainder: One of the arguments is the invoked object";
+       // Defend against aliased calls;
+       // same idea as in BigUnsigned::divideWithRemainder .
+       if (this == &q)
+               throw "BigInteger::divideWithRemainder: Cannot write quotient and remainder into the same variable";
+       if (this == &b || &q == &b) {
+               BigInteger tmpB(b);
+               divideWithRemainder(tmpB, q);
+               return;
+       }
+
        // Division by zero gives quotient 0 and remainder *this
        if (b.sign == zero) {
                q.len = 0;
@@ -445,9 +456,9 @@ void BigInteger::divideWithRemainder(const BigInteger &b, BigInteger &q) {
                q.sign = zero;
                return;
        }
-       
+
        // Here *this != 0, b != 0.
-       
+
        // Do the operands have the same sign?
        if (sign == b.sign) {
                // Yes: easy case.  Quotient is zero or positive.
@@ -478,10 +489,10 @@ void BigInteger::divideWithRemainder(const BigInteger &b, BigInteger &q) {
                * Find r = (b - 1) - R and give it the desired sign.
                */
        }
-       
+
        // Divide the magnitudes.
        BigUnsigned::divideWithRemainder(b, q);
-       
+
        if (sign != b.sign) {
                // More for the harder case (as described):
                // Increase the magnitude of the quotient by one.
@@ -491,24 +502,22 @@ void BigInteger::divideWithRemainder(const BigInteger &b, BigInteger &q) {
                BigUnsigned::subtract(b, temp);
                BigUnsigned::operator --();
        }
-       
+
        // 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)
                sign = zero;
        if (q.len == 0)
                q.sign = zero;
-       
+
        // WHEW!!!
 }
 
 // Negation
 void BigInteger::negate(const BigInteger &a) {
-       // Block unsafe calls
-       if (this == &a)
-               throw "BigInteger::negate: The argument is the invoked object";
+       DTRT_ALIASED(this == &a, negate(a));
        // Copy a's magnitude
        BigUnsigned::operator =(a);
        // Copy the opposite of a.sign