0
点赞
收藏
分享

微信扫一扫

【算法学习笔记】快速傅里叶变换2

alanwhy 2022-05-03 阅读 37
算法学习

文章目录


3. DFT与FFT

(算导30.1节中断言)如果使用单位复数根,可以在 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn) 时间内完成求值与插值运算。在本节中给出单位复数根的定义,研究其性质,以及定义DFT,然后说明FFT如何仅用 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn) 时间、就可以计算出DFT和它的逆。

3.1 单位复数根

n n n 次单位复数根 complex nth root of unity 是满足 ω n = 1 \omega^n = 1 ωn=1 的复数 ω \omega ω(类比平方根、立方根,且是单位根、复数)。 n n n 次单位复数根恰好有 n n n 个:对于 k = 0 , 1 , … , n − 1 k = 0, 1, \dots, n-1 k=0,1,,n1 这些根是 e 2 π i k / n   ( i = − 1 ) e^{2\pi ik / n}\ (i = \sqrt{-1}) e2πik/n (i=1 ) 。为了(理解)解释这个表达式,我们利用复数指数的定义 the definition of the exponential of a complex number e i u = cos ⁡ ( u ) + i sin ⁡ ( u ) e^{iu} = \cos(u) + i\sin (u) eiu=cos(u)+isin(u) 图30-2说明, n n n 个单位复数根均匀地分布在「以复平面的原点为圆心的、单位半径的圆周」上。值 ω n = e 2 π i / n (30.6) \omega_n = e^{2\pi i / n} \tag{30.6} ωn=e2πi/n(30.6) 称为 n n n 次单位根 the principal nth root of unity ,其余的 n n n 次单位复数根都是 ω n = ω n 1 \omega_n = \omega_n^1 ωn=ωn1 的幂次,即 ( ω n 1 ) k = ω n k (\omega_n^1)^k =\omega_n^k (ωn1)k=ωnk 。注意,有时别人对 ω n \omega_n ωn 有不同的定义: ω n = e − 2 π i / n \omega_n = e^{ -2\pi i /n} ωn=e2πi/n ,这个可替的定义一般用在信号处理应用中,这两个 ω n \omega_n ωn 的定义、其背后的数学含义基本上是相同的。
在这里插入图片描述例如(红字为主 n n n 次单位根), ω 8 0 = e 2 π × 0 8 i = cos ⁡ ( 0 ) + i sin ⁡ ( 0 ) 复 平 面 ( 1 , 0 ) ω 8 1 = e 2 π × 1 8 i = cos ⁡ ( π 4 ) + i sin ⁡ ( π 4 ) 复 平 面 ( 2 2 , 2 2 ) ω 8 2 = e 2 π × 2 8 i = cos ⁡ ( π 2 ) + i sin ⁡ ( π 2 ) 复 平 面 ( 0 , 1 ) ω 8 3 = e 2 π × 3 8 i = cos ⁡ ( 3 π 4 ) + i sin ⁡ ( 3 π 4 ) 复 平 面 ( − 2 2 , 2 2 ) ω 8 4 = e 2 π × 4 8 i = cos ⁡ ( π ) + i sin ⁡ ( π ) 复 平 面 ( − 1 , 0 ) ω 8 5 = e 2 π × 5 8 i = cos ⁡ ( 5 π 4 ) + i sin ⁡ ( 5 π 4 ) 复 平 面 ( − 2 2 , − 2 2 ) ω 8 6 = e 2 π × 6 8 i = cos ⁡ ( 3 π 2 ) + i sin ⁡ ( 3 π 2 ) 复 平 面 ( 0 , − 1 ) ω 8 7 = e 2 π × 7 8 i = cos ⁡ ( 7 π 4 ) + i sin ⁡ ( 7 π 4 ) 复 平 面 ( 2 2 , − 2 2 ) ω 8 8 = e 2 π × 8 8 i = cos ⁡ ( 2 π ) + i sin ⁡ ( 2 π ) 复 平 面 ( 1 , 0 ) \begin{aligned} &\omega^0_8 = e^{\frac{ 2 \pi \times 0 } { 8} i} = \cos (0)+i \sin(0) \quad& 复平面(1, 0) \\ &\textcolor{red} {\omega^1_8 = e^{\frac{ 2 \pi \times 1 } { 8} i}} = \cos (\frac{\pi}{4})+i \sin( \frac{\pi}{4} ) \quad& 复平面(\dfrac{\sqrt{2} }{ 2}, \dfrac{\sqrt{2} }{ 2} )\\ &\omega^2_8 = e^{\frac{ 2 \pi \times 2 } { 8} i} = \cos (\dfrac{\pi}{2} )+i \sin(\dfrac{\pi}{2} ) \quad& 复平面(0, 1) \\ &\omega^3_8 = e^{\frac{ 2 \pi \times 3 } { 8} i} = \cos ( \dfrac{3\pi}{4} )+i \sin( \dfrac{3\pi}{4} ) \quad& 复平面( -\dfrac{ \sqrt{2} }{2}, \dfrac{\sqrt{2} }{2} ) \\ &\omega^4_8 = e^{\frac{ 2 \pi \times 4 } { 8} i} = \cos ( \pi )+i \sin(\pi ) \quad& 复平面(-1, 0) \\ &\omega^5_8 = e^{\frac{ 2 \pi \times 5 } { 8} i} = \cos ( \dfrac{5\pi}{4} )+i \sin(\dfrac{5\pi}{4} ) \quad& 复平面(-\dfrac{ \sqrt{2} }{2}, -\dfrac{\sqrt{2} }{2}) \\ &\omega^6_8 = e^{\frac{ 2 \pi \times 6 } { 8} i} = \cos (\dfrac{3\pi}{2} )+i \sin( \dfrac{3\pi}{2} ) \quad& 复平面(0, -1) \\ &\omega^7_8 = e^{\frac{ 2 \pi \times 7 } { 8} i} = \cos (\dfrac{7\pi}{4} )+i \sin( \dfrac{7\pi}{4} ) \quad& 复平面(\dfrac{ \sqrt{2} }{2}, -\dfrac{\sqrt{2} }{2}) \\ &\omega^8_8 = e^{\frac{ 2 \pi \times 8 } { 8} i} = \cos (2\pi )+i \sin(2\pi ) \quad& 复平面(1, 0) \\ \end{aligned} ω80=e82π×0i=cos(0)+isin(0)ω81=e82π×1i=cos(4π)+isin(4π)ω82=e82π×2i=cos(2π)+isin(2π)ω83=e82π×3i=cos(43π)+isin(43π)ω84=e82π×4i=cos(π)+isin(π)ω85=e82π×5i=cos(45π)+isin(45π)ω86=e82π×6i=cos(23π)+isin(23π)ω87=e82π×7i=cos(47π)+isin(47π)ω88=e82π×8i=cos(2π)+isin(2π)(1,0)(22 ,22 )(0,1)(22 ,22 )(1,0)(22 ,22 )(0,1)(22 ,22 )(1,0)

n n n n n n 次单位复数根 ω n 0 , ω n 1 , … , ω n n − 1 \omega_n^0, \omega_n^1, \dots, \omega_n^{n-1} ωn0,ωn1,,ωnn1 在乘法意义下形成一个群(见算导31.3节)。该群与加法群 ( Z n , + ) (\Z_n, +) (Zn,+) 具有相同的结构,因为 ω n n = ω n 0 = 1 \omega^n_n = \omega^0_n = 1 ωnn=ωn0=1 意味着 ω n j ω n k = ω n ( j + k )   m o d   n \omega^j_n \omega^k_n = \omega_n^{{(j+k)} \bmod n} ωnjωnk=ωn(j+k)modn 。类似地, ω n − 1 = ω n n − 1 \omega_n^{-1} = \omega_n^{n-1} ωn1=ωnn1 。下面的引理给出了 n n n 次单位复数根的一些基本性质。

引理30.3消去引理 Cancellation lemma )对任何整数 n ≥ 0 , k ≥ 0 n \ge 0, k \ge 0 n0,k0 ,以及 d > 0 d > 0 d>0 n n n 不应该 > 0 >0 >0 吗?), ω d n d k = ω n k (30.7) \omega_{dn}^{dk} = \omega_{n}^k \tag{30.7} ωdndk=ωnk(30.7) 证明:由式30.6可以直接推出引理,因为: ω d n d k = ( e 2 π i d n ) d k = ( e 2 π i n ) k = ω n k ■ \omega_{dn}^{dk} = (e^{ \frac{2\pi i} {dn } } )^{dk } = (e^{\frac{2\pi i }{n}})^k = \omega_n^k \tag*{■} ωdndk=(edn2πi)dk=(en2πi)k=ωnk
推论30.4 对任意偶数 n > 0 n > 0 n>0 ,有 ω n n / 2 = ω 2 = − 1 \omega_n^{n/2} = \omega_2 = -1 ωnn/2=ω2=1 证明:证明见算导练习30.2-1。本人的证明如下:由于 n n n 为大于零的偶数,所以 n / 2 × 2 n/ 2\times 2 n/2×2 仍等于 n n n ,于是根据引理30.3有: ω n n / 2 = ω 2 n n = ( e 2 π i 2 n ) n = e 2 π i 2 = ω 2 \omega_n^{n/2} = \omega_{2n}^n =(e^{ \frac{2\pi i }{2n}} )^n = e^{\frac{2\pi i}{2}} = \omega_2 ωnn/2=ω2nn=(e2n2πi)n=e22πi=ω2 又可知: ω 2 = e 2 π i 2 = cos ⁡ ( π ) + i sin ⁡ ( π ) = − 1 \omega_2 = e^{\frac{2\pi i}{2}} = \cos(\pi) + i \sin (\pi)=-1 ω2=e22πi=cos(π)+isin(π)=1 所以推论30.4可证。 ■ \blacksquare

引理30.5折半引理 Halving lemma )如果 n > 0 n>0 n>0 为偶数,那么 n n n n n n 次单位复数根的平方的集合,就是 n / 2 n/2 n/2 n / 2 n/2 n/2 次单位复数根的集合 If n > 0 is even, then the squares of the n complex nth roots of unity are the n/2 complex (n/2)/th roots of unity
证明:根据消去引理,对任意非负整数 k k k ,我们有 ( ω n k ) 2 = ω n 2 k = ω n / 2 k (\omega_n^k)^2 =\omega_n^{2k}= \omega_{n/2}^k (ωnk)2=ωn2k=ωn/2k(即对一个 n n n 次单位复数根平方后得到一个 n / 2 n/2 n/2 次单位复数根)。注意,如果对所有 n n n 次单位复数根进行平方,那么获得每个 n / 2 n/2 n/2 次单位根正好 2 2 2 次,因为: ( ω n k + n / 2 ) 2 = ω n 2 k + n = ω n 2 k ω n n = ω n 2 k = ( ω n k ) 2 (\omega_n^{k +n / 2})^2 = \omega_n^{2k+n} = \omega_n^{2k}\omega^n_n = \omega_n^{2k} = (\omega_n^k)^2 (ωnk+n/2)2=ωn2k+n=ωn2kωnn=ωn2k=(ωnk)2 因此可知, ω n k \omega^k_n ωnk ω n k + n / 2 \omega^{k+n/2}_n ωnk+n/2 平方相同。

我们也可以由推论30.4来证明该性质,因为 ω n n / 2 = − 1 \omega_n^{n/2} = -1 ωnn/2=1 意味着 ω n k + n / 2 = − ω n k \omega_n^{k+n/2} = - \omega^k_n ωnk+n/2=ωnk ,从而 ( ω n k + n / 2 ) 2 = ( ω n k ) 2 (\omega^{k+n/2}_n)^2 = (\omega_n^k)^2 (ωnk+n/2)2=(ωnk)2 ■ \blacksquare

我们将会看到,对于用分治策略来对「多项式的系数与点值表达」进行相互转换,折半引理是非常重要的,因为它保证递归子问题的规模只是递归调用前的一半。

引理30.6求和引理 Summation lemma )对任意整数 n ≥ 1 n\ge 1 n1 和不能被 n n n 整除的非负整数 k k k ,有 ∑ j = 0 n − 1 ( ω n k ) j = 0 \sum^{n-1}_{j = 0} (\omega^k_n)^j = 0 j=0n1(ωnk)j=0 证明:对于实数 x ≠ 1 x \ne 1 x=1 ,和式: ∑ k = 0 n x k = 1 + x + x 2 + ⋯ + x n = x n + 1 − 1 x − 1 \sum^n_{k=0} x^k = 1 + x +x^2 +\dots + x^n = \dfrac{x^{n+1}- 1}{x - 1} k=0nxk=1+x+x2++xn=x1xn+11 这是几何级数/等比级数/指数级数求和公式(算导A.5),既适用于实数,也适用于复数。因此有:
∑ j = 0 n − 1 ( ω n k ) j = ( ω n k ) n − 1 ω n k − 1 = ( ω n n ) k − 1 ω n k − 1 = ( 1 ) k − 1 ω n k − 1 = 0 \sum^{n-1}_{j = 0} (\omega^k_n)^j =\dfrac{ (\omega^k_n)^n - 1}{ \omega^k_n - 1} = \dfrac{ (\omega^n_n)^k - 1} { \omega_n^k - 1} = \dfrac{ (1)^k- 1} { \omega^k_n - 1} = 0 j=0n1(ωnk)j=ωnk1(ωnk)n1=ωnk1(ωnn)k1=ωnk1(1)k1=0 因为要求 k k k 不能被 n n n 整除、而仅当 k k k n n n 整除时 ω n k = 1 \omega^k_n=1 ωnk=1 成立,我们确保分母不为 0 0 0 ■ \blacksquare

3.2 DFT

回顾一下,我们希望计算次数界为 n n n 的多项式 A ( x ) = ∑ j = 0 n − 1 a j x j A(x) = \sum^{n-1}_{j=0} a_jx^j A(x)=j=0n1ajxj ω n 0 , ω n 1 , ω n 2 , … , ω n n − 1 \omega^0_n, \omega^1_n, \omega^2_n, \dots, \omega^{n-1}_n ωn0,ωn1,ωn2,,ωnn1 处的值(即在 n n n n n n 次复数根处)。假设 A A A 以系数形式给出,即 a = ( a 0 , a 1 , … , a n − 1 ) a = (a_0, a_1, \dots, a_{n-1}) a=(a0,a1,,an1) 。接下来对 k = 0 , 1 , … , n − 1 k = 0, 1, \dots, n - 1 k=0,1,,n1 ,定义结果 y k y_k yk y k = A ( ω n k ) = ∑ j = 0 n − 1 a j ω n k j (30.8) y_k = A(\omega^k_n) = \sum^{n-1}_{j=0} a_j \omega^{kj}_n \tag{30.8} yk=A(ωnk)=j=0n1ajωnkj(30.8) 向量 y = ( y 0 , y 1 , … , y n − 1 ) y = (y_0, y_1, \dots, y_{n-1}) y=(y0,y1,,yn1) 就是系数向量 a = ( a 0 , a 1 , … , a n − 1 ) a=(a_0, a_1, \dots, a_{n-1}) a=(a0,a1,,an1)离散傅里叶变换 DFT 。我们也记为 y = D F T n ( a ) y = \mathrm{DFT_n}(a) y=DFTn(a)

3.3 FFT

通过使用一种称为快速傅里叶变换 FFT 的方法,利用复数单位根的特殊性质,我们就能在 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn) 时间内计算出 D F T n ( a ) \mathrm{DFT_n}(a) DFTn(a)(即完成系数表达到点值表达的转换),而直接的方法所需时间为 Θ ( n 2 ) \Theta(n^2) Θ(n2) 。这里全篇假设 n n n 恰好是 2 2 2 的整数幂,虽然处理非 2 2 2 整数幂的策略已经存在,但算导正文没有提。

FFT利用了分治策略,采用 A ( x ) A(x) A(x) 中偶数下标的系数与奇数下标的系数,分别定义两个新的、次数界为 n / 2 n/2 n/2 的多项式 A [ 0 ] ( x ) A^{ [0] }(x) A[0](x) A [ 1 ] ( x ) A^{ [1]} (x) A[1](x) A [ 0 ] ( x ) = a 0 + a 2 x + a 4 x 2 + ⋯ + a n − 2 x n / 2 − 1 A [ 1 ] ( x ) = a 1 + a 3 x + a 5 x 2 + ⋯ + a n − 1 x n / 2 − 1 \begin{aligned} &A^{[0]} (x) = a_0 + a_2 x + a_4 x^2 + \dots + a_{n-2} x^{{n/2} - 1} \\ &A^{ [1]}(x) = a_1 + a_3 x + a_5 x^2 + \dots + a_{n-1} x^{n/2- 1}\end{aligned} A[0](x)=a0+a2x+a4x2++an2xn/21A[1](x)=a1+a3x+a5x2++an1xn/21 注意到, A [ 0 ] ( x ) A^{ [0] } (x) A[0](x) 包含 A A A 中所有偶数下标的系数(下标的相应二进制表示的最后一位为 0 0 0 ), A [ 1 ] ( x ) A^{ [1] }(x) A[1](x) 包含 A A A 中所有奇数下标的系数(下标的相应二进制表示的最后一位为 1 1 1 )。于是有: A ( x ) = A [ 0 ] ( x 2 ) + x A [ 1 ] ( x 2 ) (30.9) A(x) = A^{ [0] } (x^2) + x A^{ [1] } (x^2) \tag{30.9} A(x)=A[0](x2)+xA[1](x2)(30.9)

所以,求 A ( x ) A(x) A(x) ω n 0 , ω n 1 , … , ω n n − 1 \omega^0_n, \omega^1_n, \dots, \omega^{n-1}_n ωn0,ωn1,,ωnn1 处的值的问题,转换为:

  1. 求次数界为 n / 2 n/2 n/2 的多项式 A [ 0 ] ( x ) A^{[0]}(x) A[0](x) A [ 1 ] ( x ) A^{ [1] }(x) A[1](x) 在点: ( ω n 0 ) 2 , ( ω n 1 ) 2 , … , ( ω n n − 1 ) 2 (30.10) (\omega^0_n)^2, (\omega^1_n)^2, \dots, (\omega^{n-1}_n)^2 \tag{30.10} (ωn0)2,(ωn1)2,,(ωnn1)2(30.10) 的取值。
  2. 根据式30.9综合上述结果。

根据折半引理(作用就在这里!),式30.10并不是由 n n n 个不同值组成,而是仅由 n / 2 n/2 n/2 n / 2 n/2 n/2 次单位复数根组成,每个根正好出现 2 2 2 次( n n n 2 2 2 的整数幂,也是偶数)。因此,我们递归地对次数界为 n / 2 n/2 n/2 的多项式 A [ 0 ] ( x ) A^{[0]}(x) A[0](x) A [ 1 ] ( x ) A^{[1]} (x) A[1](x) 、在 n / 2 n/2 n/2 n / 2 n/2 n/2 次单位复数根处进行求值。这些子问题与原始问题形式相同、但规模变为一半

现在,我们已经成功地把一个 n n n 个元素的 D F T n \mathrm{DFT_n} DFTn 计算,划分为两个规模为 n / 2 n/2 n/2 个元素的 D F T n / 2 \mathrm{ DFT_{n/2}} DFTn/2 计算。这一分解是下面递归FFT算法的基础,该算法计算出一个 n n n 元素向量 a = ( a 0 , a 1 , … , a n − 1 ) a = (a_0, a_1, \dots, a_{n-1}) a=(a0,a1,,an1) 的DFT(其中 n n n 2 2 2 的幂)。 注意,这里的长度 n n n 实际上是(算导30.1节)前面所指的 2 n 2n 2n ,因为我们需要在求值以前、加倍给定多项式的次数界,因此在多项式乘法的相关内容中,实际上处理的是 2 n 2n 2n 次单位根
在这里插入图片描述

RECURSIVE-FFT(a)
	n = a.length // n is a power of 2
	if n == 1
		return a
	wn = e^(2πi/n)
	w = 1
	A0 = (a[0], a[2], ..., a[n-2]) // a中偶数下标的系数组成的多项式
	A1 = (a[1], a[3], ..., a[n-1]) // a中奇数下标的系数组成的多项式
	y0 = RECURSIVE-FFT(A0) // 递归FFT处理A0后得到的点值表达(偶数下标系数)
	y1 = RECURSIVE-FFT(A1) // 递归FFT处理A1后得到的点值表达(奇数下标系数)
	for k = 0 to (n/2-1)
		y[k] = y0[k] + w * y1[k]
		y[k + (n/2)] = y0[k] - w * y1[k]
		w = w * wn
	return y // y is assumed to be a column vector

RECURSIVE-FFT 的执行过程如下。前三行代表递归的基础:一个元素的DFT就是该元素自身,因为在这种情形下: y 0 = a 0 ω 1 0 = a 0 ⋅ 1 = a 0 y_0 = a_0 \omega_1^0 = a_0 \cdot 1 = a_0 y0=a0ω10=a01=a0 定义 Y0, Y1 的两行,定义了多项式 A [ 0 ] ( x ) A^{[0]} (x) A[0](x) A [ 1 ] ( x ) A^{[1]} (x) A[1](x) 的系数向量。定义 wn, w 的两行和 w = w * wn 这一行,则保证了 ω \omega ω 可以正确更新,只要 y[k], y[k + (n/2)] 这两行被执行,就有 ω = ω n k \omega = \omega_n^k ω=ωnk(次次迭代中让 ω \omega ω 的值改变,可以节约每次通过for循环重新计算 ω n k \omega^k_n ωnk 的时间)。递归调用 RECURSIVE-FFT 的两行,执行递归计算 D F T n / 2 \mathrm{DFT_{n/2}} DFTn/2 ,对于 k = 0 , 1 , … , n / 2 − 1 k = 0, 1, \dots, n / 2-1 k=0,1,,n/21 y k [ 0 ] = A [ 0 ] ( ω n / 2 k ) y k [ 1 ] = A [ 1 ] ( ω n / 2 k ) \begin{aligned} &y_k^{ [0] } = A^{[0]} (\omega^k_{n/2}) \\ &y_k^{ [1]} = A^{ [1] } ( \omega_{n/2}^k ) \end{aligned} yk[0]=A[0](ωn/2k)yk[1]=A[1](ωn/2k) 或者根据消去引理,有 ω n / 2 k = ω n 2 k = ( ω n k ) 2 \omega^k_{n/2} = \omega^{2k}_n = (\omega^{k}_n)^2 ωn/2k=ωn2k=(ωnk)2 ,于是 y k [ 0 ] = A [ 0 ] ( ω n 2 k ) y k [ 1 ] = A [ 1 ] ( ω n 2 k ) \begin{aligned} &y_k^{ [0] } = A^{[0]} (\omega^{2k}_{n}) \\ &y_k^{ [1]} = A^{ [1] } ( \omega_{n}^{2k} ) \end{aligned} yk[0]=A[0](ωn2k)yk[1]=A[1](ωn2k) 更新 y[k], y[k + (n/2)] 的两行则综合了递归 D F T n / 2 \mathrm{DFT_{n/2}} DFTn/2 的计算结果。对 y 0 , y 1 , … , y n / 2 − 1 y_0, y_1, \dots, y_{n/2-1} y0,y1,,yn/21 ,前一行推出: y k = y k [ 0 ] + ω n k y k [ 1 ] = A [ 0 ] ( ω n 2 k ) + ω n k A [ 1 ] ( ω n 2 k ) = A ( ω n k ) ( 根 据 式 30.9 ) \begin{aligned} y_k &= y^{[0]}_k + \omega^k_n y_k^{[1]} \\ &= A^{[0]} (\omega^{2k}_n) + \omega^k_n A^{[1]} (\omega^{2k}_n) \\ &= A(\omega_n^k) \quad &(根据式30.9) \end{aligned} yk=yk[0]+ωnkyk[1]=A[0](ωn2k)+ωnkA[1](ωn2k)=A(ωnk)(30.9) y n / 2 , y n / 2 + 1 , … , y n − 1 y_{n/2}, y_{n/2+1}, \dots, y_{n-1} yn/2,yn/2+1,,yn1 ,设 k = 0 , 1 , … , n / 2 − 1 k = 0, 1, \dots, n/2-1 k=0,1,,n/21 ,后一行推出:
y k + ( n / 2 ) = y k [ 0 ] − ω n k y k [ 1 ] = y k [ 0 ] + ω k k + ( n / 2 ) y k [ 1 ] ( 因 为 ω n k + ( n / 2 ) = − ω n k ) = A [ 0 ] ( ω n 2 k ) + ω n k + ( n / 2 ) A [ 1 ] ( ω n 2 k ) = A [ 0 ] ( ω n 2 k + n ) + ω n k + ( n / 2 ) A [ 1 ] ( ω n 2 k + n ) ( 因 为 ω n 2 k + n = ω n 2 k ) = A ( ω n k + ( n / 2 ) ) ( 根 据 式 30.9 ) \begin{aligned} y_{k+(n/2)} &= y_k^{[0]} - \omega^k_n y_k^{[1]} \\ &= y_k^{[0]} + \omega_k^{k + (n/2)} y_k^{[1]} \quad &(因为 \omega^{k+(n/2)}_n = - \omega^k_n) \\ &= A^{[0]} ( \omega^{2k}_n) + \omega^{k+(n/2)}_n A^{[1]} (\omega^{2k}_{n}) \\ &= A^{[0]} (\omega^{2k+n}_n) + \omega^{k+(n/2)}_n A^{[1]} (\omega^{2k+n}_n) \quad &(因为\omega^{2k+n}_n = \omega^{2k}_n) \\ &= A(\omega^{k+(n/2)}_n) \quad &(根据式30.9) \end{aligned} yk+(n/2)=yk[0]ωnkyk[1]=yk[0]+ωkk+(n/2)yk[1]=A[0](ωn2k)+ωnk+(n/2)A[1](ωn2k)=A[0](ωn2k+n)+ωnk+(n/2)A[1](ωn2k+n)=A(ωnk+(n/2))(ωnk+(n/2)=ωnk)(ωn2k+n=ωn2k)(30.9) 因此,由 RECURSIVE-FFT 返回的向量 y 确实是输入向量 a 的DFT。

更新 y[k], y[k + (n/2)] 的两行中,对 k = 0 , 1 , … , n / 2 − 1 k = 0, 1, \dots, n / 2 - 1 k=0,1,,n/21 ,每个值 y k [ 1 ] y_k^{[1]} yk[1] 都乘了 ω n k \omega^k_n ωnk 。前一行中这个乘积加到了 y k [ 0 ] y_k^{[0]} yk[0] 上,后一行又减去它。因为应用了每个因子 ω n k \omega^k_n ωnk 的正数形式和负数形式,我们把因子 ω n k \omega^k_n ωnk 称为旋转因子 twiddle factor

为了确定过程 RECURSIVE-FFT 的运行时间,注意到除了递归调用外,每次调用所需的时间为 Θ ( n ) \Theta(n) Θ(n) ,其中 n n n 是输入向量的长度。因此,对运行时间有下列递归式: T ( n ) = 2 T ( n / 2 ) + Θ ( n ) = Θ ( n log ⁡ n ) T(n) = 2T(n/2) + \Theta(n) = \Theta(n\log n) T(n)=2T(n/2)+Θ(n)=Θ(nlogn) 因此,采用快速傅里叶变换,我们可以在 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn) 时间内,求出次数界为 n n n 的多项式在 n n n 次单位复数根处的值。

3.4 在单位复数根处插值

现在我们展示,如何在单位复数根处插值、来完成多项式乘法方案,使得我们把一个多项式从点值表达转换回系数表达。如下方法进行插值:把DFT写成一个矩阵方程,然后再观察其逆矩阵的形式

根据等式30.4,我们可以把DFT写成矩阵乘积 y = V n a y = V_n a y=Vna ,其中 V n V_n Vn 是一个由 ω n \omega_n ωn 适当幂次填充成的范德蒙矩阵:
[ y 0 y 1 y 2 y 3 ⋮ y n − 1 ] = [ 1 1 1 1 … 1 1 ω n 1 ω n 2 ω n 3 … ω n n − 1 1 ω n 2 ω n 4 ω n 6 … ω n 2 ( n − 1 ) 1 ω n 3 ω n 6 ω n 9 … ω n 3 ( n − 1 ) ⋮ ⋮ ⋮ ⋮ ⋱ ⋮ 1 ω n n − 1 ω n 2 ( n − 1 ) ω n 3 ( n − 1 ) … ω n ( n − 1 ) ( n − 1 ) ] [ a 0 a 1 a 2 a 3 ⋮ a n − 1 ] \begin{bmatrix} y_0 \\ y_1 \\ y_2 \\ y_3 \\ \vdots \\ y_{n-1} \end{bmatrix} = \begin{bmatrix} 1 & 1 & 1 & 1 & \dots & 1 \\ 1 & \omega_n^1 & \omega_n^2 & \omega_n^3 & \dots & \omega_n^{n-1} \\ 1 & \omega_n^2 & \omega_n^4 & \omega_n^6 & \dots & \omega_n^{2(n-1)} \\ 1 & \omega_n^3 & \omega_n^6 & \omega_n^9 & \dots & \omega_n^{3(n-1)} \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots \\ 1 & \omega_n^{n-1} & \omega_n^{2(n-1)} & \omega_n^{3(n-1)} & \dots & \omega_n^{(n-1)(n-1)} \end{bmatrix} \begin{bmatrix} a_0 \\ a_1 \\ a_2 \\ a_3 \\ \vdots \\ a_{n-1} \end{bmatrix} y0y1y2y3yn1=111111ωn1ωn2ωn3ωnn11ωn2ωn4ωn6ωn2(n1)1ωn3ωn6ωn9ωn3(n1)1ωnn1ωn2(n1)ωn3(n1)ωn(n1)(n1)a0a1a2a3an1 j , k = 0 , 1 , … , n − 1 j,k = 0, 1, \dots, n - 1 j,k=0,1,,n1 V n V_n Vn ( k , j ) (k,j) (k,j) 处元素为 ω n k j \omega_n^{kj} ωnkj V n V_n Vn 中元素的指数组成一张乘法表。对于逆运算 a = D F T n − 1 ( y ) a = \mathrm{DFT_n^{-1}} (y) a=DFTn1(y) ,我们把 y y y 乘以 V n V_n Vn 的逆矩阵 V n − 1 V_n^{-1} Vn1 来进行处理

定理30.7 j , k = 0 , 1 , … , n − 1 j,k = 0, 1, \dots, n - 1 j,k=0,1,,n1 V n − 1 V^{-1}_n Vn1 ( j , k ) (j,k) (j,k) 处元素为 ω n − k j / n \omega^{-kj}_n / n ωnkj/n
证明:我们要做的只是证明,这种形式下 V n − 1 V n = I n V_n^{-1} V_n = I_n Vn1Vn=In ,其中 I n I_n In n × n n\times n n×n 的单位矩阵。考虑 V n − 1 V n V_{n}^{-1}V_n Vn1Vn ( j , j ′ ) (j, j') (j,j) 处的元素:
[ V n − 1 V n ] j j ′ = ∑ k = 0 n − 1 ( ω n − j k / n ) ( ω n k j ′ ) = ∑ k = 0 n − 1 ω n k ( j ′ − j ) / n [ V^{-1}_n V_n]_{jj'} = \sum^{n-1}_{k=0} ( \omega^{-jk}_n / n ) ( \omega_n^{kj'}) = \sum^{n-1}_{k=0} \omega^{k (j' - j)}_n / n [Vn1Vn]jj=k=0n1(ωnjk/n)(ωnkj)=k=0n1ωnk(jj)/n 如果 j ′ = j j' = j j=j ,则此和为 1 1 1 ;否则,根据求和引理(引理30.6),此和为 0 0 0 。注意,只有 − ( n − 1 ) ≤ j ′ − j ≤ n − 1 -(n-1) \le j' - j \le n - 1 (n1)jjn1 ,使得 j ′ − j j' - j jj 不能被 n n n 整除,才能应用求和引理 ■ \blacksquare

给定逆矩阵 V n − 1 V_n^{-1} Vn1 ,可以推导出 D F T n − 1 ( y ) \mathrm{DFT_n^{-1}}(y) DFTn1(y) a j = 1 n ∑ k = 0 n − 1 ω n − j k y k ( j = 0 , 1 , … , n − 1 ) (30.11) a_j = \dfrac{1}{n} \sum^{n-1}_{k=0} \omega_n^{-jk} y_k\quad (j=0, 1, \dots, n-1) \tag{30.11} aj=n1k=0n1ωnjkyk(j=0,1,,n1)(30.11) 通过比较式30.8与式30.11,我们可以看到,对FFT算法进行如下修改就可以计算出逆DFT(算导练习30.2-4):把 a a a y y y 互换,用 ω n − 1 \omega^{-1}_n ωn1 替换 ω n \omega_n ωn ,并将计算结果的每个元素除以 n n n 。因此,我们也可以在 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn) 时间内计算出 D F T n − 1 \mathrm{DFT_n^{-1}} DFTn1

我们可以看到,通过运用FFT与逆FFT,可以在 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn) 时间内、把次数界为 n n n 的多项式在其系数表达与点值表达之间进行相互转换。在矩阵乘法的相关内容中,已经说明了下面的结论。

定理30.8卷积定理 Convolution theorem)对任意两个长度为 n n n 的向量 a , b a, b a,b ,其中 n n n 2 2 2 的整数幂。 a ⊗ b = D F T 2 n − 1 ( D F T 2 n ( a ) ⋅ D F T 2 n ( b ) ) a\otimes b = \mathrm{DFT_{2n}^{-1} ( DFT_{2n}(a) \cdot DFT_{2n}(b))} ab=DFT2n1(DFT2n(a)DFT2n(b)) 其中,向量 a , b a, b a,b 0 0 0 填充、使其长度达到 2 n 2n 2n ,并用 ⋅ \cdot 表示两个 2 n 2n 2n 元向量的点乘。 ■ \blacksquare


4. 高效FFT实现

因为DFT的实际应用(如信号处理)中需要尽可能快的速度,本节将探究两种高效的FFT实现方法。首先,讨论一种运行时间为 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn)FFT迭代实现方法,不过在此运行时间的 Θ \Theta Θ 记号,隐含的常数要比(算导30.2节)前面递归实现方法的常数小(如果实现精确,这个递归方法可能会更加高效地应用硬件缓存)。然后,深入分析迭代实现方法,设计出一个高效的并行FFT电路

4.1 FFT的一种迭代实现

首先我们注意到,在 RECURSIVE-FFT 中,第10~13行的for循环中,包含了 ω n k y k [ 1 ] \omega^k_n y_k^{[1]} ωnkyk[1] 2 2 2 次计算。在编译术语中,称该值为公用子表达式 common subexpression 。我们可以改变循环、使其仅计算一次,并将其存放在临时变量 t t t 中。
在这里插入图片描述

for k = 0 to n/2-1
	t = w * Y1[k]
	y[k] = Y0[k] + t
	y[k + (n/2)] = Y0[k] - t
	w = w * wn

在这个循环中,把旋转因子 ω = ω n k \omega =\omega^k_n ω=ωnk 乘以 y k [ 1 ] y_k^{[1]} yk[1] ,把所得乘积存入 t t t 中,然后从 y k [ 0 ] y^{[0]}_k yk[0] 中增加及减去 t t t ,这一系列操作称为一个蝴蝶操作 butterfly operation ,图30-3说明了执行步骤:
在这里插入图片描述

现在来说明,如何使FFT算法采用迭代结构、而非递归结构。在图30-4中,我们已把输入向量分配在「一次 RECURSIVE-FFT 调用中的各次递归调用中」 、形成一个树形结构 we have arranged the input vectors to the recursive calls in an invocation of RECURSIVE-FFT in a tree structure ,其中初始调用时有 n = 8 n = 8 n=8 。树中的每个结点对应每次递归过程调用,由相应的输入向量标记。每次 RECURSIVE-FFT 调用产生两个递归调用,除非该调用已收到了 1 1 1 个元素的向量。第一次调用作为左孩子,第二次调用作为右孩子。
在这里插入图片描述
观察此树,我们注意到,如果把初始向量 a a a 中的元素按其在叶中出现次序进行安排,就可以对过程 RECURSIVE-FFT 的执行进行追踪,不过是自底向上、而非自顶向下

  • 首先,我们成对取出元素,利用一次蝴蝶操作计算出每对的DFT,然后用其DFT取代这对元素,这样向量中就包含了 n / 2 n/2 n/2 个二元素的DFT。
  • 下一步,我们按对取出这 n / 2 n/2 n/2 个DFT,通过两次蝴蝶操作计算出含有四个元素向量的DFT,并用一个具有四个元素的DFT取代对应的两个二元素的DFT。于是,向量中包含 n / 4 n/4 n/4 个四元素的DFT。
  • 继续进行这一过程,直到向量包含两个具有 n / 2 n/2 n/2 个元素的DFT,这时我们综合应用 n / 2 n/2 n/2 次蝴蝶操作,就可以合成最终的具有 n n n 个元素的DFT。

为了把这个自底向上的方法变为代码,采用了一个数组 A [ 0 … n − 1 ] A[0\dots n - 1] A[0n1] ,初始时该数组包含输入向量 a a a 中的元素,其顺序为它们在图30-4中树叶出现的顺序(在后面说明如何确定这个顺序,这也称为位逆序置换 bit-reversal permutation )。因为需要在树的每一层进行组合,于是引入一个变量 s s s 以计算树的层次,取值范围为从 1 1 1(在最底层,这时我们组合对来构成二元素的DFT)到 log ⁡ n \log n logn(在最顶层,这里我们要对两个具有 n / 2 n/2 n/2 个元素的DFT进行组合,以产生最后结果)。因此,这个算法有如下结构:
在这里插入图片描述
我们可以用更精确的伪代码描述第3行中的循环主体部分。从子程序 RECURSIVE-FFT 中复制for循环,让 y [ 0 ] y^{[0]} y[0] A [ k … k + 2 s − 1 − 1 ] A[k \dots k + 2^{s-1} - 1] A[kk+2s11] 一致、 y [ 1 ] y^{[1]} y[1] A [ k + 2 s − 1 … k + 2 s − 1 ] A[k+2^{s - 1}\dots k + 2^{s} - 1] A[k+2s1k+2s1] 一致。在每次蝴蝶操作中,使用的旋转因子依赖于 s s s 的值,它是 ω m \omega_m ωm 的幂,其中 m = 2 s m = 2^s m=2s(引入变量 m m m 仅为使代码易读)。又引入另一个临时变量 u u u ,使得能恰当地执行蝴蝶操作。当用循环主体来取代第3行的整个结构时,就得到下面的伪代码,它是稍后将展示的、并行实现的基础
在这里插入图片描述
这一代码首先调用辅助过程 BIT-REVERSE-COPY(a, A) ,把向量 a 按我们所需要的初始顺序复制到数组 A 中。BIT-REVERSE-COPY 如何做到这一点呢?在图30-4中,叶出现的顺序是一个位逆序置换。也就是说,如果让 r e v ( k ) rev(k) rev(k) 为「 k k k 的二进制表示各位逆序」所形成的 log ⁡ n \log n logn 位的整数,那么我们希望把向量中的元素 a k a_k ak 放在数组的 A [ r e v ( k ) ] A[rev(k)] A[rev(k)] 位置上。例如,图30-4中叶出现的次序为 0 , 4 , 2 , 6 , 1 , 5 , 3 , 7 0, 4, 2, 6, 1, 5, 3, 7 0,4,2,6,1,5,3,7 ,这个序列用二进制表示为 000 , 100 , 010 , 110 , 001 , 101 , 011 , 111 000, 100, 010, 110, 001, 101, 011, 111 000,100,010,110,001,101,011,111 ,当把二进制表示的各位逆序后,得到序列 000 , 001 , 010 , 011 , 100 , 101 , 110 , 111 000, 001, 010, 011, 100, 101, 110, 111 000,001,010,011,100,101,110,111 。为了获得一般情况下的位逆序置换,我们注意到,在树的最顶层,最低位为 0 0 0 的下标在左子树中、最低位为 1 1 1 的下标在右子树中;在每一层去掉最低位后,我们沿着树往下继续这一过程,直到在叶子得出「由位逆序置换给出的顺序」 at the top level of the tree, indices whose low-order bit is 0 go into the left subtree and indices whose low-order bit is 1 go into the right subtree. Stripping off the low-order bit at each level, we continue this process down the tree, until we get the order given by the bit-reversal permutation at the leaves 。由于很容易计算函数 r e v ( k ) rev(k) rev(k) ,因此过程 BIT-REVERSE-COPY 相对简单。
在这里插入图片描述
调用 BIT-REVERSE-COPY(a, A) 的运行时间当然是 O ( n log ⁡ n ) O(n\log n) O(nlogn) ,因为迭代了 n n n 次,并可以在 O ( log ⁡ n ) O(\log n) O(logn) 时间内、把一个 0 ∼ n − 1 0\sim n - 1 0n1 之间的 log ⁡ n \log n logn 位整数逆序(实际上,通常事先知道 n n n 的初始值,我们就可以编制出一张表、把 k k k 映射为 r e v ( k ) rev(k) rev(k) ,使 BIT-REVERSE-COPY 的运行时间为 Θ ( n ) \Theta(n) Θ(n) ,且该式中隐含的常数因子较小)。此外,可以采用算导思考题17-1中描述的「聪明的摊还逆序二进制计数器方案」。

这种迭代的FFT实现方法的运行时间为 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn) 。为了完成 ITERATIVE-FFT 的运行时间是 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn) 的证明,需要说明最内层循环体(第 8 ∼ 13 8 \sim 13 813 行)执行次数 L ( n ) L(n) L(n) Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn) 。对 s s s 的每个值,第 6 ∼ 13 6\sim 13 613 行的for循环迭代了 n / m = n / 2 s n / m = n / 2^s n/m=n/2s 次、第 8 ∼ 13 8 \sim 13 813 行的最内层循环迭代了 m / 2 = 2 s − 1 m / 2 = 2^{s - 1} m/2=2s1 次。因此: L ( n ) = ∑ s = 1 log ⁡ n n 2 s ⋅ 2 s − 1 = ∑ s = 1 log ⁡ n n 2 = Θ ( n log ⁡ n ) L(n) = \sum^{ \log n}_{s = 1} \dfrac{n}{2^s} \cdot 2^{s - 1} = \sum^{\log n}_{s = 1} \dfrac{n}{2} = \Theta(n\log n) L(n)=s=1logn2sn2s1=s=1logn2n=Θ(nlogn)

4.2 并行FFT电路

我们可以利用许多「允许我们实现一个高效的迭代FFT算法」的性质,来产生一个高效的并行FFT算法,并将其表示成一个电路。图30-5给出了 n = 8 n = 8 n=8 时,已知 n n n 个输入,一个并行FFT电路计算FFT。该电路开始时对输入进行位逆序置换,其后电路分为 log ⁡ n \log n logn 级,每一级由 n / 2 n/2 n/2 个并行执行的蝴蝶操作组成。电路的深度定义为:任意的输入和任意的输出之间、最大的可以达到的计算元素数目,因此上面电路的深度为 Θ ( log ⁡ n ) \Theta(\log n) Θ(logn)

并行FFT电路的最左边部分执行位逆序置换,其余部分模拟迭代的 ITERATIVE-FFT 过程。因为最外层for循环的每次迭代执行 n / 2 n/2 n/2 次独立的蝴蝶操作,于是电路并行地执行它们。

  • ITERATIVE-FFT 内,每次迭代的值 s s s 对应于图30-5中的一个蝴蝶操作的阶段 a stage of butterflies
  • 对于 s = 1 , 2 , … , log ⁡ n s = 1, 2, \dots, \log n s=1,2,,logn ,阶段 s s s n / 2 s n/ 2^s n/2s 组蝴蝶操作(对应于 ITERATIVE-FFT 中每个 k k k 值),每组中有 2 s − 1 2^{s - 1} 2s1 个蝴蝶操作(对应于 ITERATIVE-FFT 中的每个 j j j 值)。
  • 图30-5所示的蝴蝶操作对应于最内层循环的蝴蝶操作( ITERATIVE-FFT 的第 9 ∼ 12 9\sim 12 912 行)。此外还要注意,蝴蝶中用到的旋转因子对应于 ITERATIVE-FFT 中用到的那些旋转因子:在阶段 s s s ,我们使用 ω m 0 , ω m 1 , … , ω m m / 2 − 1 \omega^0_m, \omega^1_m, \dots, \omega^{m/2-1}_m ωm0,ωm1,,ωmm/21 ,其中 m = 2 s m = 2^s m=2s
    在这里插入图片描述

在这里插入图片描述

举报

相关推荐

0 条评论