我最近学习了FFT算法。
我将其应用于遵循此伪代码的非常大自然数的快速乘法的问题,
Let A be array of length m, w be primitive m-th root of unity.
Goal: produce DFT F(A): evaluation of A at 1, w, w^2,...,w^{m-1}.
FFT(A, m, w)
{
if (m==1) return vector (a_0)
else {
A_even = (a_0, a_2, ..., a_{m-2})
A_odd = (a_1, a_3, ..., a_{m-1})
F_even = FFT(A_even, m/2, w^2) //w^2 is a primitive m/2-th root of unity
F_odd = FFT(A_odd, m/2, w^2)
F = new vector of length m
x = 1
for (j=0; j < m/2; ++j) {
F[j] = F_even[j] + x*F_odd[j]
F[j+m/2] = F_even[j] - x*F_odd[j]
x = x * w
}
return F
}
效果很好,但是我发现了更好的代码,它无需递归即可完成相同的工作,并且运行速度也更快。
我试图逐行弄清楚它是如何工作的,但是,我失败了。
如果您能详细解释一下我的前两个for循环(不是数学部分),我将不胜感激
下面是新代码
typedef complex<double> base;
void fft(vector<base> &a, bool invert)
{
int n = a.size();
for (int i = 1, j = 0; i < n; i++){
int bit = n >> 1;
for (; j >= bit; bit >>= 1) j -= bit;
j += bit;
if (i < j) swap(a[i], a[j]);
}
for (int len = 2; len <= n; len <<= 1){
double ang = 2 * M_PI / len * (invert ? -1 : 1);
base wlen(cos(ang), sin(ang));
for (int i = 0; i < n; i += len){
base w(1);
for (int j = 0; j < len / 2; j++){
base u = a[i + j], v = a[i + j + len / 2] * w;
a[i + j] = u + v;
a[i + j + len / 2] = u - v;
w *= wlen;
}
}
}
if (invert)
{
for (int i = 0; i < n; i++)
a[i] /= n;
}
}
答案 0 :(得分:0)
Cooley–Tukey FFT实现已有数百次描述。
Wiki page part with non-recursive method.
第一个循环是位反转部分-代码重新打包源数组,将第i个索引处的元素与i的反转位索引交换(因此,对于长度= 8的索引6=110b
与索引{{1}交换) },索引3=011b
保留在同一位置。
此重新排序允许按原样处理数组,对中的对进行计算,并用相应的三角系数以1,2,4,8 ...索引(此处为5=101b
步骤分隔)。
P.S。您的答案包含len/2
标记,因此这种紧凑的实现非常适合您的目的。但是对于实际工作,值得使用一些高度优化的库,例如onlinejudge
等