private void LongDivide3( Integer ToDivide, Integer DivideBy, Integer Quotient, Integer Remainder ) { 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 ); 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 ); MultiplyTop( TestForDivide1, DivideBy ); /* Test2.Copy( Quotient ); Test2.SetD( TestIndex, MaxValue ); 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 ); MultiplyTop( TestForDivide1, DivideBy ); /* Test2.Copy( Quotient ); Test2.SetD( TestIndex, MaxValue ); Multiply( Test2, DivideBy ); if( !Test2.IsEqual( Test1 )) throw( new Exception( "Top one. !Test2.IsEqual( Test1 ) in LongDivide3()" )); */ 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 ); Multiply( TestForDivide1, DivideByKeep ); Remainder.Copy( ToDivideKeep ); 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. Multiply( TestForDivide1, DivideBy ); // if( ToDivide.ParamIsGreater( TestForDivide1 )) // throw( new Exception( "Bug here in LongDivide3()." )); Remainder.Copy( ToDivide ); 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. 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 ); 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 ); Multiply( TestForDivide1, DivideByKeep ); Remainder.Copy( ToDivideKeep ); Subtract( Remainder, TestForDivide1 ); // if( DivideByKeep.ParamIsGreater( Remainder )) // throw( new Exception( "Remainder > DivideBy in LongDivide3()." )); }
// Finding the square root of a number is similar to division since // it is a search algorithm. The TestSqrtBits method shown next is // very much like TestDivideBits(). It works the same as // FindULSqrRoot(), but on a bigger scale. /* private void TestSqrtBits( int TestIndex, Integer Square, Integer SqrRoot ) { Integer Test1 = new Integer(); uint BitTest = 0x80000000; for( int BitCount = 31; BitCount >= 0; BitCount-- ) { Test1.Copy( SqrRoot ); Test1.D[TestIndex] |= BitTest; Test1.Square(); if( !Square.ParamIsGreater( Test1 ) ) SqrRoot.D[TestIndex] |= BitTest; // Use the bit. BitTest >>= 1; } } */ // In the SquareRoot() method SqrRoot.Index is half of Square.Index. // Compare this to the Square() method where the Carry might or // might not increment the index to an odd number. (So if the Index // was 5 its square root would have an Index of 5 / 2 = 2.) // The SquareRoot1() method uses FindULSqrRoot() either to find the // whole answer, if it's a small number, or it uses it to find the // top part. Then from there it goes on to a bit by bit search // with TestSqrtBits(). public bool SquareRoot( Integer Square, Integer SqrRoot ) { ulong ToMatch; if( Square.IsULong() ) { ToMatch = Square.GetAsULong(); SqrRoot.SetD( 0, FindULSqrRoot( ToMatch )); SqrRoot.SetIndex( 0 ); if( (SqrRoot.GetD(0 ) * SqrRoot.GetD( 0 )) == ToMatch ) return true; else return false; } int TestIndex = Square.GetIndex() >> 1; // LgSquare.Index / 2; SqrRoot.SetDigitAndClear( TestIndex, 1 ); // if( (TestIndex * 2) > (LgSquare.Index - 1) ) if( (TestIndex << 1) > (Square.GetIndex() - 1) ) { ToMatch = Square.GetD( Square.GetIndex()); } else { // LgSquare.Index is at least 2 here. ToMatch = Square.GetD( Square.GetIndex()) << 32; ToMatch |= Square.GetD( Square.GetIndex() - 1 ); } SqrRoot.SetD( TestIndex, FindULSqrRoot( ToMatch )); TestIndex--; while( true ) { // TestSqrtBits( TestIndex, LgSquare, LgSqrRoot ); SearchSqrtXPart( TestIndex, Square, SqrRoot ); if( TestIndex == 0 ) break; TestIndex--; } // Avoid squaring the whole thing to see if it's an exact square root: if( ((SqrRoot.GetD( 0 ) * SqrRoot.GetD( 0 )) & 0xFFFFFFFF) != Square.GetD( 0 )) return false; TestForSquareRoot.Copy( SqrRoot ); DoSquare( TestForSquareRoot ); if( Square.IsEqual( TestForSquareRoot )) return true; else return false; }