/// <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); }
//************************** Conversions ************************* /// <summary> /// Converts a BigFloat to an BigInt with the specified precision /// </summary> /// <param name="n1">The number to convert</param> /// <param name="precision">The precision to convert it with</param> /// <param name="round">Do we round the number if we are truncating the mantissa?</param> /// <returns></returns> public static BigInt ConvertToInt(BigFloat n1, PrecisionSpec precision, bool round) { BigInt ret = new BigInt(precision); int numBits = n1.mantissa.Precision.NumBits; int shift = numBits - (n1.exponent + 1); BigFloat copy = new BigFloat(n1); bool inc = false; //Rounding if (copy.mantissa.Precision.NumBits > ret.Precision.NumBits) { inc = true; for (int i = copy.exponent + 1; i <= ret.Precision.NumBits; i++) { if (copy.mantissa.GetBitFromTop(i) == 0) { inc = false; break; } } } if (shift > 0) { copy.mantissa.RSH(shift); } else if (shift < 0) { copy.mantissa.LSH(-shift); } ret.Assign(copy.mantissa); if (inc) ret.Increment(); return ret; }
/// <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); }