一 多项式的表达方式
系数表示
数值表式
对于维度是N-1的多项式,对x取N个不同的值,计算对应的N个p值,得到N组对应的值
说明:
文章中
二 离散傅里叶变换
对于多项式的数值表式,x取值设置为N次复方根,可以得到离散傅里叶变换,也就是
这个简单举例说明一下:以为例
离散傅里叶公式
那么
这里用到复方根性质5,说明了 与 相同,可以用上面的数值对表示离散傅里叶变换。具体的证明过程大家可以尝试下,等有时间我把这部分的证明改正一下。
三 快速傅里叶变换推导
将多项式构造成两个多项式,一个只包含x的偶数指数部分对应的系数,另一个只包含x的奇数指数部分对应的系数,也就是
于是有
这样就将一个大问题,分解成两个规模较小的问题,解决两个规模较小的问题后,合起来就解决大规模问题。使用复方根的目的是 让 和 继续分解下去
在此讨论一下这些复方根的特点:
特点一:把复方根平分为两半,即
根据性质5: 上面的值可以转换为
根据性质2: 上面的值可以转换为
也就是说,在复方根中,后一半的数值是前一半数值的相反数。
特点二:将x取值为复方根,计算每个根的平方
将复方根分为上下两部分比较,根据复方根性质3: ,上下两部分平方值相等
四 快速傅里叶变换python代码实现
from math import cos, pi, sin
import numpy as np
def create_complex_roots(N):
'''
生成N次复方根
'''
roots = []
for k in range(N):
root_k = complex(cos(2*k*pi/N), -sin(2*k*pi/N))
roots.append(root_k)
return roots
def fast_fourier_transform(coefficients):
if len(coefficients) <= 1:
return coefficients
degree = len(coefficients)
n_complex_roots = create_complex_roots(degree) #1 获取N次复方根
even_coefficients = coefficients[0:degree:2] #2 获取偶数项系数
odd_coefficients = coefficients[1:degree:2] #3 获取奇数项系数
even_fft = fast_fourier_transform(even_coefficients) #4 计算偶数项fft
odd_fft = fast_fourier_transform(odd_coefficients) #5 计算奇数项fft
fft_first_part = []
fft_second_part = []
for k in range(int(degree/2)): #6 将奇数项和偶数项合并起来
w = n_complex_roots[k]
fft_first_part.append(even_fft[k] + w * odd_fft[k]) #7
fft_second_part.append(even_fft[k] - w * odd_fft[k]) #8 -w是因为后一半根是前一半根的相反数
fft = []
fft.extend(fft_first_part)
fft.extend(fft_second_part)
return fft
def py_fft(inpt, N):
fft_result = np.fft.rfft(inpt, N)
return fft_result
if __name__ == "__main__":
inpt = [1,2,3,4,5,6,7,8]
fft = fast_fourier_transform(inpt)
py_res = py_fft(inpt, len(inpt))
for item in fft:
print(item)
print("\n================================\n")
for item in py_res:
print(item)
运行结果是:
(36+0j)
(-4+9.65685424949238j)
(-4+4j)
(-4+1.6568542494923797j)
(-4+0j)
(-4-1.6568542494923806j)
(-3.9999999999999996-4j)
(-3.9999999999999987-9.65685424949238j)
================================
(36+0j)
(-4+9.65685424949j)
(-4+4j)
(-4+1.65685424949j)
(-4+0j)
五 python代码说明
根据代码来理解快速傅里叶变换的算法逻辑。
函数fast_fourier_transform()接收多项式系数组成的数组,如果传入的参数数组只有一个元素,意味着多项式只有一个系数,代码直接将该元素返回。
如果参数数组元素个数大于1,根据#1创建对应个数的复方根。接着#2和#3抽取偶数项和奇数项对应的系数,然后#4和#5将问题分解成两个规模更小的问题进行递归求解
需要注意的是,能够递归依赖于N次方根的特性。当执行#4语句时,进行递归再次进入函数fast_fourier_transform(),在函数起始处又构造N/2个复方根。在递归前,代码希望对x取值 进行计算,递归后代码是对 进行计算。根据复方根的性质1:, 就有 = = 。所以递归前x的取值和递归时x的取值是一样的,这是由N次复方根的性质决定的。如果x取值不是复方根,无法保证递归前后x的取值一致,这就是要使用复方根进行快速傅里叶变换的原因。
注意#6只循环系数个数的一半,这个因为复方根在取平方时,前一半值与后一半值完全相同。
注意#7和#8,因为只循环系数个数的一半,复方根只有前一半值参与计算。又因为复方根后一半值是前一半值的相反数,w对应复方根前一半值,-w对应复方根后一半值。这就是#7中是+,而#8中是 - 的原因。
此时的FFT的复杂度是O(n*lg(n))。用T(n)表示计算维度是n的多项式所需的时间,那么计算,的时间就是 2* T(n/2),#6对应的循环是O(n),整个复杂度就是,使用猜测检验法可以确定 T(n) = O(n*lg(n))。
接下来就是逆向傅里叶变换