/// <summary> /// See BigInteger#add(BigInteger) /// </summary> internal static BigInteger Add(BigInteger A, BigInteger B) { int[] resDigits; int resSign; int op1Sign = A._sign; int op2Sign = B._sign; if (op1Sign == 0) { return(B); } if (op2Sign == 0) { return(A); } int op1Len = A._numberLength; int op2Len = B._numberLength; if (op1Len + op2Len == 2) { long a = (A._digits[0] & 0xFFFFFFFFL); long b = (B._digits[0] & 0xFFFFFFFFL); long res; int valueLo; int valueHi; if (op1Sign == op2Sign) { res = a + b; valueLo = (int)res; valueHi = (int)IntUtils.URShift(res, 32); return((valueHi == 0) ? new BigInteger(op1Sign, valueLo) : new BigInteger(op1Sign, 2, new int[] { valueLo, valueHi })); } return(BigInteger.ValueOf((op1Sign < 0) ? (b - a) : (a - b))); } else if (op1Sign == op2Sign) { resSign = op1Sign; // an augend should not be shorter than addend resDigits = (op1Len >= op2Len) ? Add(A._digits, op1Len, B._digits, op2Len) : Add(B._digits, op2Len, A._digits, op1Len); } else { // signs are different int cmp = ((op1Len != op2Len) ? ((op1Len > op2Len) ? 1 : -1) : CompareArrays(A._digits, B._digits, op1Len)); if (cmp == BigInteger.EQUALS) { return(BigInteger.Zero); } // a minuend should not be shorter than subtrahend if (cmp == BigInteger.GREATER) { resSign = op1Sign; resDigits = Subtract(A._digits, op1Len, B._digits, op2Len); } else { resSign = op2Sign; resDigits = Subtract(B._digits, op2Len, A._digits, op1Len); } } BigInteger result = new BigInteger(resSign, resDigits.Length, resDigits); result.CutOffLeadingZeroes(); return(result); }
/// <summary> /// Divides the array 'a' by the array 'b' and gets the quotient and the remainder. /// <para>Implements the Knuth's division algorithm. See D. Knuth, The Art of Computer Programming, /// vol. 2. Steps D1-D8 correspond the steps in the algorithm description.</para> /// </summary> /// /// <param name="Quotient">The quotient</param> /// <param name="QuotientLen">The quotient's length</param> /// <param name="X">The dividend</param> /// <param name="XLen">The dividend's length</param> /// <param name="Y">The divisor</param> /// <param name="YLength">The divisor's length</param> /// /// <returns>eturn the remainder</returns> internal static int[] Divide(int[] Quotient, int QuotientLen, int[] X, int XLen, int[] Y, int YLength) { int[] normA = new int[XLen + 1]; // the normalized dividend // an extra byte is needed for correct shift int[] normB = new int[YLength + 1]; // the normalized divisor; int normBLength = YLength; // Step D1: normalize a and b and put the results to a1 and b1 the // normalized divisor's first digit must be >= 2^31 int divisorShift = IntUtils.NumberOfLeadingZeros(Y[YLength - 1]); if (divisorShift != 0) { BitLevel.ShiftLeft(normB, Y, 0, divisorShift); BitLevel.ShiftLeft(normA, X, 0, divisorShift); } else { Array.Copy(X, 0, normA, 0, XLen); Array.Copy(Y, 0, normB, 0, YLength); } int firstDivisorDigit = normB[normBLength - 1]; // Step D2: set the quotient index int i = QuotientLen - 1; int j = XLen; while (i >= 0) { // Step D3: calculate a guess digit guessDigit int guessDigit = 0; if (normA[j] == firstDivisorDigit) { // set guessDigit to the largest unsigned int value guessDigit = -1; } else { long product = (((normA[j] & 0xffffffffL) << 32) + (normA[j - 1] & 0xffffffffL)); long res = Division.DivideLongByInt(product, firstDivisorDigit); guessDigit = (int)res; // the quotient of divideLongByInt int rem = (int)(res >> 32); // the remainder of // divideLongByInt // decrease guessDigit by 1 while leftHand > rightHand if (guessDigit != 0) { long leftHand = 0; long rightHand = 0; bool rOverflowed = false; guessDigit++; // to have the proper value in the loop // below do { guessDigit--; if (rOverflowed) { break; } // leftHand always fits in an unsigned long leftHand = (guessDigit & 0xffffffffL) * (normB[normBLength - 2] & 0xffffffffL); // rightHand can overflow; in this case the loop // condition will be true in the next step of the loop rightHand = ((long)rem << 32) + (normA[j - 2] & 0xffffffffL); long longR = (rem & 0xffffffffL) + (firstDivisorDigit & 0xffffffffL); // checks that longR does not fit in an unsigned int; // this ensures that rightHand will overflow unsigned long in the next step if (IntUtils.NumberOfLeadingZeros((int)IntUtils.URShift(longR, 32)) < 32) { rOverflowed = true; } else { rem = (int)longR; } } while ((leftHand ^ Int64.MinValue) > (rightHand ^ Int64.MinValue)); } } // Step D4: multiply normB by guessDigit and subtract the production from normA. if (guessDigit != 0) { int borrow = Division.MultiplyAndSubtract(normA, j - normBLength, normB, normBLength, guessDigit); // Step D5: check the borrow if (borrow != 0) { // Step D6: compensating addition guessDigit--; long carry = 0; for (int k = 0; k < normBLength; k++) { carry += (normA[j - normBLength + k] & 0xffffffffL) + (normB[k] & 0xffffffffL); normA[j - normBLength + k] = (int)carry; carry = IntUtils.URShift(carry, 32); } } } if (Quotient != null) { Quotient[i] = guessDigit; } // Step D7 j--; i--; } // Step D8: we got the remainder in normA. Denormalize it as needed if (divisorShift != 0) { // reuse normB BitLevel.ShiftRight(normB, normBLength, normA, 0, divisorShift); return(normB); } Array.Copy(normA, 0, normB, 0, YLength); return(normA); }