Пример #1
0
        Mul(Digits a, int aN, Digits b, int bN, Digits c)
        {
            Debug.Assert(!c._Overlaps(a) && !c._Overlaps(b)
                         , "overlapping arguments");
            Digits p1, p2;
            int    i, n1, n2;

            if (aN > bN)
            {
                p1 = a;
                p2 = b;
                n1 = aN;
                n2 = bN;
            }
            else
            {
                p2 = a;
                p1 = b;
                n2 = aN;
                n1 = bN;
            }
            if (n2 == 0)
            {
                Debug.Assert(false, "untested code");
                c._SetAll(0, n1);
                return;
            }
            c[n1] = Mul(p1, p2[0], c, n1);
            for (i = 1; i != n2; i++)
            {
                c[i + n1] = Accumulate(p1, p2[i], c + i, n1);
            }
        }
Пример #2
0
        static void Random(Digits mod, Digits arr, int n, Random generator)
        {
            Debug.Assert(!arr._Overlaps(mod), "overlapping arguments");
            int sigDigitN = n;

            while (sigDigitN > 0 && mod[sigDigitN - 1] == 0)
            {
                Debug.Assert(false, "untested code");
                arr[sigDigitN - 1] = 0;
                sigDigitN--;
            }
            if (sigDigitN == 0)
            {
                throw new ArgumentException();
            }
            Digit nlead = mod[sigDigitN - 1];
            int   ntry  = 0;

            do
            {
                ntry++;
                Debug.Assert(ntry <= 100, "too many iterations");
                Digits.Random(arr, sigDigitN - 1, generator);
                arr[sigDigitN - 1] = Digit.Random(0, nlead, generator);
            } while (Digits.Compare(arr, mod, sigDigitN) >= 0);
        }
Пример #3
0
        internal static void ExtendedGcd(
            Digits a
            , int aN
            , Digits b
            , int bN
            , Digits ainvmodb
            , Digits binvmoda
            , Digits gcd
            , out int lgcd
            )
        {
            Debug.Assert(!gcd._Overlaps(a) &&
                         !gcd._Overlaps(b) &&
                         !ainvmodb._Overlaps(a) &&
                         !ainvmodb._Overlaps(b) &&
                         !ainvmodb._Overlaps(gcd)
                         , "overlapping arguments");
            int aSigDigitN = SigDigitN(a, aN), bSigDigitN = SigDigitN(b, bN);

            if (aSigDigitN == 0 || bSigDigitN == 0)
            {
                throw new ArgumentException();
            }
            int[] abN = new int[2] {
                aSigDigitN, bSigDigitN
            };
            if (a == null || b == null || gcd == null || ainvmodb == null)
            {
                throw new ArgumentNullException();
            }
            int    maxDigitN = aN > bN ? aN : bN;
            Digits ab0Padded = new Digits(maxDigitN + 2)
            , ab1Padded      = new Digits(maxDigitN + 2)
            , tempProd       = new Digits(2 * maxDigitN)
            , tempQ          = new Digits(maxDigitN + 1);

            Digits[] ab = new Digits[] { ab0Padded + 1, ab1Padded + 1 };
            ab[0]._Set(a, aSigDigitN);
            ab[1]._Set(b, bSigDigitN);
            Digits[]
            tempsMul
                           = new Digits[] { new Digits(maxDigitN), new Digits(maxDigitN) };
            tempsMul[0][0] = 1;
            int mulN = 1, iterations = 0;

            while (abN[0] != 0 && abN[1] != 0)
            {
                int    abN0 = abN[0], abN1 = abN[1];
                Digits pab0top = ab[0] + (abN0 - 1)
                , pab1top = ab[1] + (abN1 - 1);
                Digit topword0 = pab0top[0], topword1 = pab1top[0];
                int   topsigbitN0 = Digit.SigBitN(topword0)
                , topsigbitN1     = Digit.SigBitN(topword1)
                , sigbitN0        = Digit.BitN * (abN0 - 1) + topsigbitN0
                , sigbitN1        = Digit.BitN * (abN1 - 1) + topsigbitN1
                , maxSigBitN      = sigbitN0 > sigbitN1 ? sigbitN0 : sigbitN1
                , maxlab          = abN0 > abN1 ? abN0 : abN1
                , ibig            = Compare(ab[1], abN1, ab[0], abN0) > 0 ? 1 : 0
                , ismall          = 1 - ibig;
                Digit[] mat22     = new Digit[4];
                iterations++;
                Debug.Assert(iterations <= Digit.BitN * (aN + bN + 1)
                             , "too many iterations");
                if (maxlab == 1)
                {
                    Digit ab0, ab1, m00, m01, m10, m11;
                    if (topword0 > Digit.MaxValue - topword1)
                    {
                        if (ibig == 0)
                        {
                            topword0 -= topword1;
                        }
                        else
                        {
                            topword1 -= topword0;
                        }
                        Digit carry = Add(tempsMul[0]
                                          , tempsMul[1]
                                          , tempsMul[ibig]
                                          , mulN);
                        if (carry != 0)
                        {
                            Debug.Assert(false, "untested code");
                            Debug.Assert(mulN < bN, "internal error");
                            tempsMul[ibig][mulN] = carry;
                            mulN++;
                        }
                    }
                    ab0 = topword0;
                    ab1 = topword1;
                    m00 = 1;
                    m01 = 0;
                    m10 = 0;
                    m11 = 1;
                    while (ab1 != 0)
                    {
                        if (ab0 >= ab1)
                        {
                            if (ab0 >> 2 >= ab1)
                            {
                                Digit q = ab0 / ab1;
                                ab0 -= q * ab1;
                                m00 += q * m10;
                                m01 += q * m11;
                            }
                            else
                            {
                                do
                                {
                                    ab0 -= ab1;
                                    m00 += m10;
                                    m01 += m11;
                                } while (ab0 >= ab1);
                            }
                        }
                        Debug.Assert(ab1 > ab0, "internal error");
                        if (ab0 == 0)
                        {
                            break;
                        }
                        if (ab1 >> 2 >= ab0)
                        {
                            Digit q = ab1 / ab0;
                            ab1 -= q * ab0;
                            m10 += q * m00;
                            m11 += q * m01;
                        }
                        else
                        {
                            do
                            {
                                ab1 -= ab0;
                                m10 += m00;
                                m11 += m01;
                            } while (ab1 >= ab0);
                        }
                        Debug.Assert(ab0 > ab1, "internal error");
                    }
                    ab[0][0] = ab0;
                    ab[1][0] = ab1;
                    abN[0]   = ab0 != 0 ? 1 : 0;
                    abN[1]   = ab1 != 0 ? 1 : 0;
                    mat22[0] = m00;
                    mat22[1] = m01;
                    mat22[2] = m10;
                    mat22[3] = m11;
                    Digits carrys = new Digits(2);
                    Mul22U(mat22, tempsMul[0], tempsMul[1], mulN, carrys);
                    if (carrys[0] == 0 && carrys[1] == 0)
                    {
                    }
                    else
                    {
                        Debug.Assert(mulN < bN, "internal error");
                        tempsMul[0][mulN] = carrys[0];
                        tempsMul[1][mulN] = carrys[1];
                        mulN++;
                    }
                }
                else if (
                    sigbitN0 > sigbitN1 + Digit.BitN / 2 ||
                    sigbitN1 > sigbitN0 + Digit.BitN / 2
                    )
                {
                    int smallMulN = SigDigitN(tempsMul[ismall], mulN);
                    Div(ab[ibig]
                        , abN[ibig]
                        , ab[ismall]
                        , abN[ismall]
                        , null
                        , tempQ
                        , tempProd);
                    int lQ = SigDigitN(tempQ, abN[ibig] - abN[ismall] + 1);
                    abN[ibig] = SigDigitN(tempProd, abN[ismall]);
                    ab[ibig]._Set(tempProd, abN[ibig]);
                    Mul(tempQ, lQ, tempsMul[ismall], smallMulN, tempProd);
                    AddFull(tempProd
                            , SigDigitN(tempProd, lQ + smallMulN)
                            , tempsMul[ibig]
                            , mulN
                            , tempsMul[ibig]
                            , out mulN);
                }
                else
                {
                    int norm = (int)(Digit.BitN * maxlab - maxSigBitN);
                    pab0top[1] = pab1top[1] = 0;
                    Debug.Assert(maxlab >= 2, "internal error");
                    UInt64 lead0
                        = (UInt64)
                          (ab[0][maxlab - 1] << norm
                           | ab[0][maxlab - 2] >> 1 >> Digit.BitN - 1 - norm)
                          << Digit.BitN
                          | (ab[0][maxlab - 2] << norm
                             | ab[0][maxlab - 3] >> 1 >> Digit.BitN - 1 - norm)
                        , lead1
                        = (UInt64)
                          (ab[1][maxlab - 1] << norm
                           | ab[1][maxlab - 2] >> 1 >> Digit.BitN - 1 - norm)
                          << Digit.BitN
                          | (ab[1][maxlab - 2] << norm
                             | ab[1][maxlab - 3] >> 1 >> Digit.BitN - 1 - norm);
                    LehmerMat22(lead0, lead1, mat22);
                    if ((mat22[1] | mat22[2]) == 0)
                    {
                        Debug.Assert(false, "untested code");
                        Debug.Assert(
                            mat22[0] == 1 && mat22[3] == 1, "internal error");
                        mat22[ibig + 1] = 1;
                    }
                    int   lab     = abN0 > abN1 ? abN0 : abN1;
                    int[] scarrys = new int[2];
                    Mul22S(mat22, ab[0], ab[1], lab, scarrys);
                    Debug.Assert(scarrys[0] == 0 && scarrys[1] == 0
                                 , "internal error");
                    int abN0Sig = lab, abN1Sig = lab;
                    while (abN0Sig != 0 && ab[0][abN0Sig - 1] == 0)
                    {
                        abN0Sig--;
                    }
                    while (abN1Sig != 0 && ab[1][abN1Sig - 1] == 0)
                    {
                        abN1Sig--;
                    }
                    abN[0] = abN0Sig;
                    abN[1] = abN1Sig;
                    Digits carrys = new Digits(2);
                    Mul22U(mat22, tempsMul[0], tempsMul[1], mulN, carrys);
                    if (carrys[0] == 0 && carrys[1] == 0)
                    {
                    }
                    else
                    {
                        Debug.Assert(mulN < bN, "internal error");
                        tempsMul[0][mulN] = carrys[0];
                        tempsMul[1][mulN] = carrys[1];
                        mulN++;
                    }
                }
            }
            Digit igcd = (Digit)(abN[0] == 0 ? 1U : 0U);

            lgcd = abN[igcd];
            gcd._Set(ab[igcd], lgcd);
            Debug.Assert(Compare(b, tempsMul[1 - igcd], bN) >= 0 &&
                         Compare(tempsMul[1 - igcd], tempsMul[igcd], bN) >= 0
                         , "internal error");
            if (igcd == 0)
            {
                ainvmodb._Set(tempsMul[0], bN);
            }
            else
            {
                Sub(tempsMul[0], tempsMul[1], ainvmodb, bN);
            }
            if (binvmoda != null)
            {
                Sub(tempsMul[1 - igcd], ainvmodb, tempsMul[1 - igcd], bN);
                Mul(a, aN, tempsMul[1 - igcd], bN, tempProd);
                Add(tempProd, aN + bN, gcd, lgcd, tempProd);
                Div(tempProd
                    , aN + bSigDigitN
                    , b
                    , bSigDigitN
                    , null
                    , tempQ
                    , tempsMul[1 - igcd]);
                Debug.Assert(SigDigitN(tempsMul[1 - igcd], bSigDigitN) == 0
                             , "internal error");
                binvmoda._Set(tempQ, aN);
            }
        }
Пример #4
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;
                }
            }
        }