コード例 #1
0
ファイル: IntegerMath.cs プロジェクト: Eric7Apps/BlogSource
        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()." ));
        }
コード例 #2
0
ファイル: IntegerMath.cs プロジェクト: Eric7Apps/BlogSource
        // 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;
        }