// This works like LongDivide1 except that it // estimates the maximum value for the digit and // the for-loop for bit testing is called // as a separate function. private bool LongDivide2(Integer ToDivide, Integer DivideBy, Integer Quotient, Integer Remainder) { Integer Test1 = new Integer(); int TestIndex = ToDivide.GetIndex() - DivideBy.GetIndex(); // See if TestIndex is too high. if (TestIndex != 0) { // Is 1 too high? Test1.SetDigitAndClear(TestIndex, 1); IntMath.MultiplyTopOne(Test1, DivideBy); if (ToDivide.ParamIsGreater(Test1)) { TestIndex--; } } // If you were multiplying 99 times 97 you'd get // 9,603 and the upper two digits [96] are used // to find the MaxValue. But if you multiply // 12 * 13 you'd have 156 and only the upper one // digit is used to find the MaxValue. // Here it checks if it should use one digit or // two: ulong MaxValue; if ((ToDivide.GetIndex() - 1) > (DivideBy.GetIndex() + TestIndex)) { MaxValue = ToDivide.GetD(ToDivide.GetIndex()); } else { MaxValue = ToDivide.GetD(ToDivide.GetIndex()) << 32; MaxValue |= ToDivide.GetD(ToDivide.GetIndex() - 1); } MaxValue = MaxValue / DivideBy.GetD(DivideBy.GetIndex()); Quotient.SetDigitAndClear(TestIndex, 1); Quotient.SetD(TestIndex, 0); TestDivideBits(MaxValue, true, TestIndex, ToDivide, DivideBy, Quotient, Remainder); if (TestIndex == 0) { Test1.Copy(Quotient); IntMath.Multiply(Test1, DivideBy); Remainder.Copy(ToDivide); IntMath.Subtract(Remainder, Test1); /////////////// if (DivideBy.ParamIsGreater(Remainder)) { throw(new Exception("Remainder > DivideBy in LongDivide2().")); } ////////////// if (Remainder.IsZero()) { return(true); } else { return(false); } } TestIndex--; while (true) { // This remainder is used the same way you do // long division with paper and pen and you // keep working with a remainder until the // remainder is reduced to something smaller // than DivideBy. You look at the remainder // to estimate your next quotient digit. Test1.Copy(Quotient); IntMath.Multiply(Test1, DivideBy); Remainder.Copy(ToDivide); IntMath.Subtract(Remainder, Test1); MaxValue = Remainder.GetD(Remainder.GetIndex()) << 32; MaxValue |= Remainder.GetD(Remainder.GetIndex() - 1); MaxValue = MaxValue / DivideBy.GetD(DivideBy.GetIndex()); TestDivideBits(MaxValue, false, TestIndex, ToDivide, DivideBy, Quotient, Remainder); if (TestIndex == 0) { break; } TestIndex--; } Test1.Copy(Quotient); IntMath.Multiply(Test1, DivideBy); Remainder.Copy(ToDivide); IntMath.Subtract(Remainder, Test1); ////////////////////////////// if (DivideBy.ParamIsGreater(Remainder)) { throw(new Exception("Remainder > DivideBy in LongDivide2().")); } //////////////////////////////// if (Remainder.IsZero()) { return(true); } else { return(false); } }
private void LongDivide3(Integer ToDivide, Integer DivideBy, Integer Quotient, Integer Remainder) { ////////////////// Integer Test2 = new Integer(); ///////////////// int TestIndex = ToDivide.GetIndex() - DivideBy.GetIndex(); if (TestIndex < 0) { throw(new Exception("TestIndex < 0 in Divide3.")); } if (TestIndex != 0) { // Is 1 too high? TestForDivide1.SetDigitAndClear(TestIndex, 1); IntMath.MultiplyTopOne(TestForDivide1, DivideBy); if (ToDivide.ParamIsGreater(TestForDivide1)) { TestIndex--; } } // Keep a copy of the originals. ToDivideKeep.Copy(ToDivide); DivideByKeep.Copy(DivideBy); ulong TestBits = DivideBy.GetD(DivideBy.GetIndex()); int ShiftBy = FindShiftBy(TestBits); ToDivide.ShiftLeft(ShiftBy); // Multiply the numerator and the denominator DivideBy.ShiftLeft(ShiftBy); // by the same amount. ulong MaxValue; if ((ToDivide.GetIndex() - 1) > (DivideBy.GetIndex() + TestIndex)) { MaxValue = ToDivide.GetD(ToDivide.GetIndex()); } else { MaxValue = ToDivide.GetD(ToDivide.GetIndex()) << 32; MaxValue |= ToDivide.GetD(ToDivide.GetIndex() - 1); } ulong Denom = DivideBy.GetD(DivideBy.GetIndex()); if (Denom != 0) { MaxValue = MaxValue / Denom; } else { MaxValue = 0xFFFFFFFF; } if (MaxValue > 0xFFFFFFFF) { MaxValue = 0xFFFFFFFF; } if (MaxValue == 0) { throw(new Exception("MaxValue is zero at the top in LongDivide3().")); } Quotient.SetDigitAndClear(TestIndex, 1); Quotient.SetD(TestIndex, 0); TestForDivide1.Copy(Quotient); TestForDivide1.SetD(TestIndex, MaxValue); IntMath.MultiplyTop(TestForDivide1, DivideBy); ///////////// Test2.Copy(Quotient); Test2.SetD(TestIndex, MaxValue); IntMath.Multiply(Test2, DivideBy); if (!Test2.IsEqual(TestForDivide1)) { throw(new Exception("In Divide3() !IsEqual( Test2, TestForDivide1 )")); } /////////// if (TestForDivide1.ParamIsGreaterOrEq(ToDivide)) { // ToMatchExactCount++; // Most of the time (roughly 5 out of every 6 // times) this MaxValue estimate is exactly // right: Quotient.SetD(TestIndex, MaxValue); } else { // MaxValue can't be zero here. If it was it // would already be low enough before it got // here. MaxValue--; if (MaxValue == 0) { throw(new Exception("After decrement: MaxValue is zero in LongDivide3().")); } TestForDivide1.Copy(Quotient); TestForDivide1.SetD(TestIndex, MaxValue); IntMath.MultiplyTop(TestForDivide1, DivideBy); if (TestForDivide1.ParamIsGreaterOrEq(ToDivide)) { // ToMatchDecCount++; Quotient.SetD(TestIndex, MaxValue); } else { // TestDivideBits is done as a last resort, // but it's rare. But it does at least limit // it to a worst case scenario of trying 32 // bits, rather than 4 billion or so // decrements. TestDivideBits(MaxValue, true, TestIndex, ToDivide, DivideBy, Quotient, Remainder); } // TestGap = MaxValue - LgQuotient.D[TestIndex]; // if( TestGap > HighestToMatchGap ) // HighestToMatchGap = TestGap; // HighestToMatchGap: 4,294,967,293 // uint size: 4,294,967,295 uint } // If it's done. if (TestIndex == 0) { TestForDivide1.Copy(Quotient); IntMath.Multiply(TestForDivide1, DivideByKeep); Remainder.Copy(ToDivideKeep); IntMath.Subtract(Remainder, TestForDivide1); if (DivideByKeep.ParamIsGreater(Remainder)) { throw(new Exception("Remainder > DivideBy in LongDivide3().")); } return; } // Now do the rest of the digits. TestIndex--; while (true) { TestForDivide1.Copy(Quotient); // First Multiply() for each digit. IntMath.Multiply(TestForDivide1, DivideBy); if (ToDivide.ParamIsGreater(TestForDivide1)) { throw(new Exception("Problem here in LongDivide3().")); } Remainder.Copy(ToDivide); IntMath.Subtract(Remainder, TestForDivide1); MaxValue = Remainder.GetD(Remainder.GetIndex()) << 32; int CheckIndex = Remainder.GetIndex() - 1; if (CheckIndex > 0) { MaxValue |= Remainder.GetD(CheckIndex); } Denom = DivideBy.GetD(DivideBy.GetIndex()); if (Denom != 0) { MaxValue = MaxValue / Denom; } else { MaxValue = 0xFFFFFFFF; } if (MaxValue > 0xFFFFFFFF) { MaxValue = 0xFFFFFFFF; } TestForDivide1.Copy(Quotient); TestForDivide1.SetD(TestIndex, MaxValue); // There's a minimum of two full Multiply() operations per digit. IntMath.Multiply(TestForDivide1, DivideBy); if (TestForDivide1.ParamIsGreaterOrEq(ToDivide)) { // Most of the time this MaxValue estimate is exactly right: // ToMatchExactCount++; Quotient.SetD(TestIndex, MaxValue); } else { MaxValue--; TestForDivide1.Copy(Quotient); TestForDivide1.SetD(TestIndex, MaxValue); IntMath.Multiply(TestForDivide1, DivideBy); if (TestForDivide1.ParamIsGreaterOrEq(ToDivide)) { // ToMatchDecCount++; Quotient.SetD(TestIndex, MaxValue); } else { TestDivideBits(MaxValue, false, TestIndex, ToDivide, DivideBy, Quotient, Remainder); // TestGap = MaxValue - LgQuotient.D[TestIndex]; // if( TestGap > HighestToMatchGap ) // HighestToMatchGap = TestGap; } } if (TestIndex == 0) { break; } TestIndex--; } TestForDivide1.Copy(Quotient); IntMath.Multiply(TestForDivide1, DivideByKeep); Remainder.Copy(ToDivideKeep); IntMath.Subtract(Remainder, TestForDivide1); if (DivideByKeep.ParamIsGreater(Remainder)) { throw(new Exception("Remainder > DivideBy in LongDivide3().")); } }
private bool LongDivide1(Integer ToDivide, Integer DivideBy, Integer Quotient, Integer Remainder) { uint Digit = 0; Integer Test1 = new Integer(); int TestIndex = ToDivide.GetIndex() - DivideBy.GetIndex(); if (TestIndex != 0) { // Is 1 too high? Test1.SetDigitAndClear(TestIndex, 1); IntMath.MultiplyTopOne(Test1, DivideBy); if (ToDivide.ParamIsGreater(Test1)) { TestIndex--; } } Quotient.SetDigitAndClear(TestIndex, 1); Quotient.SetD(TestIndex, 0); uint BitTest = 0x80000000; while (true) { // For-loop to test each bit: for (int BitCount = 31; BitCount >= 0; BitCount--) { Test1.Copy(Quotient); Digit = (uint)Test1.GetD(TestIndex) | BitTest; Test1.SetD(TestIndex, Digit); IntMath.Multiply(Test1, DivideBy); if (Test1.ParamIsGreaterOrEq(ToDivide)) { Digit = (uint)Quotient.GetD(TestIndex) | BitTest; // I want to keep this bit because it // passed the test. Quotient.SetD(TestIndex, Digit); } BitTest >>= 1; } if (TestIndex == 0) { break; } TestIndex--; BitTest = 0x80000000; } Test1.Copy(Quotient); IntMath.Multiply(Test1, DivideBy); if (Test1.IsEqual(ToDivide)) { Remainder.SetToZero(); return(true); // Divides exactly. } Remainder.Copy(ToDivide); IntMath.Subtract(Remainder, Test1); // Does not divide it exactly. return(false); }