FFT快速傅里叶变换

DFT

把系数表示把转化为点值表示法。

有多项式 f n ( x ) = ∑ i = 0 n − 1 a i x i f_n(x)=\sum_{i=0}^{n-1}a_{i}x^{i} fn(x)=i=0n1aixi,其中 n n n是一个 2 2 2的幂,现在要快速求出 ∀ i , 0 ≤ i < n \forall i,0 \le i <n i,0i<n f ( ω n i ) f(\omega_{n}^{i}) f(ωni)

首先把 f n ( x ) f_n(x) fn(x)的系数按照奇偶性分成两组,分别为 h n 2 ( x ) = ∑ i = 0 n 2 − 1 a 2 i x i h_{\frac{n}{2}}(x)=\sum_{i=0}^{\frac{n}{2}-1}a_{2i}x^i h2n(x)=i=02n1a2ixi g n 2 ( x ) = ∑ i = 0 n 2 − 1 a 2 i + 1 x i g_{\frac{n}{2}}(x)=\sum_{i=0}^{\frac{n}{2}-1}a_{2i+1}x^i g2n(x)=i=02n1a2i+1xi

那么把 f n ( ω n i ) f_n(\omega_{n}^{i}) fn(ωni)拆一下,就有如下:
f n ( ω n i ) = ∑ j = 0 n 2 − 1 a 2 j ( ω n i ) 2 j + ∑ j = 0 n 2 − 1 a 2 j + 1 ( ω n i ) 2 j + 1 = ∑ j = 0 n 2 − 1 a 2 j ( ω n 2 i ) j + ∑ j = 0 n 2 − 1 a 2 j + 1 ( ω n 2 i ) j ω n i = ∑ j = 0 n 2 − 1 a 2 j ( ω n 2 i ) j + ∑ j = 0 n 2 − 1 a 2 j + 1 ( ω n 2 i ) j ω n i = h n 2 ( ω n 2 i ) + ω n i g n 2 ( ω n 2 i ) \begin{aligned} f_n(\omega_{n}^{i}) & = \sum_{j=0}^{\frac{n}{2}-1}a_{2j}(\omega_{n}^{i})^{2j}+\sum_{j=0}^{\frac{n}{2}-1}a_{2j+1}(\omega_{n}^{i})^{2j+1} \\ & = \sum_{j=0}^{\frac{n}{2}-1}a_{2j}(\omega_{n}^{2i})^{j}+\sum_{j=0}^{\frac{n}{2}-1}a_{2j+1}(\omega_{n}^{2i})^{j}\omega_{n}^{i} \\ & = \sum_{j=0}^{\frac{n}{2}-1}a_{2j}(\omega_{\frac{n}{2}}^{i})^{j}+\sum_{j=0}^{\frac{n}{2}-1}a_{2j+1}(\omega_{\frac{n}{2}}^{i})^{j}\omega_{n}^{i} \\ & = h_{\frac{n}{2}}(\omega_{\frac{n}{2}}^{i})+\omega_{n}^{i}g_{\frac{n}{2}}(\omega_{\frac{n}{2}}^{i}) \end{aligned} fn(ωni)=j=02n1a2j(ωni)2j+j=02n1a2j+1(ωni)2j+1=j=02n1a2j(ωn2i)j+j=02n1a2j+1(ωn2i)jωni=j=02n1a2j(ω2ni)j+j=02n1a2j+1(ω2ni)jωni=h2n(ω2ni)+ωnig2n(ω2ni)
发现 g , h g,h g,h​和 f f f​是类似的,那么可以分治处理。

然后发现位置的变换是蝴蝶变换,就可以非递归计算了。

蝴蝶变换

可以发现在分治过程中,位置 i i i的值会唯一的变换到 i ′ i' i的位置,那么可否快速计算,然后从低到高合并呢?这样就可以降低常数。

当然是可以的, i ′ i' i的二进制表达式和 i i i的二进制表达式是前后对调的,证明就不写了。

IDFT

把点值化为系数表示法。

假设现在要做多项式乘法 C ( x ) = A ( x ) B ( x ) C(x)=A(x)B(x) C(x)=A(x)B(x),那么可以把他们都拓展到 ( n − 1 ) (n-1) (n1)次的多项式,其中 n n n 2 2 2的幂。接着对 A ( x ) , B ( x ) A(x),B(x) A(x),B(x) D F T DFT DFT,将其转化为点值表示法,那么对于带入的 n n n ω n i \omega_{n}^{i} ωni,都有 C ( ω n i ) = A ( ω n i ) B ( ω n i ) C(\omega_{n}^{i})=A(\omega_{n}^{i})B(\omega_{n}^{i}) C(ωni)=A(ωni)B(ωni),就是把对应位置的点值乘到一块就好了,然后对其做 I D F T IDFT IDFT即可。

假设 C ( x ) = ∑ i = 0 n − 1 a i x i C(x)=\sum_{i=0}^{n-1}a_ix^i C(x)=i=0n1aixi y i = C ( ω n i ) y_i=C(\omega_{n}^{i}) yi=C(ωni),那么有如下的矩阵乘法:
[ 1 1 1 1 ⋯ 1 1 ω n 1 ω n 2 ω n 3 ⋯ ω n n − 1 1 ω n 2 ω n 4 ω n 6 ⋯ ω n 2 ( n − 1 ) 1 ω n 3 ω n 6 ω n 9 ⋯ ω n 3 ( n − 1 ) ⋮ ⋮ ⋮ ⋮ ⋱ ⋮ 1 ω n n − 1 ω n 2 ( n − 1 ) ω n 3 ( n − 1 ) ⋯ ω n ( n − 1 ) 2 ] [ a 0 a 1 a 2 a 3 ⋮ a n − 1 ] = [ y 0 y 1 y 2 y 3 ⋮ y n − 1 ] \begin{bmatrix}1 & 1 & 1 & 1 & \cdots & 1 \\ 1 & \omega_n^1 & \omega_n^2 & \omega_n^3 & \cdots & \omega_n^{n-1} \\ 1 & \omega_n^2 & \omega_n^4 & \omega_n^6 & \cdots & \omega_n^{2(n-1)} \\ 1 & \omega_n^3 & \omega_n^6 & \omega_n^9 & \cdots & \omega_n^{3(n-1)} \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots \\ 1 & \omega_n^{n-1} & \omega_n^{2(n-1)} & \omega_n^{3(n-1)} & \cdots & \omega_n^{(n-1)^2} \end{bmatrix} \begin{bmatrix} a_0 \\ a_1 \\ a_2 \\ a_3 \\ \vdots \\ a_{n-1} \end{bmatrix} = \begin{bmatrix}y_0 \\ y_1 \\ y_2 \\ y_3 \\ \vdots \\ y_{n-1} \end{bmatrix} 111111ωn1ωn2ωn3ωnn11ωn2ωn4ωn6ωn2(n1)1ωn3ωn6ωn9ωn3(n1)1ωnn1ωn2(n1)ωn3(n1)ωn(n1)2a0a1a2a3an1=y0y1y2y3yn1
只要两边都乘上这个方阵的逆矩阵就好了,然后我们发现它的逆矩阵就是对应每一项取倒数并再除以 n n n,如下:
1 n [ 1 1 1 1 ⋯ 1 1 ω n − 1 ω n − 2 ω n − 3 ⋯ ω n − ( n − 1 ) 1 ω n − 2 ω n − 4 ω n − 6 ⋯ ω n − 2 ( n − 1 ) 1 ω n − 3 ω n − 6 ω n − 9 ⋯ ω n − 3 ( n − 1 ) ⋮ ⋮ ⋮ ⋮ ⋱ ⋮ 1 ω n − ( n − 1 ) ω n − 2 ( n − 1 ) ω n − 3 ( n − 1 ) ⋯ ω n − ( n − 1 ) 2 ] \frac{1}{n} \begin{bmatrix} 1 & 1 & 1 & 1 & \cdots & 1 \\ 1 & \omega_n^{-1} & \omega_n^{-2} & \omega_n^{-3} & \cdots & \omega_n^{-(n-1)} \\ 1 & \omega_n^{-2} & \omega_n^{-4} & \omega_n^{-6} & \cdots & \omega_n^{-2(n-1)} \\ 1 & \omega_n^{-3} & \omega_n^{-6} & \omega_n^{-9} & \cdots & \omega_n^{-3(n-1)} \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots \\ 1 & \omega_n^{-(n-1)} & \omega_n^{-2(n-1)} & \omega_n^{-3(n-1)} & \cdots & \omega_n^{-(n-1)^2} \end{bmatrix} n1111111ωn1ωn2ωn3ωn(n1)1ωn2ωn4ωn6ωn2(n1)1ωn3ωn6ωn9ωn3(n1)1ωn(n1)ωn2(n1)ωn3(n1)ωn(n1)2
那么现在来证明:

对于乘完之后的方阵,第 i i i行第 i i i列的值可任意这样计算: ∑ k = 0 n − 1 ω n i ω n − i = ∑ k = 0 n − 1 ω n 0 = n \sum_{k=0}^{n-1} \omega_{n}^{i}\omega_{n}^{-i}=\sum_{k=0}^{n-1}\omega_{n}^{0}=n k=0n1ωniωni=k=0n1ωn0=n

对于第 i i i j j j列,其中 i ≠ j i \not = j i=j,可以这样计算: ∑ k = 0 n − 1 ( ω n i − j ) k = ( ω n i − j ) n − ( ω n i − j ) 0 ω n i − j − 1 = 0 \sum_{k=0}^{n-1}(\omega_{n}^{i-j})^{k}=\frac{(\omega_{n}^{i-j})^n-(\omega_{n}^{i-j})^0}{\omega_{n}^{i-j}-1}=0 k=0n1(ωnij)k=ωnij1(ωnij)n(ωnij)0=0

再乘上矩阵前面的 1 n \frac{1}{n} n1,那么逆矩阵就得证了,于是又是一个 D F T DFT DFT。这次的系数是计算出来的点值,带入的是 ω n − i \omega_{n}^{-i} ωni,最后把 1 n \frac{1}{n} n1乘进去就好了。

#include<bits/stdc++.h>
using namespace std;
const int N=1<<22;
typedef complex<double> comp;
comp f[N],g[N],h[N];
int r[N];
int nf,ng,nh=1;
void FFT(comp *f,int rev){//rev=1->DFT  rev=-1->IDFT
	for (int i=0;i<nh;++i) if (r[i]<i) swap(f[i],f[r[i]]);
	for (int l=2;l<=nh;l<<=1){
		for (int i=0;i<nh;i+=l){
			comp step=comp(cos(2.0*M_PI/l),sin(2.0*M_PI/l)*rev),mul=comp(1,0);
			for (int j=0;j<(l>>1);++j){
				comp tmp=f[i+j+(l>>1)];
				f[i+j+(l>>1)]=f[i+j]-mul*tmp;
				f[i+j]=f[i+j]+mul*tmp;
				mul=mul*step;
			}
		}
	}
}
int main(){
	scanf("%d%d",&nf,&ng);
	while (nh-1<nf+ng)
		nh<<=1;
	for (int i=0;i<=nf;++i){double x;scanf("%lf",&x);f[i]=comp(x,0);}
	for (int i=0;i<=ng;++i){double x;scanf("%lf",&x);g[i]=comp(x,0);}
	r[0]=0; 
	for (int i=1;i<nh;++i) r[i]=(r[i>>1]>>1)|(i&1?(nh>>1):0);
	FFT(f,1);
	FFT(g,1);
	for (int i=0;i<nh;++i) h[i]=f[i]*g[i];
	FFT(h,-1);
	for (int i=0;i<=nf+ng;++i) printf("%d ",(int)round(h[i].real()/nh));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值