예제 #1
0
        // 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);
            }
        }
예제 #2
0
        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()."));
            }
        }
예제 #3
0
        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);
        }