FFT前言
快速傅里叶变换 (fast Fourier transform),即利用计算机计算离散傅里叶变换(DFT)的高效、快速计算方法的统称,简称FFT。快速傅里叶变换是1965年由J.W.库利和T.W.图基提出的。采用这种算法能使计算机计算离散傅里叶变换所需要的乘法次数大为减少,特别是被变换的抽样点数N越多,FFT算法计算量的节省就越显著。
FFT(Fast Fourier Transformation) 是离散傅氏变换(DFT)的快速算法。即为快速傅氏变换。它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。
——百度百科
FFT(Fast Fourier Transformation),中文名快速傅里叶变换,用来加速多项式乘法
朴素高精度乘法时间 O ( n 2 ) O(n^2) O(n2),但 F F T FFT FFT能 O ( n log 2 n ) O(n\log_2 n) O(nlog2n)的时间解决
F F T FFT FFT名字逼格高,也难懂,其他教程写得让人看不太懂,于是自己随便写一下
建议对复数、三角函数相关知识有所耳闻
(不会也无所谓)下面难懂的点我会从网上盗
多项式的系数表示法和点值表示法
-
F F T FFT FFT其实是一个用 O ( n log 2 n ) O(n\log_2n) O(nlog2n)的时间将一个用系数表示的多项式转换成它的点值表示的算法
-
多项式的系数表示和点值表示可以互相转换
系数表示法
一个n-1次n项多项式 f ( x ) f(x) f(x)可以表示为 f ( x ) = ∑ i = 0 n − 1 a i x i f(x)=\sum^{n-1}_{i=0}a_ix^i f(x)=∑i=0n−1aixi
也可以用每一项的系数来表示 f ( x ) f(x) f(x),即 f ( x ) = { a 0 , a 1 , a 2 , . . . , a n − 1 } f(x)=\{a_0,a_1,a_2,...,a_{n-1} \} f(x)={
a0,a1,a2,...,an−1}
这就是系数表示法,也就是平时数学课上用的方法
点值表示法
-
把多项式放到平面直角坐标系里面,看成一个函数
-
把 n n n个不同的 x x x代入,会得出 n n n个不同的 y y y,在坐标系内就是 n n n个不同的点
-
那么这 n n n个点唯一确定该多项式,也就是有且仅有一个多项式满足 ∀ k , f ( x k ) = y k ∀k,f(x_k)=y_k ∀k,f(xk)=yk
-
理由很简单,把 n n n条式子联立起来成为一个有n条方程的n元方程组,每一项的系数都可以解出来
那么 f ( x ) f(x) f(x)还可以用 f ( x ) = { ( x 0 , f ( x 0 ) ) , ( x 1 , f ( x 1 ) ) , ( x 2 , f ( x 2 ) ) , . . . , ( x n − 1 , f ( x n − 1 ) ) } f(x)=\{(x_0,f(x_0)),(x_1,f(x_1)),(x_2,f(x_2)),...,(x_{n-1},f(x_{n-1}))\} f(x)={
(x0,f(x0)),(x1,f(x1)),(x2,f(x2)),...,(xn−1,f(xn−1))}来表示
这就是点值表示法
高精度乘法下两种多项式表示法的区别
对于两个用系数表示的多项式,我们把它们相乘
设两个多项式分别为 A ( x ) , B ( x ) A(x),B(x) A(x),B(x)
我们要枚举 A A A每一位的系数与 B B B每一位的系数相乘
那么系数表示法做多项式乘法时间复杂度 O ( n 2 ) O(n^2) O(n2)
但两个用点值表示的多项式相乘,只需要 O ( n ) O(n) O(n)的时间
什么意思呢?
设两个点值多项式分别为 f ( x ) = { ( x 0 , f ( x 0 ) ) , ( x 1 , f ( x 1 ) ) , ( x 2 , f ( x 2 ) ) , . . . , ( x n − 1 , f ( x n − 1 ) ) } f(x)=\{(x_0,f(x_0)),(x_1,f(x_1)),(x_2,f(x_2)),...,(x_{n-1},f(x_{n-1}))\} f(x)={
(x0,f(x0)),(x1,f(x1)),(x2,f(x2)),...,(xn−1,f(xn−1))} g ( x ) = { ( x 0 , g ( x 0 ) ) , ( x 1 , g ( x 1 ) ) , ( x 2 , g ( x 2 ) ) , . . . , ( x n − 1 , g ( x n − 1 ) ) } g(x)=\{(x_0,g(x_0)),(x_1,g(x_1)),(x_2,g(x_2)),...,(x_{n-1},g(x_{n-1}))\} g(x)={
(x0,g(x0)),(x1,g(x1)),(x2,g(x2)),...,(xn−1,g(xn−1))}
设它们的乘积是 h ( x ) h(x) h(x),那么 h ( x ) = { ( x 0 , f ( x 0 ) ⋅ g ( x 0 ) ) , ( x 1 , f ( x 1 ) ⋅ g ( x 1 ) ) , . . . , ( x n − 1 , f ( x n − 1 ) ⋅ g ( x n − 1 ) ) } h(x)=\{(x_0,f(x_0)·g(x_0)),(x_1,f(x_1)·g(x_1)),...,(x_{n-1},f(x_{n-1})·g(x_{n-1}))\} h(x)={
(x0,f(x0)⋅g(x0)),(x1,f(x1)⋅g(x1)),...,(xn−1,f(xn−1)⋅g(xn−1))}
所以这里的时间复杂度只有一个枚举的 O ( n ) O(n) O(n)
-
突然感觉高精度乘法能 O ( n ) O(n) O(n)暴艹一堆题?
-
但是朴素的系数表示法转点值表示法的算法还是 O ( n 2 ) O(n^2) O(n2)的,逆操作类似
-
朴素系数转点值的算法叫DFT(离散傅里叶变换),点值转系数叫IDFT(离散傅里叶逆变换)
-
难道高精度乘法只能 O ( n 2 ) O(n^2) O(n2)了吗?
DFT前置知识&技能
复数
毕竟高中有所以不多说
我们把形如a+bi(a,b均为实数)的数称为复数,其中a称为实部,b称为虚部,i称为虚数单位。当虚部等于零时,这个复数可以视为实数;当z的虚部不等于零时,实部等于零时,常称z为纯虚数。复数域是实数域的代数闭包,也即任何复系数多项式在复数域中总有根。 复数是由意大利米兰学者卡当在十六世纪首次引入,经过达朗贝尔、棣莫弗、欧拉、高斯等人的工作,此概念逐渐为数学家所接受。
——百度百科
初中数学老师会告诉你没有 − 1 \sqrt{-1} −1,但仅限 R R R
扩展至复数集 C C C,定义 i 2 = − 1 i^2=-1 i