public static BigInteger ShiftLeft(BigInteger value, int n) { if ((n == 0) || (value.Sign == 0)) { return(value); } return((n > 0) ? BitLevel.ShiftLeft(value, n) : BitLevel.ShiftRight(value, -n)); }
/** * Divides the array 'a' by the array 'b' and gets the quotient and the * remainder. 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. * * @param quot the quotient * @param quotLength the quotient's length * @param a the dividend * @param aLength the dividend's length * @param b the divisor * @param bLength the divisor's length * @return the remainder */ public static int[] Divide(int[] quot, int quotLength, int[] a, int aLength, int[] b, int bLength) { int[] normA = new int[aLength + 1]; // the normalized dividend // an extra byte is needed for correct shift int[] normB = new int[bLength + 1]; // the normalized divisor; int normBLength = bLength; /* * 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 = Utils.NumberOfLeadingZeros(b[bLength - 1]); if (divisorShift != 0) { BitLevel.ShiftLeft(normB, b, 0, divisorShift); BitLevel.ShiftLeft(normA, a, 0, divisorShift); } else { Array.Copy(a, 0, normA, 0, aLength); Array.Copy(b, 0, normB, 0, bLength); } int firstDivisorDigit = normB[normBLength - 1]; // Step D2: set the quotient index int i = quotLength - 1; int j = aLength; 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 (Utils.NumberOfLeadingZeros((int)Utils.URShift(longR, 32)) < 32) { rOverflowed = true; } else { rem = (int)longR; } } while ((leftHand ^ Int64.MinValue) > (rightHand ^ Int64.MinValue)); //} while ((leftHand ^ Int64.MaxValue) > (rightHand ^ Int64.MaxValue)); // while (((leftHand ^ 0x8000000000000000L) > (rightHand ^ 0x8000000000000000L))) ; } } // 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 = Utils.URShift(carry, 32); } } } if (quot != null) { quot[i] = guessDigit; } // Step D7 j--; i--; } /* * Step D8: we got the remainder in normA. Denormalize it id needed */ if (divisorShift != 0) { // reuse normB BitLevel.ShiftRight(normB, normBLength, normA, 0, divisorShift); return(normB); } Array.Copy(normA, 0, normB, 0, bLength); return(normA); }