Ejemplo n.º 1
0
        static void Div(
            Digits numer
            , Digit den
            , Reciprocal recip
            , Digits q
            , int n
            , Digits r
            )
        {
            Digit carry = 0;
            int   nLeft = n;

            if (nLeft > 0 && numer[nLeft - 1] < den)
            {
                nLeft--;
                carry = numer[nLeft];
                if (q != null)
                {
                    q[nLeft] = 0;
                }
            }
            if (recip == null && nLeft < 2)
            {
                for (int i = nLeft; i-- != 0;)
                {
                    Digit qest = 0;
                    Digit2.Div((UInt64)carry << Digit.BitN | numer[i]
                               , den
                               , out qest
                               , out carry);
                    if (q != null)
                    {
                        q[i] = qest;
                    }
                }
            }
            else
            {
                if (recip == null)
                {
                    recip = new Reciprocal();
                    DivPrecondition(new Digits(new Digit[] { den }), 1, recip);
                }
                for (int i = nLeft; i-- != 0;)
                {
                    Digit qest = 0;
                    Digit2.Div((UInt64)carry << Digit.BitN | numer[i]
                               , den
                               , recip
                               , out qest
                               , out carry);
                    if (q != null)
                    {
                        q[i] = qest;
                    }
                }
            }
            r[0] = carry;
        }
Ejemplo n.º 2
0
        DivPrecondition(Digits denom, int denomN, Reciprocal recip)
        {
            if (denom == null)
            {
                throw new ArgumentNullException();
            }
            if (denomN == 0 || denom[denomN - 1] == 0)
            {
                throw new ArgumentException();
            }
            int   recipBitShift = Digit.BitN - Digit.SigBitN(denom[denomN - 1]);
            Digit dlead2        = denom[denomN - 1]
            , dlead1            = denomN >= 2 ? denom[denomN - 2] : 0
            , dlead0            = denomN >= 3 ? denom[denomN - 3] : 0
            , dShiftHi          = dlead2 << recipBitShift
                         | dlead1 >> 1 >> Digit.BitN - 1 - recipBitShift
                , dShiftLo = dlead1 << recipBitShift
                         | dlead0 >> 1 >> Digit.BitN - 1 - recipBitShift;
            Digit recipMpy, r;

            Digit2.Div((UInt64)(Digit.MaxValue - dShiftHi) << Digit.BitN
                       | Digit.MaxValue - dShiftLo
                       , dShiftHi
                       , out recipMpy
                       , out r);
            if (Digit2.Hi((UInt64)recipMpy * dShiftLo) > r)
            {
                recipMpy -= 1;
            }
            r = (Digit.MaxValue >> recipBitShift) - denom[denomN - 1];
            for (int id = denomN; id-- != 0 && r < recipMpy;)
            {
                UInt64 test1 = (UInt64)r << Digit.BitN
                               | Digit.MaxValue - (id > 0 ? denom[id - 1] : 0)
                    , test2 = (UInt64)recipMpy * denom[id];
                if (test2 > test1)
                {
                    recipMpy -= 1; break;
                }
                test1 = test1 - test2;
                r     = Digit2.Lo(test1);
                if (Digit2.Hi(test1) != 0)
                {
                    break;
                }
            }
            recip._shiftBitN  = recipBitShift;
            recip._multiplier = recipMpy;
        }
Ejemplo n.º 3
0
        internal static void Div(
            UInt64 num
            , Digit denom
            , Reciprocal recip
            , out Digit q
            , out Digit r
            )
        {
            Digit numHi = Hi(num)
            , numLo     = Lo(num)
            , qEst      = Digit.MaxValue - recip.EstQuotient(numHi, numLo, 0);
            UInt64 rEst = unchecked (
                ((UInt64)(numHi - denom) << Digit.BitN | numLo)
                + (UInt64)qEst * denom
                );

            q = unchecked ((Digit)(Hi(rEst) - qEst));
            r = unchecked (Lo(rEst) + (denom & Hi(rEst)));
            Digit qq, rr;

            Div(num, denom, out qq, out rr);
            Debug.Assert(qq == q && rr == r, "internal error");
        }
Ejemplo n.º 4
0
        internal Modulus(Digits mod, int digitN, bool fromRight)
        {
            if (digitN == 0 || mod[digitN - 1] == 0)
            {
                throw new ArgumentException();
            }
            _mod         = mod;
            _digitN      = digitN;
            _fromRight   = fromRight;
            _one         = new Digits(digitN);
            _multiplier1 = new Digits(digitN);
            _multiplier2 = new Digits(digitN);
            // this.mod.Set(this.mod, _digitN);
            _leftRecip = new Reciprocal();
            Digits.DivPrecondition(mod, digitN, _leftRecip);
            Digit mod0inv = 0;

            if ((mod[0] & 1) != 0)
            {
                mod0inv = Digit.TwoAdicInverse(mod[0]);
            }
            _rightRecip = mod0inv;
            int    digitN2 = (digitN + 1) / 2;
            Digits temp    = new Digits(digitN + digitN2);

            if (!fromRight)
            {
                _algorithm = new MulAlgorithm(_MulFromLeft);
                int dividendN = digitN + digitN2;
                _scaleBitN = 0;
                for (int i = 0; i != dividendN; i++)
                {
                    temp[i] = Digit.MaxValue;
                }
                temp[dividendN - 1] = Digit.MaxValue >> _leftRecip._shiftBitN;
                Digits q = new Digits(digitN2 + 1);
                Digits r = new Digits(digitN);
                Digits.Div(temp, dividendN, mod, digitN, _leftRecip, q, r);
                Debug.Assert(q[digitN2] == 1, "internal error");
                Digits.Add(r, 1U, r, digitN);
                Digits.Sub(mod, r, r, digitN);
            }
            else
            {
                _algorithm = new MulAlgorithm(_MulFromRight);
                _scaleBitN = Digit.BitN * digitN;
                if (mod0inv == 0)
                {
                    throw new ArgumentException();
                }
                _multiplier2[0] = mod0inv;
                temp[digitN]    = Digits.Mul(mod, mod0inv, temp, digitN);
                Debug.Assert(temp[0] == 1, "internal error");
                for (int i = 1; i != digitN2; i++)
                {
                    Digit mul = unchecked (0 - mod0inv * temp[i]);
                    _multiplier2[i] = mul;
                    temp[i + digitN]
                        = Digits.Accumulate(mod, mul, temp + i, digitN);
                    Debug.Assert(temp[i] == 0, "internal error");
                }
                _multiplier1._Set(temp + digitN2, digitN);
            }
            _ToModular(new Digits(new Digit[] { 1 }), 1, _one);
        }
Ejemplo n.º 5
0
        internal static void Div(
            Digits num
            , int numN
            , Digits denom
            , int denomN
            , Reciprocal recip
            , Digits q
            , Digits r
            )
        {
            if (denomN == 0)
            {
                throw new DivideByZeroException();
            }
            if (num == null || denom == null || r == null)
            {
                throw new ArgumentNullException();
            }
            Debug.Assert(!r._Overlaps(num) && !r._Overlaps(denom)
                         , "overlapping arguments");
            if (q != null)
            {
                Debug.Assert(
                    !q._Overlaps(num) && !q._Overlaps(denom) && !r._Overlaps(q)
                    , "overlapping arguments"
                    );
            }
            Digit dlead = denom[denomN - 1];

            if (dlead == 0)
            {
                throw new ArgumentException();
            }
            if (numN < denomN)
            {
                Debug.Assert(false, "untested code");
                Set(num, numN, r, denomN);
                return;
            }
            if (denomN == 1)
            {
                Div(num, dlead, recip, q, numN, r); return;
            }
            if (recip == null)
            {
                recip = new Reciprocal();
                DivPrecondition(denom, denomN, recip);
            }
            r[denomN - 1] = 0;
            r._Set(num + (numN - denomN + 1), denomN - 1);
            for (int iq = numN - denomN + 1; iq-- != 0;)
            {
                Digit rTop = r[denomN - 1];
                for (int i = denomN - 1; i != 0; i--)
                {
                    r[i] = r[i - 1];
                }
                r[0] = num[iq];
                Digit qest;
                if (rTop == 0 && Compare(r, denom, denomN) < 0)
                {
                    qest = 0;
                }
                else
                {
                    qest
                        = recip.EstQuotient(rTop, r[denomN - 1], r[denomN - 2]);
                    if (qest < Digit.MaxValue)
                    {
                        qest += 1;
                    }
                    Digit borrow = Decumulate(denom, qest, r, denomN);
                    if (borrow > rTop)
                    {
                        qest   -= 1;
                        borrow -= Add(r, denom, r, denomN);
                    }
                    Debug.Assert(borrow == rTop, "internal error");
                }
                if (q != null)
                {
                    q[iq] = qest;
                }
            }
        }