多项式的点值表示(Point Value Representation)

设多项式的系数表示(Coefficient Representation)
\[
\begin{align*}
\mathrm P_a(x)&=a_0+a_1x+a_2x^2+\cdots+a_{n-1}x^{n-1} \\
&= \sum_{i=0}^{n-1}a_ix^i
\end{align*}
\]
则我们对上面的式子可以代入不同的 \(n\) 个 \(x\) 的值,构成一个 \(n\) 维向量:
\[
\begin{bmatrix}
\mathrm P_a(x_0) \\
\mathrm P_a(x_1) \\
\mathrm P_a(x_2) \\
\vdots \\
\mathrm P_a(x_{n-1})
\end{bmatrix} =
\begin{bmatrix}
1 & x_0 & x_0^2 & \cdots & x_0^{n-1} \\
1 & x_1 & x_1^2 & \cdots & x_1^{n-1} \\
1 & x_2 & x_2^2 & \cdots & x_2^{n-1} \\
\vdots & \vdots & \vdots & \ddots & \vdots \\
1 & x_{n-1} & x_{n-1}^2 & \cdots & x_{x-1}^{n-1}
\end{bmatrix}
\begin{bmatrix}
a_0 \\ a_1 \\ a_2 \\ \vdots \\ a_{n-1}
\end{bmatrix}
\]
更简洁的写法:
\[
\mathbf P_a = \mathbf X \mathbf \alpha
\]
对上式观察后发现,\(\mathbf X\) 是所谓的范德蒙德矩阵(Vandermonde's Matrix),在 \(n\) 个 \(x\) 的值不同的情况下,其行列式的值为:
\[
\det(\mathbf X) = \prod_{0\leqslant i\lt j \leqslant n-1} (x_j - x_i)
\]
很明显,当所有 \(n\) 个 \(x\) 取值不同时,其行列式不为零,因此 \(\mathbf X\) 可逆。
所以我们可以唯一确定多项式系数构成的向量 \(\alpha\):
\[
\mathbf \alpha = \mathbf X^{-1} \mathbf P_a
\]
也就是说,多项式 \(\mathrm P_a(x)\) 还可以由 \(n\) 个 \(x\) 代入得到的 \(n\) 个点值来唯一表示:
\[
\{ \left [x_0, \mathrm P(x_0) \right ], \left [ x_1, \mathrm P(x_1) \right ], \left [x_2, \mathrm P(x_2) \right ], \cdots,\left [ x_{n-1}, \mathrm P(x_{n-1}) \right ] \}
\]
这就是多项式的点值表示

多项式的点值表示是指,对于 \(n\) 次多项式,可以用 \(n\) 个不同的 \(x\) 和与之对应的多项式的值 \(\mathrm P(x)\) 构成一个长度为 \(n\) 的序列,这个序列唯一确定多项式,并且能够与系数表示相互转化。

\(n\) 次单位根

了解了多项式的点值表示,一个很自然的问题是:如何选择 \(x\) 的值,来防止其指数大小爆炸型增长呢?这里可以借用复数的单位根。
简单回顾一下,复数有两种表示方法:迪卡尔积坐标表示和极坐标表示,这里我们用到的是后者:
\[
z=re^{i\theta}
\]
\(i\) 是虚数单位,\(r\) 表示模长,\(\theta\) 表示相角。
复数的 \(n\) 次单位根 \(\omega\) 需要满足条件:
\[
\omega^n_n=1
\]
了解复数乘法及其几何意义的同学知道,复数相乘则相角1相加,相当于复数点逆时针转动;\(n\) 个复数相乘则说明有 \(n\) 个相角相加,\(n\) 次逆时针转动。因此:

\[
\omega_n^n = 1 = e^{i \cdot 2\pi}
\]

则 \(n\) 次单位根为:
\[
\sqrt[n] {\omega^n} = e^{i \cdot \frac{2\pi}{n}}
\]
很容易想到,\(n\) 等分 \(2\pi\) 相当于 \(n\) 等分圆。下图是 \(n=16\) 的例子:

引入了 \(n\) 次单位根,我们就可以找到任意 \(n\) 个不同的点值 \(x\),并且不用担心指数增长带来的大小爆炸性增长的问题。

离散傅里叶变换(Discrete Fourier Transform)及其反变换

DFT

设长度为 \(n\) 的离散序列 \(\alpha^{\mathrm T}=[a_0, a_1, \cdots,a_{n-1}]\),构建多项式:
\[
\mathrm P_a(x) = \sum_{i=0}^{n-1}a_ix^i
= \mathbf x \mathbf \alpha^{\mathrm T}
\]
其中,\(\mathbf x^{\mathrm T} = [1, x, x^2, \cdots, x^{n-1}]\)

用 \(n\) 次单位根生成 \(n\) 个不同的值:\(\omega_n^0,\ \omega_n^1,\ \omega_n^2,\ \cdots,\ \omega_n^{n-1}\)
对应的点值表示可以用下面的矩阵运算完成:
\[
\begin{bmatrix}
\mathrm P_a(\omega_n^0) \\
\mathrm P_a(\omega_n^1) \\
\mathrm P_a(\omega_n^2) \\
\vdots \\
\mathrm P_a(\omega_n^{n-1})
\end{bmatrix} =
\begin{bmatrix}
1 & 1 & 1 & \cdots & 1 \\
1 & \omega_n^1 & \omega_n^2 & \cdots & \omega_n^{n-1} \\
1 & \omega_n^2 & \omega_n^4 & \cdots & \omega_n^{2(n-1)} \\
\vdots & \vdots & \vdots & \ddots & \vdots \\
1 & \omega_n^{n-1} & \omega_n^{2(n-1)} & \cdots & \omega_n^{(n-1)(n-1)}
\end{bmatrix}
\begin{bmatrix}
a_0 \\ a_1 \\ a_2 \\ \vdots \\ a_{n-1}
\end{bmatrix}
\]
更简洁的写法:
\[
\mathbf P_a = \Omega \alpha
\]
序列 \(\mathbf P_a\) 被称为 \(\alpha\) 的离散傅里叶变换(DFT),也称为频域序列。
很明显,DFT 的计算时间复杂度是 \(O(n^2)\)

IDFT

离散傅里叶反变换,就是根据 DFT 得到的频域序列算出多项式的系数(也称时域序列)。这可以根据单位根矩阵 \(\Omega\) 的逆矩阵 \(\Omega^{-1}\) 得到
\[
\alpha = \Omega^{-1}\mathrm P_a
\]
一般来说,计算矩阵的逆的时间复杂度高达 \(O(n^3)\)。所幸,单位根矩阵的逆 \(\Omega^{-1}\) 有个优良的性质可以省去庞大的计算量:
\[
\begin{bmatrix}
1 & 1 & 1 & \cdots & 1 \\
1 & \omega_n^1 & \omega_n^2 & \cdots & \omega_n^{n-1} \\
1 & \omega_n^2 & \omega_n^4 & \cdots & \omega_n^{2(n-1)} \\
\vdots & \vdots & \vdots & \ddots & \vdots \\
1 & \omega_n^{n-1} & \omega_n^{2(n-1)} & \cdots & \omega_n^{(n-1)(n-1)}
\end{bmatrix}^{-1} = \frac 1 n
\begin{bmatrix}
1 & 1 & 1 & \cdots & 1 \\
1 & \omega_n^{-1} & \omega_n^{-2} & \cdots & \omega_n^{-(n-1)} \\
1 & \omega_n^{-2} & \omega_n^{-4} & \cdots & \omega_n^{-2(n-1)} \\
\vdots & \vdots & \vdots & \ddots & \vdots \\
1 & \omega_n^{-(n-1)} & \omega_n^{-2(n-1)} & \cdots & \omega_n^{-(n-1)(n-1)}
\end{bmatrix}
\]
也就是说,求 \(\Omega^{-1}\) 就是将里面元素的指数改成其相反数,再对所有元素除以 \(n\)。
有了这个性质,我们就可以得到:
\[
\begin{bmatrix}
a_0 \\
a_1 \\
a_2 \\
\vdots \\
a_{n-1}
\end{bmatrix}=\frac1 n
\begin{bmatrix}
1 & 1 & 1 & \cdots & 1 \\
1 & \omega_n^{-1} & \omega_n^{-2} & \cdots & \omega_n^{-(n-1)} \\
1 & \omega_n^{-2} & \omega_n^{-4} & \cdots & \omega_n^{-2(n-1)} \\
\vdots & \vdots & \vdots & \ddots & \vdots \\
1 & \omega_n^{-(n-1)} & \omega_n^{-2(n-1)} & \cdots & \omega_n^{-(n-1)(n-1)}
\end{bmatrix}
\begin{bmatrix}
\mathrm P_a(\omega_n^0) \\
\mathrm P_a(\omega_n^1) \\
\mathrm P_a(\omega_n^2) \\
\vdots \\
\mathrm P_a(\omega_n^{n-1})
\end{bmatrix}
\]
很明显,DFT 和 IDFT 的计算时间复杂度都是 \(O(n^2)\),效率并不高。

快速傅里叶变换(Fast Fourier Transform)及其反变换

FFT

FFT 是用分治法(Divide & Conquer)的思想,用来优化 DFT 计算矩阵相乘的时间复杂度过高这一问题的算法。
设 \(n\) 次多项式 \(\mathrm P(x)\)2

\[
\mathrm P(x)=a_0+a_1x+a_2x^2+a_3x^3+\cdots+a_{n-1}x^{n-1}
\]

我们把多项式 \(\mathrm P(x)\) 按照系数下标的奇偶性分成两部分
\[
\mathrm P_{e}(x^2) = a_0 + a_2x^2 + a_4\left(x^2\right)^2 + \cdots + a_{n-2}x^{n-2} \\
x\mathrm P_{o}(x^2) = x\left [a_1 + a_3x^2+a_5\left(x^2\right)^2+\cdots+a_{n-1}x^{n-2} \right ]
\]
则多项式 \(\mathrm P(x)\) 就是奇偶两部分之和
\[
\mathrm P(x)=\mathrm P_e(x^2)+x\mathrm P_o(x^2)
\]
从上式中可以看出,多项式 \(\mathrm P(x)\) 可以由两个系数个数为 \(n/2\) 的多项式 \(\mathrm P_{e}(x^2)\) 和 \(\mathrm P_o(x^2)\) 计算得到。
对于 \(\mathrm P_e(x^2)\) 和 \(\mathrm P_{o}(x^2)\),我们令 \(x=x^2\),就会发现这很明显是一个递归的过程:
\[
\mathrm P_{e}(x)=a_0+a_2x+a_4x^2+\cdots+a_{n-2}x^{\frac{n-2}{2}} \\
\mathrm P_{ee}(x^2)=a_0+a_4x^2+a_8x^4+\cdots+a_{n-4}x^{\frac{n-2}{2}-1} \\
x\mathrm P_{eo}(x^2)=x\left [ a_2+a_6x^2+a_{10}x^4+\cdots+a_{n-2}x^{\frac{n-2}{2}-1} \right ] \\
\]
就可以求出
\[
\mathrm P_e(x)=\mathrm P_{ee}(x^2)+xP_{eo}(x^2)
\]
同理
\[
\mathrm P_{o}(x)=a_1+a_3x+a_5x^2+\cdots+a_{n-1}x^{\frac{n-2}{2}} \\
\mathrm P_{oe}(x^2)=a_1+a_5x^2+a_9x^4+\cdots+a_{n-3}x^{\frac{n-2}{2}-1} \\
x\mathrm P_{oo}(x^2)=x\left [ a_3+a_7x^2+a_{11}x^4+\cdots+a_{n-1}x^{\frac{n-2}{2}-1} \right ]
\]
同样可以求出
\[
\mathrm P_o(x)=\mathrm P_{oe}(x^2)+xP_{oo}(x^2)
\]
递归的终止条件很明显,就是当遇到多项式中只有一个系数时返回该系数。
因此我们将 \(n\) 个单位根 \(\omega_n^0,\ \omega_n^1,\ \omega_n^2,\ \cdots,\ \omega_n^{n-1}\) 带入多项式 \(\mathrm P(x)\):
\[
\mathrm P(\omega_n^{k})=\mathrm P_e(\omega_n^{2k})+\omega_n^k\mathrm P_o(\omega_n^{2k}) \quad (k=0, 1, \cdots,n-1)
\]
刚刚提到,多项式 \(\mathrm P_{e}(x^2)\) 和 \(\mathrm P_o(x^2)\) 的系数个数为 \(n/2\) ,恰好 \(n\) 个单位根平方后也只剩下 \(n/2\) 个不同的单位根,简单证明如下:

首先证明:
\[
\left( \omega_n^k \right)^2=e^{i\frac{2\pi k}{n}\cdot2}=e^{i\frac{2\pi k}{n/2}}=\omega_{n/2}^k
\]
因此相当于 \(n\) 等分圆变成了 \(n/2\) 等分圆。下面证明 \(k=0,\ 1,\ \cdots,\ \frac n 2-1\):
设 \(k_1=m\), \(k_2=m+n/2\),\(m=0,1,\cdots,\frac{n}{2}-1\)。则
\[
\omega_{n/2}^{k_{1}} = \omega_{n/2}^{m}=e^{i\frac{2\pi m}{n/2}} \\
\omega_{n/2}^{k_2} = \omega_{n/2}^{m+n/2}=e^{i\frac{2\pi (m+n/2)}{n/2}}=e^{i\left(\frac{2\pi m}{n/2}+2\pi{}\right)}=e^{i\frac{2\pi m}{n/2}}
\]
即:
\[
\omega_{n/2}^{m}=\omega_{n/2}^{m+n/2}\quad (m=0,1,\cdots,\frac n 2-1)
\]
由此可以说明,\(\omega_n^k\) 是周期序列,其最小正周期为 \(n/2\)。因此 \(k=0, 1, \cdots, \frac n 2 -1\)

因此多项式 \(\mathrm P(\omega_n^{k})\) 可改写为
\[
\mathrm P(\omega_n^{k})=\mathrm P_e(\omega_{n/2}^{k})+\omega_n^k\mathrm P_o(\omega_{n/2}^{k}) \quad (k=0, 1, \cdots,\frac n 2-1)
\]
从上式中可以看出,计算 \(\mathrm P_e(\omega_{n/2}^{k})\) 和 \(\mathrm P_o(\omega_{n/2}^{k})\) 各需要 \(n/2\) 次乘法运算,即一共 \(n\) 次乘法运算;而计算\(\mathrm P_{ee}(\omega_{n/4}^{k})\) 、 \(\mathrm P_{eo}(\omega_{n/4}^{k})\) 、\(\mathrm P_{oe}(\omega_{n/4}^k)\) 和 \(\mathrm P_{oo}(\omega_{n/4}^k)\) 各需要 \(n/4\) 次乘法运算,即一共 \(n\) 次乘法运算……以此类推,这种每层递归规模减半的递归深度很明显是 \(\log n\),因此 FFT 算法的时间复杂度就是 \(O(n\log n)\)

IFFT

快速傅里叶变换反变换同样是优化 IDFT 计算矩阵相乘的时间复杂度。由于 DFT 和 IDFT 核心操作一样,都是矩阵相乘,因此 FFT 和 IDFT 的核心操作就是利用分治的思想减少矩阵相乘的运算量。可以想到,FFT 的过程可以直接移植到 IFFT 中来,需要修改的两个地方是

  1. 单位根指数部分改成其相反数:\(\omega_n^{-k}\)
  2. 得到的结果均除以 \(n\)

因此,IFFT 的时间复杂度也是\(O(n\log n)\)


Refer: COMP3121/9101, CSE UNSW
Written with StackEdit.


  1. 本文相角一律用弧度表示。

  2. 这里为了推导过程的整洁,假设 \(n\) 是 2 的整数次幂。这个假设的合理性在于:即使 \(n\) 不是 2 的整数次幂,我们也可以在多项是后面后面补零达到离 \(n\) 最近的下一个 2 的整数次幂。

FFT(快速傅里叶变换)算法详解的更多相关文章

  1. FFT快速傅里叶变换算法

    1.FFT算法概要: FFT(Fast Fourier Transformation)是离散傅氏变换(DFT)的快速算法.即为快速傅氏变换.它是根据离散傅氏变换的奇.偶.虚.实等特性,对离散傅立叶变换 ...

  2. [转] KMP算法详解

    转载自:http://www.matrix67.com/blog/archives/115 KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段.    我们这里说的K ...

  3. KMP算法详解(转自中学生OI写的。。ORZ!)

    KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法.KMP算法是拿来处理字符串匹配的.换句 ...

  4. CQOI2018 九连环 打表找规律 fft快速傅里叶变换

    题面: CQOI2018九连环 分析: 个人认为这道题没有什么价值,纯粹是为了考算法而考算法. 对于小数据我们可以直接爆搜打表,打表出来我们可以观察规律. f[1~10]: 1 2 5 10 21 4 ...

  5. KMP算法详解&&P3375 【模板】KMP字符串匹配题解

    KMP算法详解: KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt(雾)提出的. 对于字符串匹配问题(such as 问你在abababb中有多少个 ...

  6. BM算法  Boyer-Moore高质量实现代码详解与算法详解

    Boyer-Moore高质量实现代码详解与算法详解 鉴于我见到对算法本身分析非常透彻的文章以及实现的非常精巧的文章,所以就转载了,本文的贡献在于将两者结合起来,方便大家了解代码实现! 算法详解转自:h ...

  7. kmp算法详解

    转自:http://blog.csdn.net/ddupd/article/details/19899263 KMP算法详解 KMP算法简介: KMP算法是一种高效的字符串匹配算法,关于字符串匹配最简 ...

  8. 机器学习经典算法详解及Python实现--基于SMO的SVM分类器

    原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector  ...

  9. 【转】AC算法详解

    原文转自:http://blog.csdn.net/joylnwang/article/details/6793192 AC算法是Alfred V.Aho(<编译原理>(龙书)的作者),和 ...

  10. EM算法详解

    EM算法详解 1 极大似然估计 假设有如图1的X所示的抽取的n个学生某门课程的成绩,又知学生的成绩符合高斯分布f(x|μ,σ2),求学生的成绩最符合哪种高斯分布,即μ和σ2最优值是什么? 图1 学生成 ...

随机推荐

  1. 1875. [SDOI2009]HH去散步【矩阵乘法】

    Description HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但 是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又 ...

  2. 1059. [ZJOI2007]矩阵游戏【二分图】

    Description 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏——矩阵游戏.矩阵游戏在一个N *N黑白方阵进行(如同国际象棋一般,只是颜色是随意的).每次可以对该矩阵进行 ...

  3. JSONP - 从理论到实践

    同源策略 ajax之所以需要“跨域”,罪魁祸首就是浏览器的同源策略.即,一个页面的ajax只能获取这个页面相同源或者相同域的数据. 如何叫“同源”或者“同域”呢?——协议.域名.端口号都必须相同.例如 ...

  4. lightbox用法

    示例代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...

  5. Hadoop(16)-MapReduce框架原理-自定义FileInputFormat

    1. 需求 将多个小文件合并成一个SequenceFile文件(SequenceFile文件是Hadoop用来存储二进制形式的key-value对的文件格式),SequenceFile里面存储着多个文 ...

  6. 通过yum安装MySQL5.7.4

    1,进入yum的repo文件夹 cd /etc/yum.repos.d 2,mysql主页已经提供了centos等系统需要的rpm文件,直接去主页下载. 我用的centos6.5,选择Red Hat ...

  7. ARM汇编关键知识点总结(转)

    1.LDR R1, =COUNT 意思是将 COUNT 变量的地址放到 R1中LDR R1, COUNT 意思是将 COUNT 变量地址里面的内容赋给 R1 2. Load-Store 结构——这个应 ...

  8. flex学习园地

    http://blog.sina.com.cn/s/blog_6d0dc2a901013enk.html

  9. spring boot 资料

    http://412887952-qq-com.iteye.com/blog/2344171 http://study.163.com/course/courseMain.htm?courseId=1 ...

  10. PostgreSQL的索引膨胀

    磨砺技术珠矶,践行数据之道,追求卓越价值 回到上一级页面:PostgreSQL内部结构与源代码研究索引页    回到顶级页面:PostgreSQL索引页 索引膨胀,主要是针对B-tree而言. 索引膨 ...