简介
FFT(快速傅里叶变换Fast Fourier Transformation)是DFT(离散傅里叶变换Discrete Fourier Transform)的快速算法,它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。
FFT是用来进行多项式乘法运算,对于多项式加法,我们只需要将次数相同的数的系数相加即可。然而乘法会复杂很多,对于两个n-1次多项式,算出他们的乘积的复杂度为 O(N2) O ( N 2 ) ,这显然不是特别优秀,所以我们的数学家就想出了FFT,可以将复杂度优化到 O(Nlog2N) O ( N l o g 2 N )
预备知识:
多项式的点值表示
多项式的点值表示也就是把不同的数值带入多项式,然后算出结果。
定理:一个 n−1 次多项式在 n 个不同点的取值唯一确定了该多项式。
证明:假设命题不成立,存在两个不同的 n−1 n − 1 次多项式 A(x)、B(x) A ( x ) 、 B ( x ) 满足对于任何 i∈[0,n−1] i ∈ [ 0 , n − 1 ] 都存在 A(xi)=B(xi) A ( x i ) = B ( x i ) 。
令 C(x)=A(x)−B(x) C ( x ) = A ( x ) − B ( x ) ,则 C C 也是一个 次多项式,并且对于任何 i∈[0,n−1] i ∈ [ 0 , n − 1 ] , C(xi)=0 C ( x i ) = 0 。所以 C C 有 个根。
这与代数基本定理矛盾,所以证明完毕。
于是我们就有了把多项式转化为点值,然后让点值相称,最终再重新插值,求出最终的多项式这样一种思路。但是这种方法的朴素时间复杂度依旧为 O(N2) O ( N 2 )
弧度制
弧度制也就是用弧度来表示角度,我们定义 πrad=180° π r a d = 180 °
这里介绍弧度制主要是因为C++三角函数库是使用弧度制的。
复数
复数域是目前已知最大的数域,我们知道在实数的时候 sqrt(−1) s q r t ( − 1 ) 是不存在意义的,但是在复数域下, sqrt(−1)=i s q r t ( − 1 ) = i ,并且我们对复数的定义与 i i 有关,复数的通式为
复平面
既然复数的定义是 a+bi a + b i ,那么我们将点(a,b)放在直角坐标系里面,则复数就转化为了一些点。我们让复平面上点 (0,0) ( 0 , 0 ) 到点 (a,b) ( a , b ) 的向量代表这个复数。则将 (0,0) ( 0 , 0 ) 到 (a,b) ( a , b ) 的长度成为模长,将从x轴转到向量的角度大小成为幅角。
那么在这个复平面上,两个复数相加就代表着两个向量按照平行四边形法则相加;两个复数相乘就代表着两个向量模长相乘,幅角相加。
单位根
在复平面上以圆心为起点,以1为半径画圆。这个圆称为单位圆。那么选圆上的点有什么用呢?因为我们发现,复数相乘是模长相乘,幅角相加。那么我们选取单位圆上的点,也就保证了模长一直是1。再进行复数乘积时,就不许要考虑模长,只要相加幅角即可。
我们设 n=2x,x∈N n = 2 x , x ∈ N 。那么我们将单位圆从(1,0)开始划分为n等份(令 wn w n 为到(0,1)的向量,称为n次单位根),则沿着逆时针方向的向量刚好对应着 w1n,w2n…… w n 1 , w n 2 … …
关于单位根的三个重要性质
1. w2k2n=wkn w 2 n 2 k = w n k 这个可以根据单位圆图像的性质来证明。
2. wkn=cos k2πn+i sin k2πn w n k = c o s k 2 π n + i s i n k 2 π n 这个根据三角函数即可
3. wk+n2n=−wkn w n k + n 2 = − w n k
wk+n2n=wkn∗wn2n w n k + n 2 = w n k ∗ w n n 2
wn2n=cos π+i sin π=−1 w n n 2 = c o s π + i s i n π = − 1
wk+n2n=wkn∗−1=−wkn w n k + n 2 = w n k ∗ − 1 = − w n k
快速傅里叶变换:
离散傅里叶变换
我们考虑用点值表示多项式 A(x) A ( x ) 。我们将n次单位根0~n-1代入多项式,得到点值向量
(A(w0n),A(