快速傅立叶变换(FFT)

FFT的里有许多地方我也搞不懂,我不想懂也不需要懂,知道结论能用就行了。。。看了好多天的鬼东西,本来觉得好难,看完之后觉得也不过如此。

快速傅里叶变换的java实现 快速傅里叶变换结果_快速傅里叶变换的java实现

快速傅里叶变换的java实现 快速傅里叶变换结果_递归分治_02

单位复根:

快速傅里叶变换的java实现 快速傅里叶变换结果_递归分治_03

快速傅里叶变换的java实现 快速傅里叶变换结果_多项式_04

 

快速傅里叶变换的java实现 快速傅里叶变换结果_快速傅里叶变换的java实现_05


快速傅里叶变换的java实现 快速傅里叶变换结果_多项式_06

递归的形式:

void FFT(complex<double> a[],int n){
    if(n==1) return;
    complex<double> *a0=new complex<double>[n/2];
    complex<double> *a1=new complex<double>[n/2];
    for(int i=0;i<n;i+=2){                                //用奇偶次项系数组成新的多项式
        a0[i/2]=a[i];
        a1[i/2]=a[i+1];
    }
    FFT(a0,n/2);FFT(a1,n/2);                            //递归分治问题 
    complex<double> wn(cos(2*M_PI/n),sin(2*M_PI/n));   //取n次方根 
    complex<double> w(1,0);
    for(int i=0;i<(n/2);i++){                         //蝶形操作,由下一层的a[i],a[i+n/2]
        a[i]=a0[i]+w*a1[i];                          //更新本层的 a[i],a[i+n/2]
        a[i+n/2]=a0[i]-w*a1[i];
        w=w*wn;                                      //旋转因子 
    }
    return;
}

完整代码:

#include<bits/stdc++.h>
using namespace std;
int a[100];
int b[100];
void FFT(complex<double> a[],int n,int op){
    if(n==1) return;
    complex<double> *a0=new complex<double>[n/2];
    complex<double> *a1=new complex<double>[n/2];
    for(int i=0;i<n;i+=2){                                //用奇偶次项系数组成新的多项式
        a0[i/2]=a[i];
        a1[i/2]=a[i+1];
    }
    FFT(a0,n/2,op);FFT(a1,n/2,op);                            //递归分治问题 
    complex<double> wn(cos(2*M_PI/n),sin(2*M_PI*op/n));   //取n次方根 
    complex<double> w(1,0);
    for(int i=0;i<(n/2);i++){                         //蝶形操作,由下一层的a[i],a[i+n/2]
        a[i]=a0[i]+w*a1[i];                          //更新本层的 a[i],a[i+n/2]
        a[i+n/2]=a0[i]-w*a1[i];
        w=w*wn;                                      //旋转因子 
    }
    return;
}
int main()
{
	int m1,m2;
	scanf("%d%d",&m1,&m2);
	for(int i=0;i<m1;i++){
		scanf("%d",&a[i]);
	}
	for(int i=0;i<m1;i++){
		scanf("%d",&b[i]);
	}
	int n=1;
	while(n<m1+m2){                      //不能小于两个多项式相乘的长度m1+m2
		n<<=1;
	}
	complex<double> *c=new complex<double> [n+1];
	complex<double> *d=new complex<double> [n+1];
	for(int i=0;i<m1;i++){
		c[i]=complex<double>(a[i],0);
	}
	for(int i=0;i<m2;i++){
		d[i]=complex<double>(b[i],0);
	}
	FFT(c,n,1);                //DFT变换 
	FFT(d,n,1);               //DFT变换 
	for(int i=0;i<n;i++){
		c[i]=c[i]*d[i];       //点值相乘 
	}
	FFT(c,n,-1);             //IDFT逆变换 
	
	for(int i=0;i<n;i++){
		a[i]=(c[i].real()/n+0.5);       // n倍结果 
	}
	for(int i=0;i<n;i++){
		printf("%d ",a[i]);
	}
	return 0;
} 
/*
测试数据,
输入: 
5 5
1 1 0 0 0
1 0 1 1 1
输出:
1 1 1 2 2 1 0 0 0 0 0 0 0 0 0 0 

解释:输入数据为高低位颠倒的两个数
(00011) * (11101)= (0000000000122111) 
(11) * (11101)= (122111) 
*/

注意:

快速傅里叶变换的java实现 快速傅里叶变换结果_递归分治_07

 

 

迭代替代递归:

 

减少一次DFT变换的方式:

 

尽力优化double精度误差问题:

 

NNT快速数论变换:

 

FWT?: