示例#1
0
        internal static int SigBitN(Digit d)
        {
            d |= 1;
            int bitN = BitN;

            while (d < 1U << BitN - 5)
            {
                bitN -= 5; d <<= 5;
            }
            return(bitN - leadingZeroBitN[d >> BitN - 4]);
        }
示例#2
0
        internal static Digit Mul(Digits a, Digit mult, Digits b, int n)
        {
            Digit carry = 0;

            for (int i = 0; i != n; i++)
            {
                UInt64 dtemp = (UInt64)mult * a[i] + carry;
                b[i]  = Digit2.Lo(dtemp);
                carry = Digit2.Hi(dtemp);
            }
            return(carry);
        }
示例#3
0
        internal static uint Sub(Digits a, Digits b, Digits c, int n)
        {
            uint borrow = 0;

            for (int i = 0; i != n; i++)
            {
                Digit ai = a[i], bi = b[i], sum = unchecked (ai - bi - borrow);
                c[i]   = sum;
                borrow = (ai ^ (ai ^ bi | ai ^ sum)) >> Digit.BitN - 1;
            }
            return(borrow);
        }
示例#4
0
        Accumulate(Digits a, Digit mult, Digits b, int n)
        {
            Digit carry = 0;

            for (int i = 0; i != n; i++)
            {
                UInt64 dtemp = (UInt64)mult * a[i] + b[i] + carry;
                b[i]  = Digit2.Lo(dtemp);
                carry = Digit2.Hi(dtemp);
            }
            return(carry);
        }
示例#5
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])));
        }
示例#6
0
        internal static uint Add(Digits a, Digits b, Digits c, int n)
        {
            uint carry = 0;

            for (int i = 0; i != n; i++)
            {
                Digit ai = a[i], bi = b[i], sum = unchecked (carry + (ai + bi));
                c[i]  = sum;
                carry = ((ai | bi) ^ (ai ^ bi) & sum) >> Digit.BitN - 1;
            }
            return(carry);
        }
示例#7
0
 DigitsToBytes(Digits digits, byte[] bytes, int byteI, int bitN)
 {
     for (int i = 0; i != (bitN + (Digit.BitN - 1)) / Digit.BitN; i++)
     {
         Digit dvalue    = digits[i];
         int   byteNLeft = (bitN + 7) / 8 - 4 * i;
         for (int j = 0; j != (byteNLeft > 4 ? 4 : byteNLeft); j++)
         {
             bytes[byteI + byteNLeft - 1 - j] = (byte)(dvalue & 0xff);
             dvalue >>= 8;
         }
     }
 }
示例#8
0
        Div(UInt64 num, Digit denom, out Digit q, out Digit r)
        {
            Digit numHi = Hi(num), numLo = Lo(num);

            if (numHi >= denom)
            {
                throw new ArgumentException();
            }
            q = (Digit)(num / denom);
            r = unchecked (numLo - denom * q);
            Digit rr = unchecked ((Digit)(num - denom * q));

            Debug.Assert(rr == r, "internal error");
        }
示例#9
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;
        }
示例#10
0
        void _MulFromRight(Digits a, Digits b, Digits c)
        {
            Digit minv = _rightRecip
            , minva0 = unchecked (minv * a[0])
            , mul1 = b[0]
            , mul2 = unchecked (minva0 * mul1)
            , carry1 = Digit2.Hi((UInt64)mul1 * a[0])
            , carry2 = Digit2.Hi((UInt64)mul2 * _mod[0]);
            UInt64 prod1, prod2;

            Debug.Assert(unchecked (mul1 * a[0]) == unchecked (mul2 * _mod[0])
                         , "internal error");
            Digits temp1 = new Digits(_digitN), temp2 = new Digits(_digitN);

            for (int i = 1; i != _digitN; i++)
            {
                prod1        = (UInt64)mul1 * a[i] + carry1;
                prod2        = (UInt64)mul2 * _mod[i] + carry2;
                temp1[i - 1] = Digit2.Lo(prod1);
                temp2[i - 1] = Digit2.Lo(prod2);
                carry1       = Digit2.Hi(prod1);
                carry2       = Digit2.Hi(prod2);
            }
            temp1[_digitN - 1] = carry1;
            temp2[_digitN - 1] = carry2;
            for (int j = 1; j != _digitN; j++)
            {
                mul1  = b[j];
                mul2  = unchecked (minva0 * mul1 + minv * (temp1[0] - temp2[0]));
                prod1 = (UInt64)mul1 * a[0] + temp1[0];
                prod2 = (UInt64)mul2 * _mod[0] + temp2[0];
                Debug.Assert(Digit2.Lo(prod1) == Digit2.Lo(prod2)
                             , "internal error");
                carry1 = Digit2.Hi(prod1);
                carry2 = Digit2.Hi(prod2);
                for (int i = 1; i != _digitN; i++)
                {
                    prod1        = (UInt64)mul1 * a[i] + temp1[i] + carry1;
                    prod2        = (UInt64)mul2 * _mod[i] + temp2[i] + carry2;
                    temp1[i - 1] = Digit2.Lo(prod1);
                    temp2[i - 1] = Digit2.Lo(prod2);
                    carry1       = Digit2.Hi(prod1);
                    carry2       = Digit2.Hi(prod2);
                }
                temp1[_digitN - 1] = carry1;
                temp2[_digitN - 1] = carry2;
            }
            Modular.Sub(temp1, temp2, c, _mod, _digitN);
        }
示例#11
0
        Decumulate(Digits a, Digit mult, Digits b, int n)
        {
            Digit borrow = 0;

            for (int i = 0; i != n; i++)
            {
                UInt64 dtemp;
                unchecked {
                    dtemp = (UInt64)b[i] - borrow - (UInt64)mult * a[i];
                }
                b[i] = Digit2.Lo(dtemp);
                unchecked { borrow = 0 - Digit2.Hi(dtemp); }
            }
            return(borrow);
        }
示例#12
0
        internal Digit EstQuotient(Digit n2, Digit n1, Digit n0)
        {
            Digit nShiftHi
                = n2 << _shiftBitN | n1 >> 1 >> Digit.BitN - 1 - _shiftBitN
                , nShiftLo
                = n1 << _shiftBitN | n0 >> 1 >> Digit.BitN - 1 - _shiftBitN;
            UInt64 qprod = ((UInt64)nShiftHi << Digit.BitN | nShiftLo)
                           + (UInt64)nShiftHi * _multiplier;

            if ((nShiftLo & 1U << Digit.BitN - 1) != 0)
            {
                qprod += _multiplier >> 1;
            }
            return(Digit2.Hi(qprod));
        }
示例#13
0
        internal static void Neg(Digits a, Digits b, Digits mod, int n)
        {
            Digit allZero = 0;

            for (int i = 0; i != n; i++)
            {
                allZero |= a[i]; b[i] = a[i];
            }
            if (allZero != 0)
            {
                if (Digits.Sub(mod, b, b, n) != 0)
                {
                    throw new ArgumentException();
                }
            }
        }
示例#14
0
        AddSub(Digits a, Digits b, Digits c, Digits d, int n)
        {
            uint carry1 = 0, carry2 = 0;

            for (int i = 0; i != n; i++)
            {
                Digit ai = a[i]
                , bi     = b[i]
                , ci     = c[i]
                , sum1   = unchecked (ai + bi + carry1)
                , sum2   = unchecked (sum1 - ci - carry2);
                d[i]   = sum2;
                carry1 = (sum1 ^ (sum1 ^ ai | sum1 ^ bi)) >> Digit.BitN - 1;
                carry2 = (sum1 ^ (sum1 ^ ci | sum1 ^ sum2)) >> Digit.BitN - 1;
            }
            return((int)carry1 - (int)carry2);
        }
示例#15
0
        internal static uint Add(Digits a, Digit immediate, Digits b, int n)
        {
            uint carry = immediate;

            for (int i = 0; i != n; i++)
            {
                Digit bi = a[i] + carry;
                b[i] = bi;
                if (bi >= carry)
                {
                    if (a != b)
                    {
                        (b + i + 1)._Set(a + i + 1, n - i - 1);
                    }
                    return(0);
                }
                carry = 1;
            }
            return(carry);
        }
示例#16
0
        internal static Digit TwoAdicInverse(Digit d)
        {
            if ((d & 1) == 0)
            {
                throw new ArgumentException();
            }
            UInt32 dInverse = unchecked (3 * d ^ 2)
            , error         = unchecked (1 - d * dInverse);

            Debug.Assert((error & 31) == 0, "internal error");
            for (int bitN = 5; bitN < BitN / 2; bitN *= 2)
            {
                unchecked {
                    dInverse += dInverse * error;
                    error     = error * error;
                    Debug.Assert(error == 1 - d * dInverse, "internal error");
                }
            }
            return(unchecked (dInverse * error + dInverse));
        }
示例#17
0
        internal static int Sub(Digits a, Digit isub, Digits b, int n)
        {
            Digit borrow = isub;

            for (int i = 0; i != n; i++)
            {
                Digit ai = a[i];
                b[i] = ai - borrow;
                if (ai >= borrow)
                {
                    if (a != b)
                    {
                        (b + i + 1)._Set(a + i + 1, n - i - 1);
                    }
                    return(0);
                }
                borrow = 1;
            }
            return((int)borrow);
        }
示例#18
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;
     }
 }
示例#19
0
        Add(Digits a, Digits b, Digits c, Digits mod, int n)
        {
            Debug.Assert(n != 0, "internal error");
            Digit alead = a[n - 1], blead = b[n - 1], mlead = mod[n - 1];

            if (alead >= mlead)
            {
                ValidateData(a, mod, n);
            }
            if (blead >= mlead)
            {
                ValidateData(b, mod, n);
            }
            int test;

            if (blead > mlead - alead)
            {
                test = +1;
            }
            else if (mlead - alead - blead > 1)
            {
                test = -1;
            }
            else
            {
                test = Digits.CompareSum(a, b, mod, n);
            }
            if (test >= 0)
            {
                int carry = Digits.AddSub(a, b, mod, c, n);
                Debug.Assert(carry == 0, "internal error");
            }
            else
            {
                uint carry = Digits.Add(a, b, c, n);
                Debug.Assert(carry == 0, "internal error");
            }
        }
示例#20
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");
        }
示例#21
0
        internal static int CompareSum(Digits a, Digits b, Digits c, int n)
        {
            int sumPrev = 0;

            for (int i = n; i-- != 0;)
            {
                Digit aval = a[i]
                , bval     = b[i]
                , cval     = c[i]
                , sumNow   = unchecked (aval + bval);
                Debug.Assert(sumPrev == 0 || sumPrev == -1, "internal error");
                sumPrev += (sumNow < aval ? 1 : 0) - (sumNow < cval ? 1 : 0);
                unchecked { sumNow -= cval; }
                if (
                    sumPrev != unchecked ((int)(uint)sumNow) ||
                    unchecked (sumPrev + 3 & 2) == 0
                    )
                {
                    return((sumPrev + 2 & 2) - 1);
                }
            }
            return(sumPrev);
        }
示例#22
0
        internal static Digit Hi(UInt64 x)
        {
            Digit hi = unchecked ((UInt32)(x >> Digit.BitN));

            return(hi);
        }
示例#23
0
        LehmerMat22(UInt64 lead0orig, UInt64 lead1orig, Digit[] mat22)
        {
            Digit lead0h = Digit2.Hi(lead0orig)
            , lead0l = Digit2.Lo(lead0orig)
            , lead1h = Digit2.Hi(lead1orig)
            , lead1l = Digit2.Lo(lead1orig);
            bool  progress = true;
            Digit m00 = 1, m01 = 0, m10 = 0, m11 = 1;

            Debug.Assert(lead0h != 0 &&
                         lead1h != 0 &&
                         ((lead0h | lead1h) & 1U << Digit.BitN - 1) != 0
                         , "internal error");
            while (progress)
            {
                progress = false;
                if (lead0h - 1 > lead1h && lead0h != 0)
                {
                    if (lead0h >> 2 >= lead1h + 2)
                    {
                        Digit  q          = lead0h / (lead1h + 2);
                        UInt64 prod10By11 = (UInt64)q * (m10 + m11)
                        , prod1l          = (UInt64)q * lead1l;
                        Debug.Assert(q > 3, "internal error");
                        if (
                            Digit2.Hi(prod10By11) == 0 &&
                            Digit2.Lo(prod10By11)
                            <= Digit.MaxValue / 2 - m00 - m01
                            )
                        {
                            Digit prod10 = q * m10;
                            progress = true;
                            lead0h
                                -= (Digit)((long)(UInt32)q * lead1h
                                           + Digit2.Hi(prod1l)
                                           + (Digit2.Lo(prod1l) > lead0l ? 1L : 0L));
                            unchecked { lead0l -= Digit2.Lo(prod1l); }
                            m00 += prod10;
                            m01 += Digit2.Lo(prod10By11) - prod10;
                            Debug.Assert((m00 | m01) < 1U << Digit.BitN - 1
                                         , "internal error");
                        }
                    }
                    else
                    {
                        Digit overflowTest;
                        do
                        {
                            m00         += m10;
                            m01         += m11;
                            overflowTest = (m00 | m01) & 1U << Digit.BitN - 1;
                            lead0h      -= lead1h + (lead1l > lead0l ? 1U : 0U);
                            unchecked { lead0l -= lead1l; }
                        } while (overflowTest == 0 && lead0h >= lead1h + 2);
                        progress = true;
                        if (overflowTest != 0)
                        {
                            progress = false;
                            m00     -= m10;
                            m01     -= m11;
                        }
                    }
                }
                if (lead1h - 1 > lead0h && lead1h != 0)
                {
                    if (lead1h >> 2 >= lead0h + 2)
                    {
                        Digit  q           = lead1h / (lead0h + 2);
                        UInt64 prod00And01 = (UInt64)q * (m00 + m01)
                        , prod0l           = (UInt64)q * lead0l;
                        Debug.Assert(q > 3, "internal error");
                        if (
                            Digit2.Hi(prod00And01) == 0 &&
                            Digit2.Lo(prod00And01)
                            <= Digit.MaxValue / 2 - m10 - m11
                            )
                        {
                            Digit prod00 = q * m00;
                            progress = true;
                            lead1h  -= q * lead0h
                                       + Digit2.Hi(prod0l)
                                       + (Digit2.Lo(prod0l) > lead1l ? 1U : 0U);
                            unchecked { lead1l -= Digit2.Lo(prod0l); }
                            m10 += prod00;
                            m11 += Digit2.Lo(prod00And01) - prod00;
                            Debug.Assert((m10 | m11) < 1U << Digit.BitN - 1
                                         , "internal error");
                        }
                    }
                    else
                    {
                        Digit overflowTest;
                        do
                        {
                            m10         += m00;
                            m11         += m01;
                            overflowTest = (m10 | m11) & 1U << Digit.BitN - 1;
                            lead1h      -= lead0h + (lead0l > lead1l ? 1U : 0U);
                            unchecked { lead1l -= lead0l; }
                        } while (overflowTest == 0 && lead1h >= lead0h + 2);
                        progress = true;
                        if (overflowTest != 0)
                        {
                            progress = false;
                            m10     -= m00;
                            m11     -= m01;
                        }
                    }
                }
            }
            Debug.Assert(((m00 | m01 | m10 | m11) & 1U << Digit.BitN - 1) == 0
                         , "internal error");
            mat22[0] = m00;
            mat22[1] = m01;
            mat22[2] = m10;
            mat22[3] = m11;
        }
示例#24
0
 internal static int Compare(Digits a, Digit ivalue, int aN)
 {
     return(Compare(a, aN, new Digits(new Digit[] { ivalue }), 1));
 }
示例#25
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);
        }
示例#26
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);
        }
示例#27
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);
            }
        }
示例#28
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);
        }
示例#29
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;
                }
            }
        }