Ejemplo n.º 1
0
        void _BucketMul(UInt32 ibucket, Digits mult, Temps2000 temps)
        {
            Digits bloc = temps._bucket[ibucket];

            if (temps._bucketBusy[ibucket])
            {
                _Mul(bloc, mult, bloc);
            }
            else
            {
                temps._bucketBusy[ibucket] = true;
                bloc._Set(mult, _digitN);
            }
        }
Ejemplo n.º 2
0
 void _Shift(Digits a, int n, Digits b)
 {
     if (a != b)
     {
         b._Set(a, _digitN);
     }
     Modular.ValidateData(a, _mod, _digitN);
     if (n < 0 && (_mod[0] & 1) == 0)
     {
         throw new ArgumentException();
     }
     while (n > 0)
     {
         int   shiftNow = n > Digit.BitN ? Digit.BitN : n;
         Digit carryOut = Digits.ShiftLost(b, shiftNow, b, _digitN)
         , qest         = _leftRecip
                          .EstQuotient(carryOut
                                       , b[_digitN - 1]
                                       , _digitN >= 2 ? b[_digitN - 2] : 0);
         carryOut -= Digits.Decumulate(_mod, qest, b, _digitN);
         if (carryOut != 0 || Digits.Compare(b, _mod, _digitN) >= 0)
         {
             carryOut -= Digits.Sub(b, _mod, b, _digitN);
         }
         Debug.Assert(carryOut == 0, "internal error");
         n -= shiftNow;
     }
     while (n < 0)
     {
         int   shiftNow = -n > Digit.BitN ? Digit.BitN : -n;
         Digit mul      = unchecked (0 - _rightRecip * b[0])
                          & Digit.MaxValue >> Digit.BitN - shiftNow
         , carry       = Digits.Accumulate(_mod, mul, b, _digitN)
         , lowBitNLost = Digits.ShiftLost(b, -shiftNow, b, _digitN);
         b[_digitN - 1] |= carry << Digit.BitN - shiftNow;
         Debug.Assert(lowBitNLost == 0, "internal error");
         n += shiftNow;
     }
 }
Ejemplo n.º 3
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.º 4
0
        _Exp(Digits @base, Digits exp, int expDigitN, Digits answer)
        {
            int expBitNUsed = Digits.SigBitN(exp, expDigitN);

            ushort[] widthCutoffs = new ushort[] { 6, 24, 80, 240, 672 };
            Digits   basepower    = answer;
            int      bucketWidth  = 1;

            while (
                bucketWidth < 5 && widthCutoffs[bucketWidth - 1] < expBitNUsed
                )
            {
                bucketWidth++;
            }
            Modular.ValidateData(@base, _mod, _digitN);
            UInt32    bucketMask = (1U << bucketWidth) - 1;
            UInt32    maxBucket  = bucketMask;
            Digits    bucketData = new Digits((int)(_digitN * maxBucket));
            Temps2000 temps      = new Temps2000();

            temps._modulus   = this;
            temps._bucket[0] = null;
            Modular.Add(_one, _one, bucketData, _mod, _digitN);
            bool base2 = Digits.Compare(@base, bucketData, _digitN) == 0;

            if (base2 && expBitNUsed != 0)
            {
                int shiftMax
                    = Digit.BitN * _digitN > 1024 ? 1024 : Digit.BitN * _digitN;
                int    highExponBitN     = 0;
                bool   bighBitNProcessed = false;
                Digits temp = bucketData;
                for (int i = expBitNUsed; i-- != 0;)
                {
                    Digit expBit = Digits.GetBit(exp, i);
                    if (bighBitNProcessed)
                    {
                        _Mul(temp, temp, temp);
                        if (expBit != 0)
                        {
                            Modular.Add(temp, temp, temp, _mod, _digitN);
                        }
                    }
                    else
                    {
                        highExponBitN = (int)(2 * highExponBitN + expBit);
                        if (i == 0 || 2 * highExponBitN >= shiftMax)
                        {
                            bighBitNProcessed = true;
                            _Shift(_one, highExponBitN, temp);
                        }
                    }
                }
                temps._bucket[1] = temp;
                Debug.Assert(bighBitNProcessed, "internal error");
            }
            else
            {
                UInt32 ibucket;
                for (ibucket = 1; ibucket <= maxBucket; ibucket++)
                {
                    Digits bloc = bucketData
                                  + (int)(_digitN
                                          * (ibucket
                                             - 1
                                             + ((ibucket & 1) == 0 ? maxBucket : 0))
                                          / 2);
                    temps._bucket[ibucket]     = bloc;
                    temps._bucketBusy[ibucket] = false;
                    bloc._Set(_one, _digitN);
                }
                basepower._Set(@base, _digitN);
                Digit carried   = 0;
                int   ndoubling = 0;
                for (int i = 0; i != expBitNUsed; i++)
                {
                    Digit bitNow = Digits.GetBit(exp, i);
                    Debug.Assert(carried >> bucketWidth + 2 == 0
                                 , "internal error");
                    if (bitNow != 0)
                    {
                        while (ndoubling >= bucketWidth + 1)
                        {
                            if ((carried & 1) != 0)
                            {
                                ibucket  = carried & bucketMask;
                                carried -= ibucket;
                                temps._modulus
                                ._BucketMul(ibucket, basepower, temps);
                            }
                            temps._modulus._BasePowerSquaring(basepower);
                            carried /= 2;
                            ndoubling--;
                        }
                        carried |= 1U << ndoubling;
                    }
                    ndoubling++;
                }
                while (carried != 0)
                {
                    bool squareNow = false;
                    if (carried <= maxBucket)
                    {
                        ibucket = carried;
                    }
                    else if ((carried & 1) == 0)
                    {
                        squareNow = true;
                    }
                    else if (carried <= 3 * maxBucket)
                    {
                        ibucket = maxBucket;
                    }
                    else
                    {
                        Debug.Assert(false, "untested code");
                        ibucket = carried & bucketMask;
                    }
                    if (squareNow)
                    {
                        carried /= 2;
                        temps._modulus._BasePowerSquaring(basepower);
                    }
                    else
                    {
                        carried -= ibucket;
                        temps._modulus._BucketMul(ibucket, basepower, temps);
                    }
                }
                for (ibucket = maxBucket; ibucket >= 2; ibucket--)
                {
                    if (temps._bucketBusy[ibucket])
                    {
                        bool   found = false;
                        UInt32 jbucket, jbucketMax, kbucket;
                        Digits bloci;
                        if ((ibucket & 1) == 0)
                        {
                            jbucketMax = ibucket / 2;
                        }
                        else
                        {
                            jbucketMax = 1;
                        }
                        for (
                            jbucket = ibucket >> 1;
                            jbucket != ibucket && !found;
                            jbucket++
                            )
                        {
                            if (temps._bucketBusy[jbucket])
                            {
                                jbucketMax = jbucket;
                                found      = temps._bucketBusy[ibucket - jbucket];
                            }
                        }
                        jbucket = jbucketMax;
                        kbucket = ibucket - jbucket;
                        bloci   = temps._bucket[ibucket];
                        temps._modulus._BucketMul(jbucket, bloci, temps);
                        temps._modulus._BucketMul(kbucket, bloci, temps);
                    }
                }
            }
            answer._Set(temps._bucket[1], _digitN);
        }
Ejemplo n.º 5
0
 internal static void Set(Digits a, int aN, Digits b, int bN)
 {
     b._Set(a, aN);
     (b + aN)._SetAll(0, bN - aN);
 }
Ejemplo n.º 6
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);
            }
        }
Ejemplo n.º 7
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;
                }
            }
        }
Ejemplo n.º 8
0
        ShiftLost(Digits a, int bitScale, Digits b, int n)
        {
            if (n == 0)
            {
                Debug.Assert(false, "untested code"); return(0);
            }
            if (bitScale == 0)
            {
                Debug.Assert(false, "untested code");
                b._Set(a, n);
                return(0);
            }
            Digit bitNLost = 0;

            if (bitScale > 0)
            {
                if (bitScale > Digit.BitN)
                {
                    throw new ArgumentException();
                }
                if (bitScale == Digit.BitN)
                {
                    bitNLost = a[n - 1];
                    for (int i = n - 1; i != 0; i--)
                    {
                        b[i] = a[i - 1];
                    }
                    b[0] = 0;
                }
                else
                {
                    for (int i = 0; i != n; i++)
                    {
                        Digit bNew = a[i] << bitScale | bitNLost;
                        bitNLost = a[i] >> Digit.BitN - bitScale;
                        b[i]     = bNew;
                    }
                }
            }
            else
            {
                if (bitScale < -Digit.BitN)
                {
                    throw new ArgumentException();
                }
                if (bitScale == -Digit.BitN)
                {
                    bitNLost = a[0];
                    for (int i = 1; i != n; i++)
                    {
                        b[i - 1] = a[i];
                    }
                    b[n - 1] = 0;
                }
                else
                {
                    for (int i = n; i-- != 0;)
                    {
                        Digit bNew = a[i] >> -bitScale | bitNLost;
                        bitNLost = a[i] << Digit.BitN + bitScale;
                        b[i]     = bNew;
                    }
                    bitNLost >>= Digit.BitN + bitScale;
                }
            }
            return(bitNLost);
        }