static int Compare(Bignum a, Bignum b) { Debug.Assert(a.IsClamped()); Debug.Assert(b.IsClamped()); int bigit_length_a = a.BigitLength(); int bigit_length_b = b.BigitLength(); if (bigit_length_a < bigit_length_b) { return(-1); } if (bigit_length_a > bigit_length_b) { return(+1); } for (int i = bigit_length_a - 1; i >= System.Math.Min(a.exponent_, b.exponent_); --i) { uint bigit_a = a.BigitAt(i); uint bigit_b = b.BigitAt(i); if (bigit_a < bigit_b) { return(-1); } if (bigit_a > bigit_b) { return(+1); } // Otherwise they are equal up to this digit. Try the next digit. } return(0); }
void SubtractBignum(Bignum other) { Debug.Assert(IsClamped()); Debug.Assert(other.IsClamped()); // We require this to be bigger than other. Debug.Assert(LessEqual(other, this)); Align(other); int offset = other.exponent_ - exponent_; uint borrow = 0; int i; for (i = 0; i < other.used_digits_; ++i) { Debug.Assert((borrow == 0) || (borrow == 1)); uint difference = bigits_[i + offset] - other.bigits_[i] - borrow; bigits_[i + offset] = difference & kBigitMask; borrow = difference >> (kChunkSize - 1); } while (borrow != 0) { uint difference = bigits_[i + offset] - borrow; bigits_[i + offset] = difference & kBigitMask; borrow = difference >> (kChunkSize - 1); ++i; } Clamp(); }
internal static int PlusCompare(Bignum a, Bignum b, Bignum c) { Debug.Assert(a.IsClamped()); Debug.Assert(b.IsClamped()); Debug.Assert(c.IsClamped()); if (a.BigitLength() < b.BigitLength()) { return(PlusCompare(b, a, c)); } if (a.BigitLength() + 1 < c.BigitLength()) { return(-1); } if (a.BigitLength() > c.BigitLength()) { return(+1); } // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one // of 'a'. if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) { return(-1); } uint borrow = 0; // Starting at min_exponent all digits are == 0. So no need to compare them. int min_exponent = System.Math.Min(System.Math.Min(a.exponent_, b.exponent_), c.exponent_); for (int i = c.BigitLength() - 1; i >= min_exponent; --i) { uint chunk_a = a.BigitAt(i); uint chunk_b = b.BigitAt(i); uint chunk_c = c.BigitAt(i); uint sum = chunk_a + chunk_b; if (sum > chunk_c + borrow) { return(+1); } else { borrow = chunk_c + borrow - sum; if (borrow > 1) { return(-1); } borrow <<= kBigitSize; } } if (borrow == 0) { return(0); } return(-1); }
// Precondition: this/other < 16bit. public uint DivideModuloIntBignum(Bignum other) { Debug.Assert(IsClamped()); Debug.Assert(other.IsClamped()); Debug.Assert(other.used_digits_ > 0); // Easy case: if we have less digits than the divisor than the result is 0. // Note: this handles the case where this == 0, too. if (BigitLength() < other.BigitLength()) { return(0); } Align(other); uint result = 0; // Start by removing multiples of 'other' until both numbers have the same // number of digits. while (BigitLength() > other.BigitLength()) { // This naive approach is extremely inefficient if the this divided other // might be big. This function is implemented for doubleToString where // the result should be small (less than 10). Debug.Assert(other.bigits_[other.used_digits_ - 1] >= (1 << kBigitSize) / 16); // Remove the multiples of the first digit. // Example this = 23 and other equals 9. -> Remove 2 multiples. result += bigits_[used_digits_ - 1]; SubtractTimes(other, bigits_[used_digits_ - 1]); } Debug.Assert(BigitLength() == other.BigitLength()); // Both bignums are at the same length now. // Since other has more than 0 digits we know that the access to // bigits_[used_digits_ - 1] is safe. var this_bigit = bigits_[used_digits_ - 1]; var other_bigit = other.bigits_[other.used_digits_ - 1]; if (other.used_digits_ == 1) { // Shortcut for easy (and common) case. uint quotient = this_bigit / other_bigit; bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient; result += quotient; Clamp(); return(result); } uint division_estimate = this_bigit / (other_bigit + 1); result += division_estimate; SubtractTimes(other, division_estimate); if (other_bigit * (division_estimate + 1) > this_bigit) { return(result); } while (LessEqual(other, this)) { SubtractBignum(other); result++; } return(result); }