FFT详细推导
FFT(傅里叶快速变换)
FFT在实际工程中有着非常的广泛,尤其是在信号领域,在ACM算法竞赛领域主要可以用来快速计算多项式的乘积
一.前置知识
1.复数和单位根
有人会觉得FFT怎么会用到复数的知识,想必是有点古怪,后面在推导过程中会介绍到它的用处。
2.单位根的三个引理
3.多项式
前置知识学完了之后下面我们来推导FFT
二.FFT(快速傅里叶变换推导)
DFT的作用是把多项式的系数表示法,转化为点值表示法,复杂度 O ( n 2 ) O(n^2) O(n2),而FFT则是快速版的DFT,作用是一样的,FFT的复杂度是 O ( n l o g n ) O(nlogn) O(nlogn).
上面我们说过n次多项式需要n+1个点来唯一确定,那么我们找点的时候为什么带入的x是复数(也即wi)而不是实数呢?这个视频讲的很详细FFT推导过程。
FFT模板:
/*这里的opt=1*/
void FFT(Complex *a,int lim,int opt)
{
if(lim==1) return ;
Complex a0[lim>>1],a1[lim>>1];
/*我们把多项式的奇数项和偶数项拆开*/
for(int i=0;i<lim;i+=2)
{
a0[i>>1]=a[i],a1[i>>1]=a[i+1];
}
FFT(a0,lim>>1,opt);//然后递归拆解奇数项
FFT(a1,lim>>1,opt);//递归拆解偶数项
Complex wn = Complex(cos(2.0*PI/lim),opt*sin(2.0*PI/lim));//单位根
Complex w = Complex(1,0);//第一个根w0
for(int k=0;k<(lim>>1);k++)
{
Complex t=w*a1[k];//这样会少一次复数运算;
a[k]=a0[k]+t;//最后我们把求得的值代回
a[k+(lim>>1)]=a0[k]-t;
w=w*wn;//想当于次幂+1
}
return ;
}
三.IFFT
我们要解决多项式a和多项式b的乘积运算,FFT把多项式转化为点值表示之后,我们对两个多项式进行乘积运算,得到一个新的多项式C的点值表示,我们还需要把C的点值表示转化为系数表示,这样才能得到每一项的系数,这时就需要用到FFT的逆过程,IFFT(快速傅里叶逆变换),也就是IDFT(离散傅里叶逆变换)的快速版。
IFFT模板:
/*这里的opt=-1*/
void FFT(Complex *a,int lim,int opt)
{
if(lim==1) return ;
Complex a0[lim>>1],a1[lim>>1];
/*我们把多项式的奇数项和偶数项拆开*/
for(int i=0;i<lim;i+=2)
{
a0[i>>1]=a[i],a1[i>>1]=a[i+1];
}
FFT(a0,lim>>1,opt);//然后递归拆解奇数项
FFT(a1,lim>>1,opt);//递归拆解偶数项
Complex wn = Complex(cos(2.0*PI/lim),opt*sin