码迷,mamicode.com
首页 > 其他好文 > 详细

FFT

时间:2019-05-31 23:44:32      阅读:131      评论:0      收藏:0      [点我收藏+]

标签:isp   研究   平行四边形   四边形   otto   计算   有一个   最大的   圆心   

多项式

系数表示法

A(x)A(x)表示一个n-1n1次多项式

A(x)=\sum_{i=0}^{n} a_i * x^iA(x)=i=0n?ai?xi

例如:A(3)=2+3*x+x^2A(3)=2+3x+x2

利用这种方法计算多项式乘法复杂度为O(n^2)O(n2)

(第一个多项式中每个系数都需要与第二个多项式的每个系数相乘)

点值表示法

nn互不相同的xx带入多项式,会得到nn个不同的取值yy

则该多项式被这nn个点(x_1,y_1),(x_2,y_2),\dots,(x_n,y_n)(x1?,y1?),(x2?,y2?),,(xn?,yn?)唯一确定

其中y_i=\sum_{j=0}^{n-1} a_j*x_i^jyi?=j=0n1?aj?xij?

例如:上面的例子用点值表示法可以为(0,2),(1,5),(2,12)(0,2),(1,5),(2,12)

利用这种方法计算多项式乘法的时间复杂度仍然为O(n^2)O(n2)

(选点O(n)O(n),每次计算O(n)O(n))

我们可以看到,两种方法的时间复杂度都为O(n^2)O(n2),我们考虑对其进行优化

对于第一种方法,由于每个点的系数都是固定的,想要优化比较困难

对于第二种方法,貌似也没有什么好的优化方法,不过当你看完下面的知识,或许就不这么想了

 复数

在介绍复数之前,首先介绍一些可能会用到的东西

向量

同时具有大小和方向的量

在几何中通常用带有箭头的线段表示

圆的弧度制

等于半径长的圆弧所对的圆心角叫做1弧度的角,用符号rad表示,读作弧度。用弧度作单位来度量角的制度叫做弧度制

公式:

1^{\circ }=\dfrac{\pi}{180}rad1°=180π?rad

180^{\circ }=\pi rad180°=πrad

平行四边形定则

平行四边形定则:AB+AD=AC

复数

定义

a,ba,b为实数,i^2=-1i2=1,形如a+bia+bi的数叫负数,其中ii被称为虚数单位,复数域是目前已知最大的域

在复平面中,xx代表实数,yy轴(除原点外的点)代表虚数,从原点(0,0)(0,0)到(a,b)(a,b)的向量表示复数a+bia+bi

模长:从原点(0,0)(0,0)到点(a,b)(a,b)的距离,即\sqrt{a^2+b^2}a2+b2?

幅角:假设以逆时针为正方向,从xx轴正半轴到已知向量的转角的有向角叫做幅角

运算法则

加法:

因为在复平面中,复数可以被表示为向量,因此复数的加法与向量的加法相同,都满足平行四边形定则(就是上面那个)

乘法:

几何定义:复数相乘,模长相乘,幅角相加

代数定义:(a+bi)*(c+di)(a+bi)(c+di)

=ac+adi+bci+bdi^2=ac+adi+bci+bdi2

=ac+adi+bci-bd=ac+adi+bcibd

=(ac-bd)+(bc+ad)i=(acbd)+(bc+ad)i

单位根

下文中,默认nn为22的正整数次幂

在复平面上,以原点为圆心,11为半径作圆,所得的圆叫单位圆。以圆点为起点,圆的nn等分点为终点,做nn个向量,设幅角为正且最小的向量对应的复数为\omega_nωn?,称为nn次单位根。

根据复数乘法的运算法则,其余n-1n1个复数为\omega_n^2,\omega_n^3,\ldots,\omega_n^nωn2?,ωn3?,,ωnn?

注意\omega_n^0=\omega_n^n=1ωn0?=ωnn?=1(对应复平面上以xx轴为正方向的向量)

那么如何计算它们的值呢?这个问题可以由欧拉公式解决\omega_{n}^{k}=\cos\ k *\frac{2\pi}{n}+i\sin k*\frac{2\pi}{n}ωnk?=cos kn2π?+isinkn2π?

单位根的幅角为周角的\dfrac{1}{n}n1?

在代数中,若z^n=1zn=1,我们把zz称为nn次单位根

单位根的性质

$\omega _{n}^{k}=\cos k\dfrac{2\pi}{n}+i\sin k\dfrac {2\pi }{n}$ωnk?=coskn2π?+isinkn2π?(即上面的公式) \omega _{2n}^{2k}=\omega _{n}^{k}ω2n2k?=ωnk? 证明:

\omega _{2n}^{2k}=\cos 2k*\frac{2\pi}{2n}+i\sin2k*\frac{2\pi}{2n}ω2n2k?=cos2k2n2π?+isin2k2n2π?

=\omega _{n}^{k}=ωnk?

\omega _{n}^{k+\frac{n}{2}}=-\omega _{n}^{k}ωnk+2n??=ωnk?\omega _{n}^{\frac{n}{2}}=\cos\frac{n}{2}*\frac{2\pi}{n}+i\sin\frac{n}{2}*\frac{2\pi}{n}ωn2n??=cos2n?n2π?+isin2n?n2π?

=\cos \pi+i\sin\pi=cosπ+isinπ

=-1=1

\omega _{n}^{0}=\omega _{n}^{n}=1ωn0?=ωnn?=1 讲了这么多,貌似跟我们的正题没啥关系啊。。

OK!各位坐稳了,前方高能!

快速傅里叶变换

我们前面提到过,一个nn次多项式可以被nn个点唯一确定。

那么我们可以把单位根的00到n-1n1次幂带入,这样也可以把这个多项式确定出来。但是这样仍然是O(n^2)O(n2)的呀!

我们设多项式A(x)A(x)的系数为(a_o,a_1,a_2,\ldots,a_{n-1})(ao?,a1?,a2?,,an1?)

那么A(x)=a_0+a_1*x+a_2*{x^2}+a_3*{x^3}+a_4*{x^4}+a_5*{x^5}+ \dots+a_{n-2}*x^{n-2}+a_{n-1}*x^{n-1}A(x)=a0?+a1?x+a2?x2+a3?x3+a4?x4+a5?x5+?+an2?xn2+an1?xn1

将其下标按照奇偶性分类

A(x)=(a_0+a_2*{x^2}+a_4*{x^4}+\dots+a_{n-2}*x^{n-2})+(a_1*x+a_3*{x^3}+a_5*{x^5}+ \dots+a_{n-1}*x^{n-1})A(x)=(a0?+a2?x2+a4?x4+?+an2?xn2)+(a1?x+a3?x3+a5?x5+?+an1?xn1)

A_1(x)=a_0+a_2*{x}+a_4*{x^2}+\dots+a_{n-2}*x^{\frac{n}{2}-1}A1?(x)=a0?+a2?x+a4?x2+?+an2?x2n?1

A_2(x)=a_1*x+a_3*{x}+a_5*{x^2}+ \dots+a_{n-1}*x^{\frac{n}{2}-1}A2?(x)=a1?x+a3?x+a5?x2+?+an1?x2n?1

那么不难得到

A(x)=A_1(x^2)+xA_2(x^2)A(x)=A1?(x2)+xA2?(x2)

我们将\omega_n^k (k<\frac{n}{2})ωnk?(k<2n?)代入得

A(\omega_n^k)=A_1(\omega_n^{2k})+\omega_n^kA_2(\omega_n^{2k})A(ωnk?)=A1?(ωn2k?)+ωnk?A2?(ωn2k?)

=A_1(\omega_{\frac{n}{2}}^{k})+\omega_n^kA_2(\omega_{\frac{n}{2}}^{k})=A1?(ω2n?k?)+ωnk?A2?(ω2n?k?)

同理,将\omega_n^{k+\frac{n}{2}}ωnk+2n??代入得

A(\omega_n^{k+\frac{n}{2}})=A_1(\omega_n^{2k+n})+\omega_n^{k+\frac{n}{2}}(\omega_n^{2k+n})A(ωnk+2n??)=A1?(ωn2k+n?)+ωnk+2n??(ωn2k+n?)

=A_1(\omega_n^{2k}*\omega_n^n)-\omega_n^kA_2(\omega_n^{2k}*\omega_n^n)=A1?(ωn2k?ωnn?)ωnk?A2?(ωn2k?ωnn?)

=A_1(\omega_n^{2k})-\omega_n^kA_2(\omega_n^{2k})=A1?(ωn2k?)ωnk?A2?(ωn2k?)

大家有没有发现什么规律?

没错!这两个式子只有一个常数项不同!

那么当我们在枚举第一个式子的时候,我们可以O(1)O(1)的得到第二个式子的值

又因为第一个式子的kk在取遍[0,\frac{n}{2}-1][0,2n?1]时,k+\frac{n}{2}k+2n?取遍了[\frac{n}{2},n-1][2n?,n1]

所以我们将原来的问题缩小了一半!

而缩小后的问题仍然满足原问题的性质,所以我们可以递归的去搞这件事情!

直到多项式仅剩一个常数项,这时候我们直接返回就好啦

时间复杂度:

不难看出FFT是类似于线段树一样的分治算法。

因此它的时间复杂度为O(nlogn)O(nlogn)

快速傅里叶逆变换

不要以为FFT到这里就结束了。

我们上面的讨论是基于点值表示法的。

但是在平常的学习和研究中很少用点值表示法来表示一个多项式。

所以我们要考虑如何把点值表示法转换为系数表示法,这个过程叫做傅里叶逆变换

(y_0,y_1,y_2,\dots,y_{n-1})(y0?,y1?,y2?,,yn1?)为(a_0,a_1,a_2,\dots,a_{n-1})(a0?,a1?,a2?,,an1?)的傅里叶变换(即点值表示)

设有另一个向量(c_0,c_1,c_2,\dots,c_{n-1})(c0?,c1?,c2?,,cn1?)满足

c_k=\sum_{i=0}^{n-1}y_i(\omega_n^{-k})^ick?=i=0n1?yi?(ωnk?)i

即多项式B(x)=y_0,y_1x,y_2x^2,\dots,y_{n-1}x^{n-1}B(x)=y0?,y1?x,y2?x2,,yn1?xn1在\omega_n^{0},\omega_n^{-1},\omega_n^{-2},\dots,\omega_{n-1}^{-(n-1)}ωn0?,ωn1?,ωn2?,,ωn1(n1)?处的点值表示

emmmm又到推公式时间啦

(c_0,c_1,c_2,\dots,c_{n-1})(c0?,c1?,c2?,,cn1?)满足c_k=\sum_{i=0}^{n-1}y_i(\omega_n^{-k})^ick?=i=0n1?yi?(ωnk?)i

=\sum_{i=0}^{n-1}(\sum_{j=0}^{n-1}a_j(\omega_n^i)^j)(\omega_n^{-k})^i=i=0n1?(j=0n1?aj?(ωni?)j)(ωnk?)i

=\sum_{i=0}^{n-1}(\sum_{j=0}^{n-1}a_j(\omega_n^j)^i)(\omega_n^{-k})^i=i=0n1?(j=0n1?aj?(ωnj?)i)(ωnk?)i

=\sum_{i=0}^{n-1}(\sum_{j=0}^{n-1}a_j(\omega_n^j)^i(\omega_n^{-k})^i)=i=0n1?(j=0n1?aj?(ωnj?)i(ωnk?)i)

=\sum_{i=0}^{n-1}\sum_{j=0}^{n-1}a_j(\omega_n^j)^i(\omega_n^{-k})^i=i=0n1?j=0n1?aj?(ωnj?)i(ωnk?)i

=\sum_{i=0}^{n-1}\sum_{j=0}^{n-1}a_j(\omega_n^{j-k})^i=i=0n1?j=0n1?aj?(ωnjk?)i

=\sum_{j=0}^{n-1}a_j(\sum_{i=0}^{n-1}(\omega_n^{j-k})^i)=j=0n1?aj?(i=0n1?(ωnjk?)i)

S(x)=\sum_{i=0}^{n-1}x^iS(x)=i=0n1?xi

\omega_n^kωnk?代入得

S(\omega_n^k)=1+(\omega_n^k)+(\omega_n^k)^2+\dots(\omega_n^k)^{n-1}S(ωnk?)=1+(ωnk?)+(ωnk?)2+(ωnk?)n1

k!=0k!=0时

等式两边同乘\omega_n^kωnk?

\omega_n^kS(\omega_n^k)=\omega_n^k+(\omega_n^k)^2+(\omega_n^k)^3+\dots(\omega_n^k)^{n}ωnk?S(ωnk?)=ωnk?+(ωnk?)2+(ωnk?)3+(ωnk?)n

两式相减得

\omega_n^kS(\omega_n^k)-S(\omega_n^k)=(\omega_n^k)^{n}-1ωnk?S(ωnk?)S(ωnk?)=(ωnk?)n1

S(\omega_n^k)=\frac{(\omega_n^k)^{n}-1}{\omega_n^k-1}S(ωnk?)=ωnk?1(ωnk?)n1?

S(\omega_n^k)=\frac{(\omega_n^n)^{k}-1}{\omega_n^k-1}S(ωnk?)=ωnk?1(ωnn?)k1?

S(\omega_n^k)=\frac{1-1}{\omega_n^k-1}S(ωnk?)=ωnk?111?

观察这个式子,不难看出它分母不为0,但是分子为0

因此,当K!=0K!=0时,S(\omega^{k}_{n})=0S(ωnk?)=0

那当k=0k=0时呢?

很显然,S(\omega^{0}_{n})=nS(ωn0?)=n

继续考虑刚刚的式子

c_k=\sum_{j=0}^{n-1}a_j(\sum_{i=0}^{n-1}(\omega_n^{j-k})^i)ck?=j=0n1?aj?(i=0n1?(ωnjk?)i)当j!=kj!=k时,值为00 当j=kj=k时,值为nn 因此,c_k=na_kck?=nak?a_k=\frac{c_k}{n}ak?=nck??

这样我们就得到点值与系数之间的表示啦

FFT

标签:isp   研究   平行四边形   四边形   otto   计算   有一个   最大的   圆心   

原文地址:https://www.cnblogs.com/guoshaoyang/p/10957854.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!