Пример #1
0
        private static void Initialize()
        {
            _previousModulo = ModuloInteger.Modulo;
            _sumE           = new ModuloInteger[30];
            _sumIe          = new ModuloInteger[30];
            var es  = new ModuloInteger[30];
            var ies = new ModuloInteger[30];
            var bit = BitScanForward(_previousModulo - 1);
            var e   = ModuloInteger.Power(Mathematics.PrimitiveRoot(_previousModulo), (_previousModulo - 1) >> bit);
            var ie  = e.Inverse();

            for (var i = bit; i >= 2; i--)
            {
                es[i - 2]  = e;
                ies[i - 2] = ie;
                e         *= e;
                ie        *= ie;
            }

            ModuloInteger now  = 1;
            ModuloInteger inow = 1;

            for (var i = 0; i <= bit - 2; i++)
            {
                _sumE[i]  = es[i] * now;
                _sumIe[i] = ies[i] * inow;
                now      *= ies[i];
                inow     *= es[i];
            }
        }
Пример #2
0
        public static ModuloInteger[] Execute(IEnumerable <ModuloInteger> source1, IEnumerable <ModuloInteger> source2)
        {
            if (source1 is null)
            {
                throw new ArgumentNullException(nameof(source1));
            }
            if (source2 is null)
            {
                throw new ArgumentNullException(nameof(source2));
            }

            var(a, b) = (source1.ToArray(), source2.ToArray());
            if (a.Length == 0 || b.Length == 0)
            {
                return(Array.Empty <ModuloInteger>());
            }
            if (Math.Min(a.Length, b.Length) <= 60)
            {
                return(Naive(a, b));
            }

            var length = a.Length + b.Length - 1;
            var z      = 1 << CeilLog2(length);

            if (ModuloInteger.Modulo != _previousModulo)
            {
                Initialize();
            }
            Array.Resize(ref a, z);
            Butterfly(a);
            Array.Resize(ref b, z);
            Butterfly(b);
            var result = new ModuloInteger[z];

            for (var i = 0; i < z; i++)
            {
                result[i] = a[i] * b[i];
            }

            ButterflyInverse(result);
            Array.Resize(ref result, length);
            var iz = ModuloInteger.Inverse(z);

            for (var i = 0; i < result.Length; i++)
            {
                result[i] *= iz;
            }

            return(result);
        }
Пример #3
0
        private static ModuloInteger[] Naive(ReadOnlySpan <ModuloInteger> source1, ReadOnlySpan <ModuloInteger> source2)
        {
            var length = source1.Length + source2.Length - 1;
            var result = new ModuloInteger[length];

            for (var i = 0; i < source1.Length; i++)
            {
                for (var j = 0; j < source2.Length; j++)
                {
                    result[i + j] += source1[i] * source2[j];
                }
            }

            return(result);
        }
Пример #4
0
        private static void ButterflyInverse(Span <ModuloInteger> items)
        {
            var h = CeilLog2(items.Length);

            for (var ph = h; ph >= 1; ph--)
            {
                var           w    = 1 << (ph - 1);
                var           p    = 1 << (h - ph);
                ModuloInteger inow = 1;
                for (var s = 0; s < w; s++)
                {
                    var offset = s << (h - ph + 1);
                    for (var i = 0; i < p; i++)
                    {
                        var l = items[i + offset];
                        var r = items[i + offset + p];
                        items[i + offset]     = l + r;
                        items[i + offset + p] = (l - r) * inow;
                    }

                    inow *= _sumIe[BitScanForward(~s)];
                }
            }
        }
Пример #5
0
        private static void Butterfly(Span <ModuloInteger> items)
        {
            var h = CeilLog2(items.Length);

            for (var ph = 1; ph <= h; ph++)
            {
                var           w   = 1 << (ph - 1);
                var           p   = 1 << (h - ph);
                ModuloInteger now = 1;
                for (var s = 0; s < w; s++)
                {
                    var offset = s << (h - ph + 1);
                    for (var i = 0; i < p; i++)
                    {
                        var l = items[i + offset];
                        var r = items[i + offset + p] * now;
                        items[i + offset]     = l + r;
                        items[i + offset + p] = l - r;
                    }

                    now *= _sumE[BitScanForward(~s)];
                }
            }
        }