快速傅里叶变换

快速计算多项式相乘系数 FFT快速傅里叶变换

快速傅里叶变换(FFT)——有史以来最巧妙的算法?

正常求两个多项式乘积

A(x)=i=0nAixi,B(x)=i=0nBixiC(x)=i=0nj=0nAiBjxi+j

复杂度为O(n2)

分别设n+1个在A与B上的点

根据高斯消元法,n+1个不同的点一定能确定一个唯一的n次多项式

A(x)={(x0,A(x0)),(x1,A(x1)),(x2,A(x2))...(xn,A(xn))}B(x)={(x0,B(x0)),(x1,B(x1)),(x2,B(x2))...(xn,B(xn))}

横坐标相同的点相乘

C(x)={(x0,A(x0)B(x0)),(x1,A(x1)B(x1))...(xn,A(xn)B(xn))}

那么就有两个问题:

1.怎么快速得到n+1个点

2.怎么将点值表达法变回系数

如果A(x)是一个偶函数,那么A(x)=A(x),因此带入一个值也就得到了两个点

同理如果A(x)是一个奇函数,那么有A(x)=A(x),也可以带一个点得到两个点

因此可以将A(x)分成奇函数部分与偶函数部分

P(x)=a0+a1x+a2x2+...+anxnP(x)=(a0+a2x2+a4x4+...)+x(a1+a3x2+a5x4+...)P(x)=Pe(x2)+xPo(x2)P(xi)=Pe(xi2)+xiPo(xi2)P(xi)=Pe(xi2)xiPo(xi2)

然后如果将Pe(x),Po(x)继续分解

但我们的Pe(x),Po(x)是通过P(x)=Pe(x2)+xPo(x2)得来的,因此取相反数也无法让它们一一符号相反

那么我们取复数呢?

i2=(i)2=112=(1)2=1i,i,1,1: x1,x1,x2,x21,1:x12,x221:x14n4

那么更大的呢?

我们令w=e2πin=cos(2πn)+isin(2πn),我们可以得到它的性质正好可以解决该问题

捕获

反过来呢?

w=e2πin,然后给每个数都乘上1n即可

//初始化每个位置最终到达的位置 
void init(int k)
{
    int len=1<<k;
	for(int i=0;i<len;i++)
	rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
}
//a表示要操作的系数,n表示序列长度
//若flag为1,则表示FFT,为-1则为IFFT(需要求倒数)
void fft(cp *a,int n,int flag){ 
    for(int i=0;i<n;i++)
	{
	 //i小于rev[i]时才交换,防止同一个元素交换两次,回到它原来的位置。 
	  if(i<rev[i])swap(a[i],a[rev[i]]);
	}
	for(int h=1;h<n;h*=2)//h是准备合并序列的长度的二分之一
	{
		cp wn=exp(cp(0,flag*pie/h));//求单位根w_n^1 
		for(int j=0;j<n;j+=h*2)//j表示合并到了哪一位
		{
			cp w(1,0);
			for(int k=j;k<j+h;k++)//只扫左半部分,得到右半部分的答案
			{
			    cp x=a[k];
			    cp y=w*a[k+h];
		        a[k]=x+y;  //这两步是蝴蝶变换 
		        a[k+h]=x-y;
		        w*=wn; //求w_n^k 
			}
		 }
	 }
	 //判断是否是FFT还是IFFT 
	 if(flag==-1)
	 for(int i=0;i<n;i++)
     a[i]/=n;
}

posted @   xxcdsg  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示