(首先膜一发高中生qwq亏我学了信号处理原理专业课了竟然是看高中生的博客才能看懂qwq。。。大概断断续续看了几十篇吧。。。
序言
可能是许久以来写的最认真的一篇了吧,加上今天感觉不太舒服,但是觉得要开始扎实的学点什么,所以,就从现在开始吧。感谢所有认真写博客的人的帮助!!!希望我也能贡献点什么qwq。。。
一直想学FFT,之前牛客的多小有一道组合数学就用FFT写的,而且当时还傻乎乎的用唯一分解定理,但是自己好久没静下心学什么了,而且自己的数学功底又不好,导致一直学不会。看了很多人的博客也没看明白,尤其是原根。但是看了一个OIer的博客,顿时明白了。。。然后赶紧记录下来。
另外,本文的代码实现全部参考匡斌(kuangbin)的模板(2018.7更新)
前言
你搜索这个关键词就已经知道这一是个数学的东西了。只想学会用很简单,但是这远远不够。所以在看这个博客之前应该先学一下复数的基本知识。
好了下面进入正文。
1.DFT IDFT FFT官方定义?
离散傅里叶变换(Discrete Fourier Transform,缩写为DFT),是傅里叶变换在时域和频域上都呈离散的形式,将信号的时域采样变换为其DTFT的频域采样。
FFT是一种DFT的高效算法,称为快速傅立叶变换(fast Fourier transform)。
——百度百科
在百度百科上能找到DFT和FFT这两个定义。正如定义,FFT和DFT实际上按照结果来看的话是一样的,但是FFT比较快的计算DFT和IDFT(离散反傅里叶变换·)。
快速数论变换(NTT)是快速傅里叶变换(FFT)在数论基础上的实现。
是不是有点迷QAQ?既然是官方定义那肯定不能让你看懂才对嘛~下面我们一一解释~
2.为什么要使用FFT?
我们在这里引入一个例子:求多项式乘积的朴素算法。
大家平时求 与
的乘积时候,是怎么进行的呢?
我们令
那么很显然我们进行了9次运算,复杂度是.(具体代码实现不再展开)
但是如果数字足够大呢?比如100000?那朴素算法可太慢啦(;′⌒`),
3.学习FFT
3.1 在学习FFT之前...
3.1.1什么是FFT
FFT,即为快速傅氏变换,是离散傅氏变换的快速算法,它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。它对傅氏变换的理论并没有新的发现,但是对于在计算机系统或者说数字系统中应用离散傅立叶变换,可以说是进了一大步。——360百科
如果上一个例子用朴素算法太慢啦!所以我们要用FFT进行优化,复杂度会降为
3.1.2项式的系数表示法与点值表示法
一个多项式,我们可以怎样来表示呢?
系数表示法就是用一个多项式的各个项系数来表达这个多项式。比如:
点值表示法是把这个多项式看成一个函数,从上面选取n+1个点,从而利用这n+1个点来唯一的表示这个函数。为什么用(n+1)个点就能唯一的表示这个函数了呢?想一下高斯消元法,两点确定一条直线。再来一个点,能确定这个直线中的另一个参数,那么也就是说(n+1)个点能确定n个参数(不考虑倍数点之类的没用点)。如下:
多项式由系数表示法转为点值表示法的过程,就成为DFT;
相对地,把一个多项式的点值表示法转化为系数表示法的过程,就是IDFT。
而FFT就是通过取某些特殊的x的点值来加速DFT和FFT的过程。
3.1.3复数的引入
复数分为实数和虚数。实数就是我们日常最常用的有理数和无理数。大家记得我们在开始学平方的时候,老师会说所有数的平方大于等于0对不对,那么虚数就引入了。虚数一般用i表示,对于虚数i,有。另外,i对于虚数的意义,与1对于实数的意义是一样的。如果我说得不够明确,你可以看下面我引用的百科说明。
在数学中,虚数就是形如a+b*i的数,其中a,b是实数,且b≠0,i² = - 1。虚数这个名词是17世纪著名数学家笛卡尔创立,因为当时的观念认为这是真实不存在的数字。后来发现虚数a+b*i的实部a可对应平面上的横轴,虚部b与对应平面上的纵轴,这样虚数a+b*i可与平面内的点(a,b)对应。
可以将虚数bi添加到实数a以形成形式a + bi的复数,其中实数a和b分别被称为复数的实部和