Fast Fourier Transform

快速傅里叶变换(FFT)

这几天在家没事慢慢研究了一下集训最后的一个专题FFT, 陈犇讲完还是有点不是很懂, 网上的很多资料都讲的不是很清晰, 由于这个算法太美了, 我有必要写点什么东西表示对前人智慧的赞美! (顺便练练打公式)

1.FFT这玩意是什么?有什么用?

FFT ( fast Fourier transform )的中文名是快速傅里叶变换, 在信号领域有很大的作用, 在ACM中我们常用FFT来求解多项式乘法

举个例子:

y1=2x4+3x2+5x+7
y2=5x3+7x2+11
FFT就是用来快速地计算 y1y2 所得到的多项式
( y1y2=10x7+14x6+15x5+68x4+70x3+82x2+55x+77 )

2.FFT预备知识

1.多项式

1.多项式定义

A(x)=a0+a1x+a2x2++an2xn2+an1xn1

A(x)=i=0n1aixi

2.多项式表达方式
  • 系数表达: (a0,a1,a2,,an2,an1)
  • 点值表达:选取 n 个(或以上)不同的值:x0,x1,...xn2,xn1, 对多项式 A(x) 求值得到 A(x0),A(x1),,A(xn1)
    那么就称 {(xi,A(xi)),0i<n,iZ} 为多项式 A(x) 的点值表示
举个例子:

f(x)=2+3x+x2 这个多项式的系数表达式就是 (2,3,1) , 点值表达式就是 {(0,2),(1,6),(2,12)} 或者 {(1,6),(2,12),(3,20),(4,30)}
n1 次多项式只要选取任意不同的 n 个点(或以上)都是可以的

显然不管是点值表达式还是系数表达式都可以唯一确定一个n1次多项式, 并且它们是可以相互推导的

3.多项式的乘法
  • 系数表达式下的乘法
    A(x)=i=0n1aixi,B(x)=i=0n1bixi

    那么 A(x)B(x) 就可以表示为
    C(x)=i=02n2(j=0iajbij)xi
  • 点值表达式下的乘法
    {xi,C(xi)}={xi,A(xi)B(xi)}
举个例子:

已知 f1(x)=x2+1,f2(x)=x+3
f1(x) 的点值表达式是 {(0,1),(1,2),(2,5),(3,10)}
f2(x) 的点值表达式是 {(0,3),(1,4),(2,5),(3,6)}
那么 f1(x)f2(x) 的点值表达式就是 {(0,3),(1,8),(2,25),(3,60)}

2.单位复根

0.引入

不考虑什么叫做单位复根
先在平面直角坐标系下画一个单位圆, 即 {(x,y)|x2+y2=1}
现在我们要在这个圆上取 n 个点(n>0),使得这 n 个点恰好把圆弧分成了n等份, 规定第 1 个点一定(1,0)

举个例子:

n=3 时, 这些点的坐标按照逆时针顺序分别是

(1,0),(12,32),(12,32)

n=4 时, 这些点的坐标按照 逆时针顺序分别是
(1,0),(0,1),(1,0),(0,1)

n=8 时, 这些点的坐标按照 逆时针顺序分别是
(1,0),(22,22),(0,1),(22,22),

(1,0),(22,22),(0,1),(22,22)

如果我们把 平面直角坐标系看做是 复平面, 那么上面那些 就变成了一个 复数, 它们正是 单位复根

1.单位复根定义

方程 xn=1 复数域一定 n 个不同的解
那么规定: wkn是方程 xn=1 的第 k+1 个根 (0k<n)
也就是对应了上面我们从圆上逆时针选取 n 个点中的第k个点

举个例子:

w02=1 (x2=1 的第 1 个根是 1)
w12=1 (x2=1 的第 2 个根是 1)

w04=1 (x4=1 的第 1 个根是 1)
w14=i (x4=1 的第 2 个根是 i)
w24=1 (x4=1 的第 3 个根是 1)
w34=i (x4=1 的第 4 个根是 i)

w08=1 (x8=1 的第 1 个根是 1)
w18=i (x8=1 的第 2 个根是 22+22i)
w28=1 (x8=1 的第 3 个根是 i)
w38=i (x8=1 的第 4 个根是 22+22i)
w48=1 (x8=1 的第 5 个根是 1)
w58=i (x8=1 的第 6 个根是 2222i)
w68=1 (x8=1 的第 7 个根是 i)
w78=i (x8=1 的第 8 个根是 2222i)

我们不难归纳得到:

wkn=cos(2πkn)+sin(2πkn)i

规定: 当 kn 时, wkn=wk%nn
例如: w64=w24,w208=w48

2.单位复根性质

下面的只讨论 n 2的次方时,即: n=2m,(m0) 时的性质
画图我们可以很容易的证明

(wkn)2=wkn/2

例如: (w38)2=w34 , (w68)2=w64=w24

3.FFT原理

用一句话来说就是:将原多项式的系数表达式转换成点值表达式 (O(nlog2n)) , 再将多项式的点值表达式相乘得到目标表达式的点值表达式 (O(n)) , 再将点值表达式转换成为系数表达式 (O(nlog2n))

为了能够在 O(nlog2n) 时间内得到多项式的点值表达式, FFT采取了一些小技巧, 选择 n 个单位复根进行求值, 由于单位复根的一些性质, 我们可以在O(nlog2n)求出它们的值

现在我们有一个最高次幂 m 的多项式:

A(x)=a0+a1x+a2x++am1xm1+amxm

1.先将这个多项式的最高次数扩充 2 的次方n1

A(x)=a0+a1x+a2x++amxm+0xm+1+0xm+2++0xn1(n1m)=a0+a1x+a2x2++an2xn2+an1xn1

2.分别带入 n 个不同的单位复根(w0n,w1n,w2n,...,wn1n)
A(w0n)=a0+a1w0n++an1(w0n)n1A(w1n)=a0+a1w1n++an1(w1n)n1A(w2n)=a0+a1w2n++an1(w2n)n1A(wn2n)=a0+a1wn2n+an1(wn2n)n1A(wn1n)=a0+a1wn1n+an1(wn1n)n1

可以写成一个矩阵:
A(w0n)A(w1n)A(w2n)A(wn2n)A(wn1n)=11111w0nw1nw2nwn2nwn1n(w0n)2(w1n)2(w2n)2(wn2n)2(wn1n)2(w0n)n2(w1n)n2(w2n)n2(wn2n)n2(wn1n)n2(w0n)n1(w1n)n1(w2n)n1(wn2n)n1(wn1n)n1a0a1a2an2an1

没错我们就是要在 O(nlog2n) 时间内得到 A(w0n),A(w1n),A(w2n),,A(wn2n),A(wn1n) n 个值 ! ! !
3.单独考虑其中任意一个方程
A(wkn)=a0+a1wkn+a2(wkn)2++an1(wkn)n1

3.将奇数项和偶数项分开
得到
A(wkn)=(a0+a2(wkn)2++an2(wkn)n2)+(a1wkn+a3(wkn)3++an1(wkn)n1)=(a0+a2(wkn)2++an2(wkn)n2)+wkn(a1+a3(wkn)2++an1(wkn)n2)=(a0+a2wkn/2++an2(wkn/2)n21)+wkn(a1+a3wkn/2++an1(wkn/2)n21)

4.假设两个新的多项式:
A0(x)=a0+a2x++an2xn21
A1(x)=a1+a3x++an1xn21
那么 A(wkn)=A0(wkn/2)+wknA1(wkn/2)
我们只要再次用同样的方法计算 A0(x) 以及 A1(x) 就可以在 O(nlog2n) 时间内求出 A(x) 所有点值表达式了

举个例子:

多项式 f(x)=a0+a1x+a2x2+a3x3 , 我们要计算 A(w04),A(w14),A(w24),A(w34) 这4个点的值
1.
A(w04)=A0(w02)+w04A1(w02)
A(w14)=A0(w12)+w14A1(w12)
A(w24)=A0(w02)+w24A1(w02)
A(w34)=A0(w12)+w34A1(w12)
2.
A(w02)=A0(w01)+w02A1(w01)
A(w12)=A0(w01)+w12A1(w01)
3.
因为 w01=1 所以可以直接得到它的值, 也就是当前的系数

上述过程就称为 离散傅里叶变换(Discrete Fourier Transform)

我们将多个多项式的点值表达式相乘, 获得了目标表达式的点值表达式
那么: 怎么获得目标表达式的系数表达式呢?

下面我们将要介绍 逆离散傅里叶变换(Inverse Discrete Fourier Transform)

A(x0)A(x1)A(x2)A(xn2)A(xn1)=11111x0x1x2xn2xn1(x0)2(x1)2(x2)2(xn2)2(xn1)2(x0)n2(x1)n2(x2)n2(xn2)n2(xn1)n2(x0)n1(x1)n1(x2)n1(xn2)n1(xn1)n1a0a1a2an2an1

上面的矩阵就是 DFT 的过程, 下面的矩阵就是 IDFT 的过程

a0a1a2an2an1=1n11111x10x11x12x1n2x1n1(x0)2(x1)2(x2)2(xn2)2(xn1)2(x0)n+2(x1)n+2(x2)n+2(xn2)n+2(xn1)n+2(x0)n+1(x1)n+1(x2)n+1(xn2)n+1(xn1)n+1A(x0)A(x1)A(x2)A(xn2)A(xn1)

其实差异并不大, 我们只需要将原来DFT中 wkn 换成 wkn ,结果再乘上 1n 就从 DFT 变成了 IDFT

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值