- Fix a sign-checking bug in the BigInteger(..., Sign) constructors.
authorMatt McCutchen <matt@mattmccutchen.net>
Thu, 17 Jul 2008 11:44:27 +0000 (07:44 -0400)
committerMatt McCutchen <matt@mattmccutchen.net>
Thu, 17 Jul 2008 11:44:27 +0000 (07:44 -0400)
- Add some tests of constructors, including one for the aforementioned bug.
- Improve some comments.

BigInteger.cc
testsuite.cc

index 56f30ab..3b23aa1 100644 (file)
@@ -13,11 +13,18 @@ void BigInteger::operator =(const BigInteger &x) {
 BigInteger::BigInteger(const Blk *b, Index blen, Sign s) : mag(b, blen) {
        switch (s) {
        case zero:
+               if (!mag.isZero())
+                       throw "BigInteger::BigInteger(const Blk *, Index, Sign): Cannot use a sign of zero with a nonzero magnitude";
+               sign = zero;
+               break;
        case positive:
        case negative:
+               // If the magnitude is zero, force the sign to zero.
                sign = mag.isZero() ? zero : s;
                break;
        default:
+               /* g++ seems to be optimizing out this case on the assumption
+                * that the sign is a valid member of the enumeration.  Oh well. */
                throw "BigInteger::BigInteger(const Blk *, Index, Sign): Invalid sign";
        }
 }
@@ -25,12 +32,19 @@ BigInteger::BigInteger(const Blk *b, Index blen, Sign s) : mag(b, blen) {
 BigInteger::BigInteger(const BigUnsigned &x, Sign s) : mag(x) {
        switch (s) {
        case zero:
+               if (!mag.isZero())
+                       throw "BigInteger::BigInteger(const BigUnsigned &, Sign): Cannot use a sign of zero with a nonzero magnitude";
+               sign = zero;
+               break;
        case positive:
        case negative:
+               // If the magnitude is zero, force the sign to zero.
                sign = mag.isZero() ? zero : s;
                break;
        default:
-               throw "BigInteger::BigInteger(Blk *, Index, Sign): Invalid sign";
+               /* g++ seems to be optimizing out this case on the assumption
+                * that the sign is a valid member of the enumeration.  Oh well. */
+               throw "BigInteger::BigInteger(const BigUnsigned &, Sign): Invalid sign";
        }
 }
 
index 8d31eda..7817e9a 100644 (file)
@@ -60,6 +60,32 @@ TEST(10); //10
 TEST(check(BigUnsigned())); //0
 TEST(check(BigInteger())); //0
 
+// === Block-array constructors ===
+
+BigUnsigned::Blk myBlocks[3];
+myBlocks[0] = 3;
+myBlocks[1] = 4;
+myBlocks[2] = 0;
+BigUnsigned bu(myBlocks, 3);
+TEST(check(bu)); //17179869187
+TEST(check(BigInteger(myBlocks, 3))); //17179869187
+TEST(check(BigInteger(bu         ))); //17179869187
+
+// For nonzero magnitude, reject zero and invalid signs.
+TEST(check(BigInteger(myBlocks, 3, BigInteger::positive))); //17179869187
+TEST(check(BigInteger(myBlocks, 3, BigInteger::negative))); //-17179869187
+TEST(check(BigInteger(myBlocks, 3, BigInteger::zero    ))); //error
+TEST(check(BigInteger(bu,          BigInteger::positive))); //17179869187
+TEST(check(BigInteger(bu,          BigInteger::negative))); //-17179869187
+TEST(check(BigInteger(bu,          BigInteger::zero    ))); //error
+
+// For zero magnitude, force the sign to zero without error.
+BigUnsigned::Blk myZeroBlocks[1];
+myZeroBlocks[0] = 0;
+TEST(check(BigInteger(myZeroBlocks, 1, BigInteger::positive))); //0
+TEST(check(BigInteger(myZeroBlocks, 1, BigInteger::negative))); //0
+TEST(check(BigInteger(myZeroBlocks, 1, BigInteger::zero    ))); //0
+
 // === BigUnsigned conversion limits ===
 
 TEST(BigUnsigned(0).toUnsignedLong()); //0