快速傅里叶变换(FFT)和逆快速傅里叶变换(IFFT)

本文深入探讨了多项式的两种表示法——系数表示法和点值表示法,并详细解析了快速傅里叶变换(FFT)和逆FFT(IFFT)在转换表示法及优化卷积运算中的应用,展示了如何通过FFT降低时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多项式表示法与卷积

多项式有两种表示方法

  • 系数表示法
  • 点值表示法

系数表示法
就是最普通的表示方法,如
f(x)=a0x0+a1x1+a2x2+......+an−1xn−1 f(x) = a_0x^0 + a_1x^1 + a_2x^2 + ...... + a_{n-1}x^{n-1} f(x)=a0x0+a1x1+a2x2+......+an1xn1则表示为 f(x)={a0,a1,a2,......,an−1}f(x) = \{a_0, a_1, a_2, ......, a_{n-1}\}f(x)={a0,a1,a2,......,an1}


点值表示法
平面坐标系上的来描述多项式的一种表示方法
对于一个多项式来说有 n 项,则可以通过 n 对 {x,y}\{x, y\}{x,y} 点对来进行系数求解,即对于上述式子来说还有
f(x)={(x0,f(x0)),(x1,f(x1)),(x2,f(x2)),......,(xn−1,f(xn−1))} f(x) = \{(x_0, f(x_0)), (x_1, f(x_1)), (x_2, f(x_2)), ......, (x_{n-1}, f(x_{n-1}))\} f(x)={(x0,f(x0)),(x1,f(x1)),(x2,f(x2)),......,(xn1,f(xn1))}这种表达方式


卷积
就是多项式相乘,对于2种不同的多项式表示法来说,做卷积的时间复杂度会不同

  • 系数表示法,由于每2个系数之间都需要做一次处理,所以时间复杂度需要 O(n2)
  • 点值表示法,只要对应的两个点的 f(xi)f(x_i)f(xi) 相乘即可,所以时间复杂度只有 O(n)

但是将系数表示法转换成点值表示法,如果用朴素的转换方法,也需要 O(n2) 的时间复杂度,所以采取DFT通过分治法来做

 

离散傅里叶变换(DFT)

傅里叶变换中所有的 n 都为 2 的整数次幂
我们的目标是将系数表示法转换成点值表示法,如果随机选取 nnn 个点,再计算出它对应的 f(x)f(x)f(x),时间复杂度为 O(n2),因为对每个点都需要求 nnnxi,i∈[0,n−1]x^i, i∈[0, n - 1]xi,i[0,n1]

傅里叶选取了一些点,这些点满足它们的若干次方 = 1,这样可以使得带入之后不需要做这么多运算(但是时间复杂度仍是O(n2))

这些点都在复数平面直角坐标系里
在这里插入图片描述
圆上所有的点都满足傅里叶的要求
我们假设将其 n=8n = 8n=8 等分,则会得到:
在这里插入图片描述
(1,0)(1, 0)(1,0) 按照逆时针进行编号,对于编号为 k 的点,记为 wnkw_n^kwnk,称为 nnn 次单位根,且
wnk=cos⁡kn2π+isin⁡kn2π w_n^k = \cos{\frac{k}{n}2\pi} + i\sin{\frac{k}{n}2\pi} wnk=cosnk2π+isinnk2π


单位根的性质

  • wnk=w2n2kw_n^k = w_{2n}^{2k}wnk=w2n2k,2可以替换为任意整数
  • wnk+n2w_n^{k+\frac{n}{2}}wnk+2n = −wnk-w_n^kwnk
  • wn0=wnnw_n^0 = w_n^nwn0=wnn
  • 对任意 k∈[0,n]k∈[0, n]k[0,n],有 Σj=0n−1(wnk)j=0\Sigma_{j=0}^{n-1}(w_n^k)^j = 0Σj=0n1(wnk)j=0

        

快速傅里叶变换(FFT)


简介

虽然通过DFT选出了便于计算的点,但是时间复杂度仍为 O(n2),但是通过分析多项式可以得到用分治法处理这些点的方式。
假设有
A(x)=Σj=0n−1aixi=a0+a1x1+a2x2+......+an−1xn−1 A(x) = \Sigma_{j=0}^{n-1}a_ix^i = a_0 + a_1x^1 + a_2x^2 + ...... + a_{n-1}x^{n-1} A(x)=Σj=0n1aixi=a0+a1x1+a2x2+......+an1xn1现在将 A(x)A(x)A(x)xxx 的下标奇偶性将 A(x)A(x)A(x) 分成两部分
A(x)=(a0+a2x2+a4x4+......+an−2xn−2)+x(a1+a3x2+......+an−1xn−2) A(x) = (a_0 + a_2x^2 + a_4x^4 + ...... + a_{n-2}x^{n-2}) + x(a_1 + a_3x^2 + ...... + a_{n-1}x^{n-2}) A(x)=(a0+a2x2+a4x4+......+an2xn2)+x(a1+a3x2+......+an1xn2)所以有
A(x)=A1(x2)+xA2(x2) A(x) = A_1(x^2) + xA_2(x^2) A(x)=A1(x2)+xA2(x2)
k&lt;n2k &lt; \frac{n}{2}k<2n 的时候,将wnkw_n^kwnk 作为 xxx 带入 A(x)A(x)A(x)
A(wnk)=A1((wnk)2)+xA2((wnk)2)=A1(wn2k)+xA2(wn2k)=A1(wn2k)+wnkA2(wn2k) \begin {aligned} A(w_n^k) &amp;= A_1((w_n^k)^2) + xA_2((w_n^k)^2) \\ &amp;= A_1(w_n^{2k}) + xA_2(w_n^{2k}) \\ &amp;=A_1(w_{\frac{n}{2}}^k) + w_n^kA_2(w_{\frac{n}{2}}^k) \end {aligned} A(wnk)=A1((wnk)2)+xA2((wnk)2)=A1(wn2k)+xA2(wn2k)=A1(w2nk)+wnkA2(w2nk)
所以当取后半部分的时候,有x=wnk+n2x = w_n^{k+\frac{n}{2}}x=wnk+2n
A(wnk+n2)=A1((wnk+n2)2)+xA2((wnk+n2)2)=A1(wn2kwnn)+wnk+n2A2(wn2kwnn)=A1(wn2k)−wnkA2(wn2k)=A1(wn2k)−wnkA2(wn2k) \begin {aligned} A(w_n^{k+\frac{n}{2}}) &amp;= A_1((w_n^{k+\frac{n}{2}})^2) + xA_2((w_n^{k+\frac{n}{2}})^2) \\ &amp;= A_1(w_n^{2k}w_n^n) + w_n^{k+\frac{n}{2}}A_2(w_n^{2k}w_n^n) \\ &amp;= A_1(w_n^{2k}) - w_n^kA_2(w_n^{2k}) \\ &amp;=A_1(w_{\frac{n}{2}}^k) - w_n^kA_2(w_{\frac{n}{2}}^k) \end {aligned} A(wnk+2n)=A1((wnk+2n)2)+xA2((wnk+2n)2)=A1(wn2kwnn)+wnk+2nA2(wn2kwnn)=A1(wn2k)wnkA2(wn2k)=A1(w2nk)wnkA2(w2nk)
可以看到对于 k=n2k = \frac{n}{2}k=2n 的中介线来说,A(wnk)A(w_n^k)A(wnk)A(wnk+n2)A(w_n^{k+\frac{n}{2}})A(wnk+2n) 都可以通过 wn2kw_{\frac{n}{2}}^kw2nk 进行计算

这样时间复杂度就降为了 O(nlog2n)O(nlog_2n)O(nlog2n)
        


蝴蝶变换 Cooley-Turkey

刚提到对于当前层确定的位置 iii,可以通过下一层的两个值对当前值进行更新

开始肯定想着用递归的方式进行操作,但是有更为便捷的二进制反转方法

  • 以下 kkk 均为 aka_kak 中的 kkk
kkk01234567
二进制000001010011100101110111

一次变换之后,将偶数下标放在一起、奇数下标放在一起,重新变化成以下数列(前4个为一组,后4个为一组)

kkk02461357

二次变换之后,将两组的奇次项、偶次项再分开,变成以下数列(2、2、2、2分组)

kkk04261537

三次变换之后,已经变成单独的一个一个的了,再观察他们的二进制,和原始序列k作比较

原始 kkk01234567
二进制000001010011100101110111
kkk04261537
二进制000100010110001101011111

这样的对比可以很容易看出,对于原始序列和变换之后的序列来说,他们就是对二进制做了一个反转操作,即 1 (001) 变成了 4 (100)

那如果我们在最开始的时候,就将序列做了二进制反转操作,就可以从前往后依次顺序运算,而不需要使用递归的方式

以刚刚的序列为例子

反转后的 kkk04261537
计算内容A(w10)=a0w10A(w_1^0) = a_0w_1^0A(w10)=a0w10A(w14)A(w_1^4)A(w14)A(w12)A(w_1^2)A(w12)A(w16)A(w_1^6)A(w16)A(w11)A(w_1^1)A(w11)A(w15)A(w_1^5)A(w15)A(w13)A(w_1^3)A(w13)A(w17)=a7w17A(w_1^7) = a_7w_1^7A(w17)=a7w17

第一次合并

kkk04261537
计算内容A(w20)=A1(w10)+w20A2(w14)A(w_2^0) = A_1(w_1^0) + w_2^0A_2(w_1^4)A(w20)=A1(w10)+w20A2(w14)A(w24)=A1(w10)−w20A2(w14)A(w_2^4) = A_1(w_1^0) - w_2^0A_2(w_1^4)A(w24)=A1(w10)w20A2(w14)A(w22)A(w_2^2)A(w22)A(w26)A(w_2^6)A(w26)A(w21)A(w_2^1)A(w21)A(w25)A(w_2^5)A(w25)A(w23)A(w_2^3)A(w23)A(w27)A(w_2^7)A(w27)

这里的 A1(w10)A_1(w_1^0)A1(w10) 就对应了第一个表中的 A(w10)A(w_1^0)A(w10)
k=4k = 4k=4 的时候取值为 w20w_2^0w20 是因为在 k&gt;n2k &gt; \frac{n}{2}k>2n 的时候,xxx 取的是 wnk+n2w_n^{k + \frac{n}{2}}wnk+2n,所以 kkk 也要相应的减去 n2\frac{n}{2}2n

第二次合并

kkk02461357
计算内容A(w40)=A1(w20)+w40A2(w24)A(w_4^0) = A_1(w_2^0) + w_4^0A_2(w_2^4)A(w40)=A1(w20)+w40A2(w24)A(w42)=A1(w20)−w40A2(w24)A(w_4^2) = A_1(w_2^0) - w_4^0A_2(w_2^4)A(w42)=A1(w20)w40A2(w24)A(w44)A(w_4^4)A(w44)A(w46)A(w_4^6)A(w46)A(w41)A(w_4^1)A(w41)A(w43)A(w_4^3)A(w43)A(w45)A(w_4^5)A(w45)A(w47)A(w_4^7)A(w47)

这里的 A1(w20)A_1(w_2^0)A1(w20) 就对应了第二个表中的 A(w20)A(w_2^0)A(w20)

第三次合并

kkk01234567
计算内容A(w80)=A1(w40)+w80A2(w42)A(w_8^0) = A_1(w_4^0) + w_8^0A_2(w_4^2)A(w80)=A1(w40)+w80A2(w42)A(w81)=A1(w40)−w80A2(w42)A(w_8^1) = A_1(w_4^0) - w_8^0A_2(w_4^2)A(w81)=A1(w40)w80A2(w42)A(w82)A(w_8^2)A(w82)A(w83)A(w_8^3)A(w83)A(w84)A(w_8^4)A(w84)A(w85)A(w_8^5)A(w85)A(w86)A(w_8^6)A(w86)A(w87)A(w_8^7)A(w87)

所以在最后一次合并之后就得到了所有的 A(x)A(x)A(x)
成功的从系数表示法转换成点值表示法!
        

逆快速傅里叶变换(IFFT)

当然我们从系数表示法转换成点值表示法只是为了计算卷积的时候减小时间复杂度,但最后对我们有帮助、便于分析的仍然是系数表示法

所以在对点值表示法的多项式进行卷积之后,仍需要将其再次转换回系数表示法

这种转换方式称为逆快速傅里叶变换

那等于说我们给出了 nnn 个线性方程组,然后需要对其进行求解
a0(wn0)0+a1(wn0)1+......+an−1(wn0)n−1=A(wn0)a0(wn1)0+a1(wn1)1+......+an−1(wn1)n−1=A(wn1)......a0(wnn−1)0+a1(wnn−1)1+......+an−1(wnn−1)n−1=A(wnn−1) \begin{aligned} a_0(w_n^0)^0 + a_1(w_n^0)^1 + ...... + a_{n-1}(w_n^0)^{n-1} &amp;= A(w_n^0) \\ a_0(w_n^1)^0 + a_1(w_n^1)^1 + ...... + a_{n-1}(w_n^1)^{n-1} &amp;= A(w_n^1) \\ ......\\ a_0(w_n^{n-1})^0 + a_1(w_n^{n-1})^1 + ...... + a_{n-1}(w_n^{n-1})^{n-1} &amp;= A(w_n^{n-1}) \\ \end{aligned} a0(wn0)0+a1(wn0)1+......+an1(wn0)n1a0(wn1)0+a1(wn1)1+......+an1(wn1)n1......a0(wnn1)0+a1(wnn1)1+......+an1(wnn1)n1=A(wn0)=A(wn1)=A(wnn1)
将其写成矩阵的形式有
[(wn0)0(wn0)1...(wn0)n−1(wn1)0(wn1)1...(wn0)n−1......(wnn−1)0(wnn−1)1...(wnn−1)n−1][a0a1...an−1]=[A(wn0)A(wn1)...A(wnn−1)] \left[ \begin{matrix} (w_n^0)^0 &amp; (w_n^0)^1 &amp; ... &amp; (w_n^0)^{n-1} \\ (w_n^1)^0 &amp; (w_n^1)^1 &amp; ... &amp; (w_n^0)^{n-1} \\ ...... \\ (w_n^{n-1})^0 &amp; (w_n^{n-1})^1 &amp; ... &amp; (w_n^{n-1})^{n-1} \end{matrix} \right] \left[ \begin{matrix} a_0 &amp; \\ a_1 &amp; \\ ...\\ a_{n-1} &amp; \end{matrix} \right] = \left[ \begin{matrix} A(w_n^0) \\ A(w_n^1) \\ ...\\ A(w_n^{n-1}) \end{matrix} \right] (wn0)0(wn1)0......(wnn1)0(wn0)1(wn1)1(wnn1)1.........(wn0)n1(wn0)n1(wnn1)n1a0a1...an1=A(wn0)A(wn1)...A(wnn1)
定义第一个矩阵为D、第二个矩阵为V、第三个矩阵为E
按照矩阵乘法,有
eij=Σk=0n−1dikvkj=Σk=0n−1wn−ikwnkj=Σk=0n−1wnk(j−i) \begin{aligned} e_{ij} &amp; = \Sigma_{k=0}^{n-1}d_{ik}v_{kj} \\ &amp;= \Sigma_{k=0}^{n-1}w_n^{-ik}w_n^{kj} \\ &amp;=\Sigma_{k=0}^{n-1}w_n^{k(j-i)} \end{aligned} eij=Σk=0n1dikvkj=Σk=0n1wnikwnkj=Σk=0n1wnk(ji)
所以有
eij={ni=j0i≠j e_{ij} = \begin{cases} &amp; n &amp; &amp; i = j \\ &amp; 0 &amp; &amp; i ≠ j \\ \end{cases} eij={n0i=ji̸=j
i≠ji≠ji̸=j 的时候可以根据等比序列求和公式得到和为0

由此可知,In=1nEI_n = \frac{1}{n}EIn=n1EInI_nIn是一个 n×n 的单位矩阵

所以有 1nD=V−1\frac{1}{n}D = V^{-1}n1D=V1,∵ EEE 和单位矩阵扯上联系了嘛

那么其实IFFT就是一个变换了一点点的FFT
如果说FFT用公式来表示是
X(k)=Σn=0N−1x(n)wNkn X(k) = \Sigma_{n=0}^{N-1}x(n)w_N^{kn} X(k)=Σn=0N1x(n)wNkn则IFFT用公式来表示就是
x(n)=1NΣn=0N−1X(k)wn−kn x(n) = \frac{1}{N}\Sigma_{n=0}^{N-1}X(k)w_n^{-kn} x(n)=N1Σn=0N1X(k)wnkn
单位根取个负然后乘个 1N\frac{1}{N}N1

那总结一下FFT和IFFT的作用就是减少卷积运算的时间复杂度www
        

其他

  • 其实是为了学习NTT
  • 然而NTT还没看懂
  • 先总结出一份FFT和IFFT的来
  • NTT的尽快出吧QuQ
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值