示例#1
0
        private static StaticModInt <T>[] CalcurateSumE()
        {
            int g    = InternalMath.PrimitiveRoot((int)default(T).Mod);
            int cnt2 = InternalBit.BSF(default(T).Mod - 1);
            var e    = new StaticModInt <T>(g).Pow((default(T).Mod - 1) >> cnt2);
            var ie   = e.Inv();

            var sumE = new StaticModInt <T> [cnt2 - 2];

            // es[i]^(2^(2+i)) == 1
            Span <StaticModInt <T> > es  = stackalloc StaticModInt <T> [cnt2 - 1];
            Span <StaticModInt <T> > ies = stackalloc StaticModInt <T> [cnt2 - 1];

            for (int i = es.Length - 1; i >= 0; i--)
            {
                // e^(2^(2+i)) == 1
                es[i]  = e;
                ies[i] = ie;
                e     *= e;
                ie    *= ie;
            }

            var now = StaticModInt <T> .Raw(1);

            for (int i = 0; i < sumE.Length; i++)
            {
                sumE[i] = es[i] * now;
                now    *= ies[i];
            }

            return(sumE);
        }
示例#2
0
        public static void Calculate(Span <StaticModInt <T> > a)
        {
            var n = a.Length;
            var h = InternalMath.CeilPow2(n);

            for (int ph = 1; ph <= h; ph++)
            {
                // ブロックサイズの半分
                int w = 1 << (ph - 1);

                // ブロック数
                int p = 1 << (h - ph);

                var now = StaticModInt <T> .Raw(1);

                // 各ブロックの s 段目
                for (int s = 0; s < w; s++)
                {
                    int offset = s << (h - ph + 1);

                    for (int i = 0; i < p; i++)
                    {
                        var l = a[i + offset];
                        var r = a[i + offset + p] * now;
                        a[i + offset]     = l + r;
                        a[i + offset + p] = l - r;
                    }
                    now *= sumE[InternalBit.BSF(~(uint)s)];
                }
            }
        }
示例#3
0
        public static void CalculateInv(Span <StaticModInt <T> > a)
        {
            var n = a.Length;
            var h = InternalMath.CeilPow2(n);

            for (int ph = h; ph >= 1; ph--)
            {
                // ブロックサイズの半分
                int w = 1 << (ph - 1);

                // ブロック数
                int p = 1 << (h - ph);

                var iNow = StaticModInt <T> .Raw(1);

                // 各ブロックの s 段目
                for (int s = 0; s < w; s++)
                {
                    int offset = s << (h - ph + 1);

                    for (int i = 0; i < p; i++)
                    {
                        var l = a[i + offset];
                        var r = a[i + offset + p];
                        a[i + offset]     = l + r;
                        a[i + offset + p] = StaticModInt <T> .Raw(
                            unchecked ((int)((ulong)(default(T).Mod + l.Value - r.Value) * (ulong)iNow.Value % default(T).Mod)));
                    }
                    iNow *= sumIE[InternalBit.BSF(~(uint)s)];
                }
            }
        }
        private static StaticModInt <T>[] CalcurateSumIE()
        {
            int g    = InternalMath.PrimitiveRoot <T>();
            int cnt2 = InternalBit.BSF(default(T).Mod - 1);
            var e    = new StaticModInt <T>(g).Pow((default(T).Mod - 1) >> cnt2);
            var ie   = e.Inv();

            var sumIE = new StaticModInt <T> [30];

            // es[i]^(2^(2+i)) == 1
            Span <StaticModInt <T> > es =
#if !NETCOREAPP3_0_OR_GREATER
                new
#else
                stackalloc
#endif
                StaticModInt <T> [cnt2 - 1];
            Span <StaticModInt <T> > ies =
#if !NETCOREAPP3_0_OR_GREATER
                new
#else
                stackalloc
#endif
                StaticModInt <T> [cnt2 - 1];

            for (int i = es.Length - 1; i >= 0; i--)
            {
                // e^(2^(2+i)) == 1
                es[i]  = e;
                ies[i] = ie;
                e     *= e;
                ie    *= ie;
            }

            var now = StaticModInt <T> .Raw(1);

            for (int i = 0; i <= cnt2 - 2; i++)
            {
                sumIE[i] = ies[i] * now;
                now     *= es[i];
            }

            return(sumIE);
        }
        public static void Calculate(Span <StaticModInt <T> > a)
        {
            CheckPow2(a.Length);
            var n = a.Length;
            var h = InternalBit.CeilPow2(n);

            var regLength = Vector <uint> .Count;

#if !NETCOREAPP3_0_OR_GREATER
            var copyTmp = new uint[regLength];
#endif

            // 全要素がmodのVector<uint>を作成(比較および加減算用)
            var modV = new Vector <uint>(default(T).Mod);

            for (int ph = 1; ph <= h; ph++)
            {
                // ブロックサイズの半分
                int w = 1 << (ph - 1);

                // ブロック数
                int p = 1 << (h - ph);

                var now = StaticModInt <T> .Raw(1);


                // 各ブロックの s 段目
                for (int s = 0; s < w; s++)
                {
                    int offset = s << (h - ph + 1);
                    var ls     = a.Slice(offset, p);
                    var rs     = a.Slice(offset + p, p);

                    if (p < regLength)
                    {
                        for (int i = 0; i < p; i++)
                        {
                            var l = ls[i];
                            var r = rs[i] * now;
                            ls[i] = l + r;
                            rs[i] = l - r;
                        }
                    }
                    else
                    {
                        foreach (ref var r in rs)
                        {
                            r *= now;
                        }

                        // uintとして再解釈
                        var lu = MemoryMarshal.Cast <StaticModInt <T>, uint>(ls);
                        var ru = MemoryMarshal.Cast <StaticModInt <T>, uint>(rs);

                        for (int i = 0; i < lu.Length; i += regLength)
                        {
                            var luSliced = lu.Slice(i);
                            var ruSliced = ru.Slice(i);
                            var u        = new Vector <uint>(luSliced);
                            var v        = new Vector <uint>(ruSliced);
                            var add      = u + v;
                            var sub      = u - v;

                            var ge = Vector.GreaterThanOrEqual(add, modV);
                            add = Vector.ConditionalSelect(ge, add - modV, add);

                            ge  = Vector.GreaterThanOrEqual(sub, modV);
                            sub = Vector.ConditionalSelect(ge, sub + modV, sub);

#if !NETCOREAPP3_0_OR_GREATER
                            add.CopyTo(copyTmp);
                            copyTmp.CopyTo(luSliced);
                            sub.CopyTo(copyTmp);
                            copyTmp.CopyTo(ruSliced);
#else
                            add.CopyTo(luSliced);
                            sub.CopyTo(ruSliced);
#endif
                        }
                    }

                    now *= sumE[InternalBit.BSF(~(uint)s)];
                }
            }
        }
 public void BSF(uint input, int expected)
 {
     InternalBit.BSF(input).Should().Be(expected);
 }
 public void CeilPow2(int input, int expected)
 {
     InternalBit.CeilPow2(input).Should().Be(expected);
 }
 public void ExtractLowestSetBit(int input, uint expected)
 {
     InternalBit.ExtractLowestSetBit(input).Should().Be(expected);
     (input & -input).Should().Be((int)expected);
 }