// Memory management definitions have moved to the bottom of NumberlikeArray.hh.
-// CONSTRUCTION FROM PRIMITIVE INTEGERS
-
-/* 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)
- ; // 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;
- blk[0] = Blk(x);
- }
-}
-
-/* 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);
-}
+// The templates used by these constructors and converters are at the bottom of
+// BigUnsigned.hh.
BigUnsigned::BigUnsigned(unsigned long x) { initFromPrimitive (x); }
BigUnsigned::BigUnsigned(unsigned int x) { initFromPrimitive (x); }
BigUnsigned::BigUnsigned( int x) { initFromSignedPrimitive(x); }
BigUnsigned::BigUnsigned( short x) { initFromSignedPrimitive(x); }
-// CONVERSION TO PRIMITIVE INTEGERS
+unsigned long BigUnsigned::toUnsignedLong () const { return convertToPrimitive ((unsigned long )0); }
+unsigned int BigUnsigned::toUnsignedInt () const { return convertToPrimitive ((unsigned int )0); }
+unsigned short BigUnsigned::toUnsignedShort() const { return convertToPrimitive ((unsigned short)0); }
+long BigUnsigned::toLong () const { return convertToSignedPrimitive(( long )0); }
+int BigUnsigned::toInt () const { return convertToSignedPrimitive(( int )0); }
+short BigUnsigned::toShort () const { return convertToSignedPrimitive(( short)0); }
-/* 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) {
- // 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.
+// BIT/BLOCK ACCESSORS
+
+void BigUnsigned::setBlock(Index i, Blk newBlock) {
+ if (newBlock == 0) {
+ if (i < len) {
+ blk[i] = 0;
+ zapLeadingZeros();
+ }
+ // If i >= len, no effect.
+ } else {
+ if (i >= len) {
+ // The nonzero block extends the number.
+ allocateAndCopy(i+1);
+ // Zero any added blocks that we aren't setting.
+ for (Index j = len; j < i; j++)
+ blk[j] = 0;
+ len = i+1;
+ }
+ blk[i] = newBlock;
}
- throw "BigUnsigned::to<Primitive>: "
- "Value is too big to fit in the requested type";
}
-/* 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::to(Primitive): "
- "Value is too big to fit in the requested type";
+/* Evidently the compiler wants BigUnsigned:: on the return type because, at
+ * that point, it hasn't yet parsed the BigUnsigned:: on the name to get the
+ * proper scope. */
+BigUnsigned::Index BigUnsigned::bitLength() const {
+ if (isZero())
+ return 0;
+ else {
+ Blk leftmostBlock = getBlock(len - 1);
+ Index leftmostBlockLen = 0;
+ while (leftmostBlock != 0) {
+ leftmostBlock >>= 1;
+ leftmostBlockLen++;
+ }
+ return leftmostBlockLen + (len - 1) * N;
+ }
}
-unsigned long BigUnsigned::toUnsignedLong() const {
- return convertToPrimitive<unsigned long>();
-}
-unsigned int BigUnsigned::toUnsignedInt() const {
- return convertToPrimitive<unsigned int>();
-}
-unsigned short BigUnsigned::toUnsignedShort() const {
- return convertToPrimitive<unsigned short>();
-}
-long BigUnsigned::toLong() const {
- return convertToSignedPrimitive<long>();
-}
-int BigUnsigned::toInt() const {
- return convertToSignedPrimitive<int>();
-}
-short BigUnsigned::toShort() const {
- return convertToSignedPrimitive<short>();
+void BigUnsigned::setBit(Index bi, bool newBit) {
+ Index blockI = bi / N;
+ Blk block = getBlock(blockI), mask = 1 << (bi % N);
+ block = newBit ? (block | mask) : (block & ~mask);
+ setBlock(blockI, block);
}
// COMPARISON