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); }