Discrete Weighted Transform FFT Multiplication
FFT时间复杂度时O(nlgn),当输入向量长度减半时时间复杂度为O(n/2lg(n/2)) < O((nlgn)/2),所需时间几乎减半。
调用FFT时,对于整数型向量,可以把向量的前半部分放入实部,后半部分放入虚部,比全部放入实部更快。
也就是对于长度为N的向量,0,1...N/2 - 1放入实部,N/2,N/2 + 1...N - 1放入虚部。在IDFT之后再调回来,注意虚部这时全部为负数。
/// <summary>
/// return Lo(data) + iHi(data), Lo(data) = data[0...i...n/2 - 1], Hi(data) = data[n/2...n/2+i...n-1]
/// </summary>
private static Complex[] Fold(int[] data)
{
var result = new Complex[data.Length >> 1];
for(var i = 0; i < result.Length; ++i)
{
result[i] = new Complex(data[i], data[result.Length + i]);
}
return result;
}
/// <summary>
/// return Real(data)...Imag(data), Real(data) = data[0...i...n-1].Real, Imag(data) = -data[0...i...n-1].Imaginary
/// </summary>
private static int[] UnFold(Complex[] data)
{
var result = new int[data.Length << 1];
for (var i = 0; i < data.Length; ++i)
{
result[i] = (int)Math.Round(data[i].Real);
result[data.Length + i] = -(int)Math.Round(data[i].Imaginary);
}
return result;
}
当在DFT前对向量乘以一个系数,IDFT后再对结果乘以该系数的逆,就是离散加权傅里叶变换。加权向量a^N = -1 => a = e^-iπ/N。
/// <summary>
/// <paramref name="data"/>[i] *= <see cref="Math.E"/>^(-<see cref="Math.PI"/>*i/<paramref name="n"/>)
/// </summary>
private static void Weight(Complex[] data, int n)
{
for(var i = 0; i < data.Length; ++i)
{
var theta = -Math.PI * i / n;
data[i] *= new Complex(Math.Cos(theta), Math.Sin(theta));
}
}
/// <summary>
/// <paramref name="data"/>[i] *= <see cref="Math.E"/>^(<see cref="Math.PI"/>*i/<paramref name="n"/>)
/// </summary>
private static void UnWeight(Complex[] data, int n)
{
for (var i = 0; i < data.Length; ++i)
{
var theta = Math.PI * i / n;
data[i] *= new Complex(Math.Cos(theta), Math.Sin(theta));
}
}
CeilingPowerOf2参考《Hacker's Delight - Power-Of-2 Boundaries》。
Radix2Forward和Radix2Inverse参考《Cooley–Tukey FFT Algorithm - Iterative Edition》。
private static readonly int MASK = 0xFF;
/// <summary>
/// <see cr