private static void SingleDivide(BigInteger leftSide, BigInteger rightSide, out BigInteger quotient, out BigInteger remainder) { if (rightSide.IsZero) { throw new DivideByZeroException(); } DigitsArray remainderDigits = new DigitsArray(leftSide.m_digits); remainderDigits.ResetDataUsed(); int pos = remainderDigits.DataUsed - 1; ulong divisor = (ulong)rightSide.m_digits[0]; ulong dividend = (ulong)remainderDigits[pos]; DType[] result = new DType[leftSide.m_digits.Count]; leftSide.m_digits.CopyTo(result, 0, result.Length); int resultPos = 0; if (dividend >= divisor) { result[resultPos++] = (DType)(dividend / divisor); remainderDigits[pos] = (DType)(dividend % divisor); } pos--; while (pos >= 0) { dividend = ((ulong)(remainderDigits[pos + 1]) << DigitsArray.DataSizeBits) + (ulong)remainderDigits[pos]; result[resultPos++] = (DType)(dividend / divisor); remainderDigits[pos + 1] = 0; remainderDigits[pos--] = (DType)(dividend % divisor); } remainder = new BigInteger(remainderDigits); DigitsArray quotientDigits = new DigitsArray(resultPos + 1, resultPos); int j = 0; for (int i = quotientDigits.DataUsed - 1; i >= 0; i--, j++) { quotientDigits[j] = result[i]; } quotient = new BigInteger(quotientDigits); }
/// <summary> /// Multiply two BigIntegers returning the result. /// </summary> /// <remarks> /// See Knuth. /// </remarks> /// <param name="leftSide">A BigInteger.</param> /// <param name="rightSide">A BigInteger</param> /// <returns></returns> public static BigInteger operator * (BigInteger leftSide, BigInteger rightSide) { if (object.ReferenceEquals(leftSide, null)) { throw new ArgumentNullException("leftSide"); } if (object.ReferenceEquals(rightSide, null)) { throw new ArgumentNullException("rightSide"); } bool leftSideNeg = leftSide.IsNegative; bool rightSideNeg = rightSide.IsNegative; leftSide = Abs(leftSide); rightSide = Abs(rightSide); DigitsArray da = new DigitsArray(leftSide.m_digits.DataUsed + rightSide.m_digits.DataUsed); da.DataUsed = da.Count; for (int i = 0; i < leftSide.m_digits.DataUsed; i++) { ulong carry = 0; for (int j = 0, k = i; j < rightSide.m_digits.DataUsed; j++, k++) { ulong val = ((ulong)leftSide.m_digits[i] * (ulong)rightSide.m_digits[j]) + (ulong)da[k] + carry; da[k] = (DType)(val & DigitsArray.AllBits); carry = (val >> DigitsArray.DataSizeBits); } if (carry != 0) { da[i + rightSide.m_digits.DataUsed] = (DType)carry; } } //da.ResetDataUsed(); BigInteger result = new BigInteger(da); return (leftSideNeg != rightSideNeg ? -result : result); }
private static void MultiDivide(BigInteger leftSide, BigInteger rightSide, out BigInteger quotient, out BigInteger remainder) { if (rightSide.IsZero) { throw new DivideByZeroException(); } DType val = rightSide.m_digits[rightSide.m_digits.DataUsed - 1]; int d = 0; for (uint mask = DigitsArray.HiBitSet; mask != 0 && (val & mask) == 0; mask >>= 1) { d++; } int remainderLen = leftSide.m_digits.DataUsed + 1; DType[] remainderDat = new DType[remainderLen]; leftSide.m_digits.CopyTo(remainderDat, 0, leftSide.m_digits.DataUsed); DigitsArray.ShiftLeft(remainderDat, d); rightSide = rightSide << d; ulong firstDivisor = rightSide.m_digits[rightSide.m_digits.DataUsed - 1]; ulong secondDivisor = (rightSide.m_digits.DataUsed < 2 ? (DType)0 : rightSide.m_digits[rightSide.m_digits.DataUsed - 2]); int divisorLen = rightSide.m_digits.DataUsed + 1; DigitsArray dividendPart = new DigitsArray(divisorLen, divisorLen); DType[] result = new DType[leftSide.m_digits.Count + 1]; int resultPos = 0; ulong carryBit = (ulong)0x1 << DigitsArray.DataSizeBits; // 0x100000000 for (int j = remainderLen - rightSide.m_digits.DataUsed, pos = remainderLen - 1; j > 0; j--, pos--) { ulong dividend = ((ulong)remainderDat[pos] << DigitsArray.DataSizeBits) + (ulong)remainderDat[pos - 1]; ulong qHat = (dividend / firstDivisor); ulong rHat = (dividend % firstDivisor); while (pos >= 2) { if (qHat == carryBit || (qHat * secondDivisor) > ((rHat << DigitsArray.DataSizeBits) + remainderDat[pos - 2])) { qHat--; rHat += firstDivisor; if (rHat < carryBit) { continue; } } break; } for (int h = 0; h < divisorLen; h++) { dividendPart[divisorLen - h - 1] = remainderDat[pos - h]; } BigInteger dTemp = new BigInteger(dividendPart); BigInteger rTemp = rightSide * (long)qHat; while (rTemp > dTemp) { qHat--; rTemp -= rightSide; } rTemp = dTemp - rTemp; for (int h = 0; h < divisorLen; h++) { remainderDat[pos - h] = rTemp.m_digits[rightSide.m_digits.DataUsed - h]; } result[resultPos++] = (DType)qHat; } Array.Reverse(result, 0, resultPos); quotient = new BigInteger(new DigitsArray(result)); int n = DigitsArray.ShiftRight(remainderDat, d); DigitsArray rDA = new DigitsArray(n, n); rDA.CopyFrom(remainderDat, 0, 0, rDA.DataUsed); remainder = new BigInteger(rDA); }
/// <summary> /// Substracts two BigIntegers and returns a new BigInteger that represents the sum. /// </summary> /// <param name="leftSide">A BigInteger</param> /// <param name="rightSide">A BigInteger</param> /// <returns>The BigInteger result of substracting <paramref name="leftSide" /> and <paramref name="rightSide" />.</returns> public static BigInteger operator - (BigInteger leftSide, BigInteger rightSide) { int size = System.Math.Max(leftSide.m_digits.DataUsed, rightSide.m_digits.DataUsed) + 1; DigitsArray da = new DigitsArray(size); long carry = 0; for (int i = 0; i < da.Count; i++) { long diff = (long)leftSide.m_digits[i] - (long)rightSide.m_digits[i] - carry; da[i] = (DType)(diff & DigitsArray.AllBits); da.DataUsed++; carry = ((diff < 0) ? 1 : 0); } return new BigInteger(da); }
/// <summary> /// Negates the BigInteger, that is, if the BigInteger is negative return a positive BigInteger, and if the /// BigInteger is negative return the postive. /// </summary> /// <param name="leftSide">A BigInteger operand.</param> /// <returns>The value of the <paramref name="this" /> negated.</returns> public static BigInteger operator - (BigInteger leftSide) { if (object.ReferenceEquals(leftSide, null)) { throw new ArgumentNullException("leftSide"); } if (leftSide.IsZero) { return new BigInteger(0); } DigitsArray da = new DigitsArray(leftSide.m_digits.DataUsed + 1, leftSide.m_digits.DataUsed + 1); for (int i = 0; i < da.Count; i++) { da[i] = (DType)(~(leftSide.m_digits[i])); } // add one to result (1's complement + 1) bool carry = true; int index = 0; while (carry && index < da.Count) { long val = (long)da[index] + 1; da[index] = (DType)(val & DigitsArray.AllBits); carry = ((val >> DigitsArray.DataSizeBits) > 0); index++; } return new BigInteger(da); }
/// <summary> /// Copy constructor, doesn't copy the digits parameter, assumes <code>this</code> owns the DigitsArray. /// </summary> /// <remarks>The <paramef name="digits" /> parameter is saved and reset.</remarks> /// <param name="digits"></param> private BigInteger(DigitsArray digits) { digits.ResetDataUsed(); this.m_digits = digits; }
/// <summary> /// Adds two BigIntegers and returns a new BigInteger that represents the sum. /// </summary> /// <param name="leftSide">A BigInteger</param> /// <param name="rightSide">A BigInteger</param> /// <returns>The BigInteger result of adding <paramref name="leftSide" /> and <paramref name="rightSide" />.</returns> public static BigInteger operator + (BigInteger leftSide, BigInteger rightSide) { int size = System.Math.Max(leftSide.m_digits.DataUsed, rightSide.m_digits.DataUsed); DigitsArray da = new DigitsArray(size + 1); long carry = 0; for (int i = 0; i < da.Count; i++) { long sum = (long)leftSide.m_digits[i] + (long)rightSide.m_digits[i] + carry; carry = (long)(sum >> DigitsArray.DataSizeBits); da[i] = (DType)(sum & DigitsArray.AllBits); } return new BigInteger(da); }
internal DigitsArray(DigitsArray copyFrom) { Allocate(copyFrom.Count, copyFrom.DataUsed); Array.Copy(copyFrom.m_data, 0, m_data, 0, copyFrom.Count); }
private void Construct(string digits, int radix) { if (digits == null) { throw new ArgumentNullException("digits"); } BigInteger multiplier = new BigInteger(1); BigInteger result = new BigInteger(); digits = digits.ToUpper(System.Globalization.CultureInfo.CurrentCulture).Trim(); int nDigits = (digits[0] == '-' ? 1 : 0); for (int idx = digits.Length - 1; idx >= nDigits ; idx--) { int d = (int)digits[idx]; if (d >= '0' && d <= '9') { d -= '0'; } else if (d >= 'A' && d <= 'Z') { d = (d - 'A') + 10; } else { throw new ArgumentOutOfRangeException("digits"); } if (d >= radix) { throw new ArgumentOutOfRangeException("digits"); } result += (multiplier * d); multiplier *= radix; } if (digits[0] == '-') { result = -result; } this.m_digits = result.m_digits; }
/// <summary> /// Creates a BigInteger with the value of the operand. Can never be negative. /// </summary> /// <param name="number">A unsigned long.</param> public BigInteger(ulong number) { m_digits = new DigitsArray((8 / DigitsArray.DataSizeOf) + 1, 0); while (number != 0 && m_digits.DataUsed < m_digits.Count) { m_digits[m_digits.DataUsed] = (DType)(number & DigitsArray.AllBits); number >>= DigitsArray.DataSizeBits; m_digits.DataUsed++; } m_digits.ResetDataUsed(); }
private void ConstructFrom(byte[] array, int offset, int length) { if (array == null) { throw new ArgumentNullException("array"); } if (offset > array.Length || length > array.Length) { throw new ArgumentOutOfRangeException("offset"); } if (length > array.Length || (offset + length) > array.Length) { throw new ArgumentOutOfRangeException("length"); } int estSize = length / 4; int leftOver = length & 3; if (leftOver != 0) { ++estSize; } m_digits = new DigitsArray(estSize + 1, 0); // alloc one extra since we can't init -'s from here. for (int i = offset + length - 1, j = 0; (i - offset) >= 3; i -= 4, j++) { m_digits[j] = (DType)((array[i - 3] << 24) + (array[i - 2] << 16) + (array[i - 1] << 8) + array[i]); m_digits.DataUsed++; } DType accumulator = 0; for (int i = leftOver; i > 0; i--) { DType digit = array[offset + leftOver - i]; digit = (digit << ((i - 1) * 8)); accumulator |= digit; } m_digits[m_digits.DataUsed] = accumulator; m_digits.ResetDataUsed(); }
/// <summary> /// Create a BigInteger with an integer value of 0. /// </summary> public BigInteger() { m_digits = new DigitsArray(1, 1); }
public static BigInteger operator >> (BigInteger leftSide, int shiftCount) { if (leftSide == null) { throw new ArgumentNullException("leftSide"); } DigitsArray da = new DigitsArray(leftSide.m_digits); da.DataUsed = da.ShiftRight(shiftCount); if (leftSide.IsNegative) { for (int i = da.Count - 1; i >= da.DataUsed; i--) { da[i] = DigitsArray.AllBits; } DType mask = DigitsArray.HiBitSet; for (int i = 0; i < DigitsArray.DataSizeBits; i++) { if ((da[da.DataUsed - 1] & mask) == DigitsArray.HiBitSet) { break; } da[da.DataUsed - 1] |= mask; mask >>= 1; } da.DataUsed = da.Count; } return new BigInteger(da); }
public static BigInteger operator << (BigInteger leftSide, int shiftCount) { if (leftSide == null) { throw new ArgumentNullException("leftSide"); } DigitsArray da = new DigitsArray(leftSide.m_digits); da.DataUsed = da.ShiftLeftWithoutOverflow(shiftCount); return new BigInteger(da); }
public static BigInteger operator ~ (BigInteger leftSide) { DigitsArray da = new DigitsArray(leftSide.m_digits.Count); for(int idx = 0; idx < da.Count; idx++) { da[idx] = (DType)(~(leftSide.m_digits[idx])); } return new BigInteger(da); }
public static BigInteger operator ^ (BigInteger leftSide, BigInteger rightSide) { int len = System.Math.Max(leftSide.m_digits.DataUsed, rightSide.m_digits.DataUsed); DigitsArray da = new DigitsArray(len, len); for (int idx = 0; idx < len; idx++) { da[idx] = (DType)(leftSide.m_digits[idx] ^ rightSide.m_digits[idx]); } return new BigInteger(da); }