Exemplo n.º 1
0
        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 CeilPow2(int input, int expected)
 {
     InternalBit.CeilPow2(input).Should().Be(expected);
 }