快速傅里叶变换 | FFT 初学

FFT

前置

多项式:形如 A(x)=i=0n1aixi 的式子,其中 n 表示项数

多项式乘法:

C(x)=A(x)B(x)=i=02n2cixi

其中,ci=j=0iajbij

多项式表示法:

  • 系数表示法:将每一项的系数拿出来写在一起共同组成一个向量,如果缺项就补 0。一般书写的顺序与数组下标对应。

A(x)=(a0,a1,a2,,an1)

  • 点值表示法:任意的 n 次多项式都可以由二维平面内任意 n+1 个点唯一确定,因为一个方程可以解出一个系数。故 n 次多项式可以用一个包含 n+1 个二维平面内的点集来表示。

A(x)={(x0,y0),(x1,y1),(x2,y2),,(xn1,yn1)}

快速傅里叶变换

对两种表示法分别进行多项式乘法,不难发现,系数表示法的过程是基于乘法分配律的,O(n2) 的时间复杂度难以优化;而对于点值表示法来说,如果两个多项式分别是 n 次和 m 次的,那么最终的多项式是 n+m 次的,是需要 n+m+1 个点来确定的。那么只需要将两个多项式均用 n+m+1 个点表示,在两两相乘即可得到目标点值,时间复杂度 O(n)

但是,一般题目给定了多项式的系数表示,为了快速实现多项式乘法,我们需要快速实现多项式的系数表示转点值表示,这也就是FFT做的事情。

至此,我们大致了解了多项式乘法的基本过程。

  • 求值:将多项式 A(x),B(x) 通过FFT由系数表示转化成点值表示;
  • 点乘:然后将点值表示下的 A(x),B(x) 通过 O(n) 的点乘得到结果 C(x) 的点值表示;
  • 插值:将多项式 C(x) 通过FFT的逆操作还原出 C(x) 的系数表示。

那么,要如何实现求多项式的一个点值呢?这里我们采用霍纳法则将多项式展开。

A(x0)=a0+x0(a1+x0(a2+x0(a3++x0an1)))

那么我们可以在 O(n) 的时间内求出单次询问定点 x0A(x0)

单位根

定义:在复数域下,我们称满足 wn=1wn 次单位根,记为 wn

由代数基本定理可知,n 次单位根有 n 个。以实轴为横轴,虚轴为纵轴建系,以原点为圆心作单位圆,那么这 n 个 单位复数根均匀分布在以复平面的原点为圆心的单位半径的圆周上,分别为 e2πikn,其中 k=0n1

eix=cos(x)+isin(x),借助图像可以更好地理解。

下面给出有关单位根的几则引理。

  • 消去引理:若 n,k0,d>0,则有 wdndk=wnk

    证明:

    wdndk=(e2πidn)dk=(e2πin)k=wnk

    推论:wnn2=w2=1
  • 折半引理:若 n 是大于 0 的偶数,则 nn 次单位复数根的平方的集合就是 n2 次单位复数根的集合,共 n2。通俗点说,n 次单位复数根的前后两半平方后是对应相等的。

    证明:

    (wnn2+k)2=wnn+2k=wnnwn2k=(wnk)2

    推论:wnn2+k=wnk
  • 求和引理:对于 n1 和满足 kn 的非负整数 k,有

    j=0n1(wnk)j=0

下面讲讲如何在 O(nlogn) 的时间内实现求值。

我们将 nn 次单位复数根代入前面展开后的多项式求点值。对于 k[0,n),和 n1 次的多项式 A(x),定义

yk=A(wnk)=i=0n1ai(wnk)i

而对于一个多项式 A(x),我们把奇数下标和偶数下标分别独立出来,定义成 2 个子多项式。

{A[0](x)=a0+a2x+a4x2++an2xn21A[1](x)=a1+a3x+a5x2++an1xn21

这样,将 A(x) 可以表示成 A[0](x2)+xA[1](x2)

这显然是可以分治递归求解的,每次次数界折半,时间复杂度 O(nlogn)

插值的话,就是反过来做,推到一下式子可得:

ak=1ni=0n1yi(wnk)i

发现求系数的过程与前面求点值的过程类似,也可以在 O(nlogn) 的时间内求解。

优化

  • 蝶形变换

    n=8,那么不难发现递归时 a 长这样。

    [01234567]

    [0246] [1357]

    [04] [26] [15] [37]

    [0] [4] [2] [6] [1] [5] [3] [7]

    记最后的数组为 a,则有 ai=arev(i),故一开始时可以交换 aiarev(i) 以减少常数。

  • 三次变两次

    发现整个过程先要求两个多项式 A(x),B(x) 的点值,点乘后又要还原出系数,总共进行了 3 次FFT。

    B(x) 放到 A(x) 的虚部上,求出 A(x)2,然后把它的虚部 ×12 即为答案。

    证明:

    (a+bi)2=(a2b2)+(2abi)


posted @   ereoth  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示