FFT

应某大巨神·红太阳斯基·FSYo之邀来写FFT的解释。

用途

FFT,快速傅里叶变换,处理两个多项式乘积。

众所周知两个多项式相乘复杂度是n^2的,参照高精度。

而FFT可以降至nlogn。

 

前置知识及概念

一、多项式的表示方法

平常常用的多项式是系数表示法。就是通过将x的幂次方分类,记录系数。

形如f(x)=\sum_{i=0}^na_ix^i

而众所周知一个n次多项式可以被n个点唯一表示。

所以还有一种是点值表示法

形如f(x)=\left \{ (x_0,y_0),(x_1,y_1)...(x_n,y_n)\right\}

而处理两个多项式f和g的卷积时,用系数表示法,是O(n^2)的。

但用点值表示法,可以做到O(n)。就是两个多项式都用同样的一组x来求点值,然后对应相乘。

但很可惜,将系数表示转化成点值表示以及转换回去都是O(n^2)的。所以复杂度没变。

系数表示转到点值表示叫DFT(离散傅里叶变换),反过来叫IDFT(离散傅里叶逆变换)

 

二、复数

扩展复数集,定义i^2=-1。也就是i=\sqrt {-1}

然后有一个复数域的平面直角坐标系,横坐标是实数,纵坐标是复数。

这样坐标系上每个点都可以用a+bi来表示。

这样的一个点,它的模长定义为\sqrt{a^2+b^2}

它的共轭复数定义为a-bi,就是后面取反。

复数的四则运算:

加减法参考向量,乘法其实也一样,不过i^2=-1,所以(a+bi)(c+di)=(ac-bd)+(ad+bc)i;

如果你的数学思维够敏锐,你会发现ac-bd和ad+bc神似和差化积的cos和sin两个公式。

所以如果我们用模长+极角的方式来表示复数向量的话,就会得到复数相乘的一个性质。

令(a,β)表示一个模长为a,极角为β的复数点。

则(a,β)*(c,δ)=(ac,β+δ)

俗称模长相乘,极角相加

 

DFT(离散傅里叶变换)

我们在做高精度的时候可以发现,x的幂次方不同导致的多次计算是很tm烦人的。

但如果x的多少次方都不变,那就可以省事。对于一个复数平面,能做到这样省事的,其实就是单位圆上的点。

因为模长相乘,极角相加。只要是单位圆上的点,无论怎么自乘,都只能在圆上面转圈圈。

可以画个图感受一下。

 

我们打算将这个圆等分。接下来,我们会把这个圆分成2的整数幂个部分。

假设分成了n等份。从极角为0(也就是x正半轴那个点开始)的开始,编号为0。得到了0~n-1这n个点。

我们将k号点表示为\omega_n^k。令\omega_n^1为单位根。这个东西自乘可以得到圆上所有点。

FFT到底是怎么降低复杂度的呢?就是通过取一些特殊的点来转换点值表示法。

我们选取的点,就是这些等分点。

 

关于这些omega,很明显的有几个性质(想象自己在圆上转圈圈)

\omega_n^k=\omega_{2n}^{2k},\omega_n^k=-\omega_n^{k+\frac{n}{2}},\omega_n^n=\omega_n^0

多转几圈就懂了。

 

FFT(快速傅里叶变换)

我们虽然得到了这些点值。但复杂度还是n^2,没有任何用处。

那我们开始推导,怎么做FFT。

提示:再次确定FFT的意义:将系数表达式转换成点值表达式。

再次回顾:我们的多项式一定是2的整数个项数的。不够就补齐。

多项式有多少项,我的omega就分多少个出来。

 

我们要搞的多项式令为F(x)=\sum_{i=0}^{n-1}a_ix^i

将其按照x的次数的奇偶性分类,得到F(x)=(a_0+a_2x^2+a_4x^4+...)+(a_1x+a_3x^3+a_5x^5+...)

倘若我们令两个多项式分别为f1(x)=a_0+a_2x+a_4x^2+...,f2(x)=a_1+a_3x+a_5x^2+...

这两个多项式分别有n/2项。

那明显的是F(x)=f1(x^2)+xf2(x^2)

设k,然后将\omega_n^k作为x代入F。

F(\omega_n^k)=f1(\omega_{\frac{n}{2}}^{k})+\omega_n^kf2(\omega_{\frac{n}{2}}^{k})

再将\omega_n^{k+\frac{n}{2}}代入,得到

F(\omega_n^{k+\frac{n}{2}})=f1(\omega_{\frac{n}{2}}^k)-\omega_{n}^kf2(\omega_{\frac{n}{2}}^k)

可以手推一下。

那事情很明显了,两个点值只有后面那一坨不一样。

那我们已经得到了朴素的FFT,递归处理版本。代码不放了,因为还有更好的。

复杂度nlog^2n。

 

递归处理是很毒瘤的,凭空多一个log。我们其实还有更好的方法。

很明显,这些系数将在递归过程中被不断按照奇偶性分类,分类在分类,然后变得很混乱。

如果我们一开始就能确定最后谁在哪个地方,就可以省去递归向下的过程,直接从下往上迭代上来。

在这里插入图片描述

持续盗图,,

发现最后位置就是二进制翻转后的地方。

通过for(int i=0;i<limit;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));来运算。

像之前那样一加一减弄上来就行。变成nlogn。

 

IDFT

忘了怎么推得了,,构造omega矩阵的逆矩阵。构造出来就发现其实就是\omega_n^k变成\frac{1}{n}\omega_n^{-k}

所以就在FFT的时候虚数部分乘-1,然后最后全部除以n就行。

 

大概完了,,代码什么的网上有很多,都挺好看的。

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值