示例#1
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);
        }