快速傅里叶变换(FFT)算法
By Long Luo
之前的文章 傅里叶变换(Fourier Transform) 详细介绍了傅里叶变换 \((\textit{Fourier Transform})\) 是什么和做什么,相信你已经感受到了傅里叶变换的强大之处。
但理论要联系实际,今天我们就来学习 快速傅里叶变换 \((\textit{Fast Fourier Transform, FFT})\) 1 的实际运用:多项式乘法。
快速傅里叶变换(Fast Fourier Transform, FFT)
快速傅里叶变换 \((\textit{Fast Fourier Transform, FFT})\) 2 是一种可在 \(O(nlogn)\) 时间内完成的 离散傅里叶变换3 \((\textit{Discrete Fourier transform, DFT})\) 算法。
FFT可以做什么?
傅里叶变换 \((\textit{Fourier Transform})\) 本质上是信号与三角函数进行卷积运算,而快速傅里叶变换 \((\textit{FFT})\) 就是提高卷积的计算效率,时间复杂度从 \(O(n^2)\) 降低到 \(O(n \log n)\)。
\(\textit{FFT}\) 在算法中的运用主要是用来加速多项式乘法或大数乘法。
多项式乘法
正如之前的文章 卷积(Convolution) 所说,多项式乘法也是一种卷积运算。
在计算中,泰勒级数4 可以使用多项式函数来逼近一个函数,所以计算中多项式乘法非常重要。
大数乘法
超大数字乘法,可以参考 超大数字的四则运算是如何实现的呢? 。朴素的算法就是列竖式做乘法,算法时间复杂度为 \(O(n^2)\) ,如果数字太大的话,效率也不够高,如果应用 \((\textit{FFT})\) 则可以使算法时间复杂度降至 \(O(n \log n)\)。
不妨设十进制数字 \(num = 123456789\) ,很容易知道:
\[ 123456789 = 1 \times 10^8 + 2 \times 10^7 + 3 \times 10^6 + 4 \times 10^5 + 5 \times 10^4 + 6 \times 10^3 + 7 \times 10^2 + 8 \times 10^1 + 9 \times 10^0 \]
令 \(x = 10\),则可以转化为:
\[ 1 \times x^8 + 2 \times x^7 + 3 \times x^6 + 4 \times x^5 + 5 \times x^4 + 6 \times x^3 + 7 \times x^2 + 8 \times x^1 + 9 \times x^0 \]
所以大数乘法就是 \(x = 10\) 情况下的多项式乘法!
那下面我们就以多项式乘法的为例来学习快速傅里叶变换 \((\textit{FFT})\) 具体是如何做的。
多项式
在学习多项式乘法之前,我们需要先学习下有关多项式的知识。
多项式有两种表示方法: 系数表示法与点值表示法。
系数表示法
设多项式 \(A(x)\) 为一个 \(n\) 项 \(n - 1\) 次的多项式,显然,所有项的系数组成的系数向量 \((a_0, a_1, a_2, \dots, a_{n-1})\) 唯一确定了这个多项式。
\[ A(x) = \sum_{i=0}^{n-1}a_i \cdot x^i = a_0 + a_1x^1 + a_2x^2 + \cdots + a_{n-1}x^{n-1} \iff A(x) = {a_0, a_1, \dots, a_{n-1}} \]
点值表示法
点值表示法是把这个多项式看成一个函数,从其中选取 \(n\) 个不同的点,从而利用这 \(n\) 个点来唯一地表示这个函数。
设
\[ \begin{array}{c} A(x_0) = y_0 = a_0 + a_1x_0+a_2x_0^2+a_3x_0^3+ \cdots + a_{n-1}x_0^{n-1} \\ A(x_1) = y_1 = a_0 + a_1x_1+a_2x_1^2+a_3x_1^3+ \cdots + a_{n-1}x_1^{n-1} \\ A(x_2) = y_2 = a_0 + a_1x_2+a_2x_2^2+a_3x_2^3+ \cdots + a_{n-1}x_2^{n-1} \\ \vdots \\ A(x_{n-1}) = y_{n-1} = a_0 + a_1x_{n-1}+a_2x_{n-1}^2+a_3x_{n-1}^3+ \cdots + a_{n-1}x_{n-1}^{n-1} \end{array} \]
那么用点值表示法表示 \(A(x)\) 如下:
\[ A(x) = a_0 + a_1x + a_2x^2 + \cdots + a_{n-1}x^{n-1} \iff A(x) = {(x_0,y_0), (x_1,y_1), \cdots,(x_{n-1},y_{n-1})} \]
为什么用 \(n\) 个不同点就能唯一地表示一个 \(n-1\) 次函数?
证明如下:
- Proof \(1\) :
两点确定一条直线。再来一个点,能确定这个直线中的另一个参数,那么也就是说 \(n\) 个点能确定 \(n-1\) 个参数(不考虑倍数点之类的没用点)。
- Proof \(2\)5 :
假设原命题不成立,则存在两个不同的 \(n-1\) 次多项式函数 \(A(x)\) ,\(B(x)\) ,那么 \(A(x)\) ,\(B(x)\) 有 \(n-1\) 个交点,即任何 \(i \in [0, n-1]\),有 \(A(x_i) = B(x_i)\) 。
令 \(C(x) = A(x) - B(x)\) ,则 \(C(x)\) 也是一个 \(n-1\) 次多项式。对于任何 \(i \in [0, n-1]\),都有 \(C(x_i) = 0\) 。
即 \(C(x)\) 有 \(n\) 个根,这与代数基本定理(一个 \(n-1\) 次多项式在复数域上有且仅有 \(n-1\) 个根)相矛盾,故 \(C(x)\) 并不是一个 \(n-1\) 次多项式,推导矛盾。
故原命题成立。