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