/// <summary> /// Schoolbook division helper function. /// </summary> /// <param name="n1"></param> /// <param name="n2"></param> /// <param name="Q">Quotient output value</param> /// <param name="R">Remainder output value</param> private static void Div_31(BigInt n1, BigInt n2, BigInt Q, BigInt R) { int digitsN1 = n1.GetMSD() + 1; int digitsN2 = n2.GetMSD() + 1; if ((digitsN1 > digitsN2)) { BigInt n1New = new BigInt(n2); n1New.DigitShiftSelfLeft(1); //If n1 >= n2 * 2^32 if (!LtInt(n1, n1New)) { n1New.sign = n1.sign; SubFast(n1New, n1, n1New); Div_32(n1New, n2, Q, R); //Q = (A - B*2^32)/B + 2^32 Q.Add2Pow32Self(); return; } } UInt32 q = 0; if (digitsN1 >= 2) { UInt64 q64 = ((((UInt64)n1.digitArray[digitsN1 - 1]) << 32) + n1.digitArray[digitsN1 - 2]) / (UInt64)n2.digitArray[digitsN2 - 1]; if (q64 > 0xfffffffful) { q = 0xffffffff; } else { q = (UInt32)q64; } } BigInt temp = Mul(n2, q); if (GtInt(temp, n1)) { temp.SubInternalBits(n2.digitArray); q--; if (GtInt(temp, n1)) { temp.SubInternalBits(n2.digitArray); q--; } } Q.Zero(); Q.digitArray[0] = q; R.Assign(n1); R.SubInternalBits(temp.digitArray); }
/// <summary> /// Schoolbook division algorithm /// </summary> /// <param name="n1"></param> /// <param name="n2"></param> /// <param name="Q"></param> /// <param name="R"></param> private static void Div_32(BigInt n1, BigInt n2, BigInt Q, BigInt R) { int digitsN1 = n1.GetMSD() + 1; int digitsN2 = n2.GetMSD() + 1; //n2 is bigger than n1 if (digitsN1 < digitsN2) { R.AssignInt(n1); Q.Zero(); return; } if (digitsN1 == digitsN2) { //n2 is bigger than n1 if (LtInt(n1, n2)) { R.AssignInt(n1); Q.Zero(); return; } //n2 >= n1, but less the 2x n1 (initial conditions make this certain) Q.Zero(); Q.digitArray[0] = 1; R.Assign(n1); R.SubInternalBits(n2.digitArray); return; } int digits = digitsN1 - (digitsN2 + 1); //Algorithm Div_31 can be used to get the answer in O(n) time. if (digits == 0) { Div_31(n1, n2, Q, R); return; } BigInt n1New = DigitShiftRight(n1, digits); BigInt s = DigitTruncate(n1, digits); BigInt Q2 = new BigInt(n1, n1.pres, true); BigInt R2 = new BigInt(n1, n1.pres, true); Div_31(n1New, n2, Q2, R2); R2.DigitShiftSelfLeft(digits); R2.Add(s); Div_32(R2, n2, Q, R); Q2.DigitShiftSelfLeft(digits); Q.Add(Q2); }
/// <summary> /// Adds n1 and n2 and puts result in dest, without intermediate memory allocation /// (unsafe if n1 and n2 disagree in precision, safe even if dest is n1 or n2) /// </summary> /// <param name="dest"></param> /// <param name="n1"></param> /// <param name="n2"></param> public static void SubFast(BigInt dest, BigInt n1, BigInt n2) { //We cast to the highest input precision... if (n1.digitArray.Length != n2.digitArray.Length) MakeSafe(ref n1, ref n2); //Then we up the output precision if less than the input precision. if (dest.digitArray.Length < n1.digitArray.Length) n1.MakeSafe(ref dest); int Length = n1.digitArray.Length; if (n1.sign != n2.sign) { //Copies sources into digit array and working set for all cases, to avoid //problems when dest is n1 or n2 for (int i = 0; i < Length; i++) { dest.workingSet[i] = n2.digitArray[i]; dest.digitArray[i] = n1.digitArray[i]; } dest.AddInternalBits(dest.workingSet); dest.sign = n1.sign; } else { bool lessThan = LtInt(n1, n2); if (lessThan) { for (int i = 0; i < Length; i++) { dest.workingSet[i] = n1.digitArray[i]; dest.digitArray[i] = n2.digitArray[i]; } dest.SubInternalBits(dest.workingSet); dest.sign = !n1.sign; } else { for (int i = 0; i < Length; i++) { dest.workingSet[i] = n2.digitArray[i]; dest.digitArray[i] = n1.digitArray[i]; } dest.SubInternalBits(dest.workingSet); dest.sign = n1.sign; } } }