Esempio n. 1
0
        internal static int SigBitN(Digits a, int aN)
        {
            int sigDigitN = SigDigitN(a, aN);

            if (sigDigitN == 0)
            {
                Debug.Assert(false, "untested code");
                return(0);
            }
            return((int)((sigDigitN - 1) * Digit.BitN
                         + Digit.SigBitN(a[sigDigitN - 1])));
        }
Esempio 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;
        }
Esempio n. 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);
            }
        }