快速傅里叶变换(Fast Fourier Transform,FFT)用来计算离散傅里叶变换(Discrete Fourier Transform,DFT)及其逆变换(IDFT),本质上多项式乘法实际上是多项式系数向量的卷积(convolution)
(以上百度)
看了很多网上关于FFT的讲解,有一些是直接忽略了公式的推导,另外一些有推导,但是推导中的细节却没有讲清楚。本着不懂就学的心态,我把FFT的思维和推导细节用公式讲清楚,方便后人能更细致地学习FFT。
在了解FFT之前,需要有一些前置的知识,以下为目录。
- 欧拉函数
- 复数及单位根
- 多项式的系数、点值表达和多项式相乘
- FFT的思维过程(Cooley-Tukey 算法)
4.1 DFT
4.2 IDFT - FFT的实现过程以及FNT
一、欧拉函数
其中i为虚数单位即即虚数单位
二、复数及单位根
复数形式:,其中i为虚数单位
复数乘法:对于两个复数和,则
由于欧拉公式(见公式1)令则复数
其中为该复数所在复平面圆的半径,为该复数在复平面中的幅角。则两个复数为,即
根据4式可得,两个复数的相乘可以看作是幅角相加,模长相乘。
单位根:对于满足方程的复数,我们称其为n次单位根。由于根据复数乘法,我们可知:复数相乘为幅角相加,模长相乘。则对于每个单位根,模长为1,幅角的n倍为0。即(易得)。
为了保证幅角的n倍始终为0,由于这个性质,我们可以将单位根表示为,其中。
我们发现无论k取值,的n倍始终为0。
记,则n次单位根可以表示为
三、多项式的系数、点值表达和多项式相乘
多项式的系数表达:给定一个多项式
其中为系数向量
多项式的点值表达:给定一个多项式如公式(5),我们将其离散化,设取(这里为什么是n+1项,将在第四节中讲到)互不相同的值,将其代入可得,则为在上的点值表达。
多项式系数表达的乘法:给定两个多项式
则多项式系数表达的乘法为
其中:
有式(9)可得,计算复杂度为
多项式点值表达的乘法:给定两个多项式如式(6)与(7),则其在上的点值表达分别为:
则多项式点值表达的乘法为
可见,当我们已知即可在的复杂度下求得结果多项式的点值表达。
四、FFT的思维过程(Cooley-Tukey 算法)
对于一个多项式的乘法,根据上述前置知识的补充,我们可以得知:降低多项式乘法复杂度的方法是将常见的多项式系数表达转变为多项式的点值表达,做完点值表达的乘法后,最后再将点值表达转化为系数表达,即可完成多项式乘法。
所以问题转变为:
1.如何将多项式系数表达转变为多项式点值表达
2.如何将多项式点值表达转变为多项式系数表达
由此引出了离散傅里叶变换 DFT(Discrete Fourier Transformation)和逆离散傅里叶变换 IDFT(Inverse Discrete Fourier Transformation)
4.1 离散傅里叶变换DFT(Discrete Fourier Transformation)
离散化多项式的一种方法是将值代入到多项式中,依次求出点值。显而易见,这种方法的复杂度是的,这与我们降低复杂度的想法是冲突的。
于是我们引入了FFT的经典算法——Cooley-Tukey 算法,来降低离散化的复杂度,这是一个基于分治策略的算法。
给定一个多项式
我们将其根据奇偶项分成两个项数相同的多项式(将多项式补充到,补充项数系数为0。PS:为什么是项呢,后续将会提及):
显而易见:
在进一步之前:我们需要返回单位根的知识点。根据n次单位根的表达,我们可以获得一个等式
我们将其代入式子(14),(15)可得:
即
至此我们发现原本需要次代入值的等式降低到了次,依次递归下去,则我们只需要递归次即可在的复杂度下求得式子,即我们求得个点值对的复杂度为,是可以接受的复杂度。
为了更加严谨的证明,以下过程供还有疑问的读者参考
由于式子(16)可得
则
其中求和中的直接被替换为的原因是,经过平方以后,负号被抵消。
复杂度公式则为
以上为Cooley-Tukey离散傅里叶变换DFT的思路。
我们回到为什么我们要将多项式补充到项的问题上,我们发现,根据Cooley-Tukey 分治的策略,我们需要每次分治的两部分都有同样的项数,则总项数必须为项。
4.2 逆离散傅里叶变换IDFT(Inverse Discrete Fourier Transformation)
经过DFT,我们将多项式的系数表达转换为多项式的点值表达。在完成乘法运算以后,我们为了获取系数的变换,需要将多项式的点值表达转换为多项式的系数表达。这时我们使用的方法是逆离散傅里叶变换IDFT,他是DFT的逆。
求解IDFT的过程实际上是一个求解线性方程的问题,给出个线性方程为:
矩阵形式如下:
假设上述矩阵为,则对于矩阵中值
设两个矩阵相乘以后的结果为
当时,
当时,
(其中由于为次单位根,又因为次单位根的次为1,所以上式成立)
所以
则
则IDFT便是将对结果再做一次DFT,即可获得最后的系数。
回到为什么要有取值的原因在于:为了多项式的点值表达转换为多项式的系数表达,我们需要系数矩阵可逆,为了使得系数矩阵可逆,需要满足矩阵满秩,为了满足矩阵满秩,我们需要使得矩阵的行数大于等于列数。则对于有个系数的多项式,必须要有个以上的取值
四、FFT的实现过程以及FNT
在具体实现FFT的过程中,还需要考虑到对于每一次递归我们如何进行合理的划分。于是这里引入bitreverse算法,也叫做蝴蝶变换。
如图所示,这是16个数进行DFT变换划分的过程。网上的步骤说的很复杂,简单来说,对于DFT的第次划分,二进制第位上为的分为一类,为的分为一类,即可完成。
举例说明:
- 对于步骤一来说,第1次划分,二进制第1位(即右边第一位)为0的分到左边,为1的分到右边。我们可以发现左边都为偶数,右边都为奇数。(因为奇数二进制第1位为1)
- 对于步骤二的左半部分,第2次划分,二进制第2位(即右边第二位)为0的分到左边,为1的分到右边。同理,右半部分,第2次划分,也是二进制第2位(即右边第二位)为0的分到左边,为1的分到右边。
- 同理,对每次的分组进行划分,即可将所有的数字划分到对应的组中。
通过这种划分方法,我们同时还能总结出另外一个规律,对于对于个数字中的任意一个位置的数字,假设原本位置为,二进制反转的函数为,则最后其所在的位置为(第一个位置为0),其中为位二进制。
举例说明:
对于个数字中的,则其位二进制的反转为,则其最后的位置为第位(ps:图中没有继续将所有的数字划分到每组一个,读者可自行划分检验)
这里可以补充一个写法:假如我们将原数组定义为,经过反转后的数组定义为,则。
又因为如果是偶数,则,则对于,但考虑到如果是是奇数,则,则对于其中为满足的最小值。
综合写可以写成
通过这个写法,我们可以直接写出所有数字经过DFT划分后的结果。
参考:从多项式乘法到快速傅里叶