📅  最后修改于: 2023-12-03 15:23:43.626000             🧑  作者: Mango
多项式乘法是计算机科学中一个重要的问题,尤其是在数学和工程领域,如图像处理、信号处理、代码压缩等。传统的多项式乘法算法的时间复杂度为 $O(n^2)$,但是可以利用快速傅里叶变换(FFT)算法将其降为 $O(n\log n)$。
FFT算法是一种高效的离散傅立叶变换(Discrete Fourier Transform,DFT)算法,它利用了一些数学技巧将DFT的时间复杂度从 $O(n^2)$ 降低到 $O(n\log n)$。因此,FFT算法可以将多项式的乘法效率提高到 $O(n\log n)$,是一种非常优秀的算法。
DFT是信号处理中常用的一种方法,它将时域(时间)上的信号转换为频域(频率)上的信号。给定一个长度为 $n$ 的序列 $x={x_0,x_1,x_2,\dots,x_{n-1}}$,其DFT为:
$$ X_k = \sum_{j=0}^{n-1} x_j \cdot w_n^{jk} \quad 0\le k<n $$
其中 $w_n=\mathrm{e}^{-2\pi \mathrm{i}/n}$,$\mathrm{i}$ 为虚数单位。DFT最简单的算法是通过定义式计算,时间复杂度为 $O(n^2)$。我们将在下一节中介绍FFT算法,它能够利用某些性质将复杂度降到 $O(n\log n)$。
将信号从频域转换为时域,得到逆离散傅里叶变换(Inverse Discrete Fourier Transform,IDFT):
$$ x_j=\frac{1}{n}\sum_{k=0}^{n-1} X_k\cdot w_n^{-jk} \quad 0\le j<n $$
FFT算法建立在DFT的性质之上,通过分治法来实现复杂度为 $O(n\log n)$ 的计算。FFT有一系列的优势:
FFT算法的主要流程如下:
在代码实现中,通常采用递归实现FFT算法,其中 $n$ 为 $2$ 的幂次。当 $n=1$ 时,递归返回;当 $n>1$ 时,递归计算两个子问题的FFT,然后将子问题的结果组合为原问题的FFT。对于计算 DFT 的常数项,CPU 的乘法操作比较快,建议采用直接计算的方式。
def fft(a):
n = len(a)
if n == 1:
return a
w_n = complex(cos(2*pi/n), sin(2*pi/n))
omega, odd = 1, a[1::2]
even, y = fft(a[::2]), [0] * n
for i in range(n//2):
y[i] = even[i] + omega * odd[i]
y[i+n//2] = even[i] - omega * odd[i]
omega = omega * w_n
return y
假设有两个多项式 $A(x)$ 和 $B(x)$,均为 $n$ 次多项式,它们的系数分别为:
$$ A(x) = a_0 + a_1x + a_2x^2 + \dots + a_{n-1}x^{n-1} + a_nx^n $$
$$ B(x) = b_0 + b_1x + b_2x^2 + \dots + b_{n-1}x^{n-1} + b_nx^n $$
则它们的乘积多项式 $C(x)$ 的系数可以通过 $A(x)$ 和 $B(x)$ 的卷积来计算:
$$ C(x) = A(x) \cdot B(x) = \sum_{i=0}^{n-1} a_ix^i \cdot \sum_{j=0}^{n-1} b_jx^j = \sum_{i+j\le n} a_ib_jx^{i+j} $$
因此,如果我们可以用FFT算法求出 $A(x)$ 和 $B(x)$ 的点值表达,就可以得到它们的乘积的点值表达式,最终再用逆FFT算法求出 $C(x)$ 的系数,即可解决多项式乘法问题。
多项式乘法 FFT算法的常用模板如下所示
def convolution(a, b):
# 扩展到2的幂次方
n = 1
while n < len(a) + len(b):
n *= 2
a += [0] * (n - len(a))
b += [0] * (n - len(b))
# fft
fft_a = fft(a)
fft_b = fft(b)
c = [i * j for i, j in zip(fft_a, fft_b)]
# ifft
ifft_c = ifft(c)
# 将结果的虚部舍去
return [int(round(i.real)) for i in ifft_c]
该程序 first 环节进行的是数据预处理,将两个多项式 $A(x)$ 和 $B(x)$ 添零至等长 2 次幂,在处理完成之后,进行 DFT(fast fourier transform)得到两个多项式的点值表达式,执行点值乘法,即对应项相乘,得到单个多项式的点值表达式。最后,通过 iDFT(inverse discrete fourier transform)将多项式转换回系数表达式。
FFT算法技术是一种理解点值思想和快速多项式卷积思维的关键。将长时间复杂度的多项式乘法优化到快速的 $O(n\log n)$ 之后,FFT算法逐渐在实际使用中得到了广泛的应用。