傅里叶变换尺度变换性质_一小时学会快速傅里叶变换(Fast Fourier Transform)

本文详细介绍了快速傅里叶变换(FFT)的概念、性质及其实现,包括离散傅里叶变换(DFT)、逆离散傅里叶变换(IDFT),并提供了C++实现的复数类和FFT算法。文中还涉及多项式乘法、复数运算以及单位根的相关知识。

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

2019.10.25更新

至此本篇文章距离上次更新已经两年,谢谢各位一直以来的支持。这一次也让我知道了追求一种通透的知识能够得到认可,再次感谢。

0x00 写在前面

为了让更多人能够看到这个教程,希望大家收藏之前,也要点赞哦!!!蟹蟹大家的认可和鼓励。

傅里叶变换

快速傅里叶变换(Fast Fourier Transform,FFT)是一种可在

时间内完成的离散傅里叶变换(Discrete Fourier transform,DFT)算法。

在算法竞赛中的运用主要是用来加速多项式的乘法。

考虑到两个多项式

的乘积
,假设
的项数为
,其系数构成的
维向量为
的项数为
,其系数构成的
维向量为

我们要求

的系数构成的
维的向量,先考虑朴素做法。

可以用这段代码表示:

for 

思路非常清晰,其时间复杂度是

的。

所以我们来学习快速傅里叶变换


0x01 关于多项式

多项式有两种表示方法,系数表达法点值表达法

多项式的系数表示法

设多项式

为一个
次的多项式,显然,所有项的系数组成的系数向量
唯一确定了这个多项式。

多项式的点值表示法

将一组互不相同的

(叫插值节点)分别带入
,得到
个取值
.

其中

定理:

一个
次多项式在
个不同点的取值唯一确定了该多项式。

证明:

假设命题不成立,存在两个不同的
次多项式
,满足对于任何
,有

,则
也是一个
次多项式。对于任何
,都有

个根,这与代数基本定理(一个
次多项式在复数域上有且仅有
个根)相矛盾,故
并不是一个
次多项式,推到矛盾。

原命题成立,证毕。

如果我们按照定义求一个多项式的点值表示,时间复杂度为

已知多项式的点值表示,求其系数表示,可以使用插值。朴素的插值算法时间复杂度为

关于多项式的乘法

已知在一组插值节点

(假设个多项式的项数相同,没有的视为
)的点值向量分别为
,那么
的点值表达式可以在
的时间内求出,为

因为

的项数为
的项数之和。

分别有
项所以我们带入的插值节点有至少有
个。

如果我们能快速通过点值表式求出系数表示,那么就搭起了它们之间的一座桥了。

这也是快速傅里叶变换的基本思路,由系数表达式到点值表达式到结果的点值表达式再到结果的系数表达式。


0x02 关于复数的基本了解

我们把形如

这样的数叫做复数,复数集合用
来表示。其中
称为实部
称为虚部
,
为虚数单位,指满足
的一个解
;此外,对于这样对复数开偶次幂的数叫做虚数
.

每一个复数

都对应了一个平面上的向量
我们把这样的平面称为复平面
,它是由水平的实轴与垂直的虚轴建立起来的复数的几何表示。

故每一个复数唯一对应了一个复平面上的向量,每一个复平面上的向量也唯一对应了一个复数。其中

既被认为是实数,也被认为是虚数。

其中复数

的模长
定义为
在复平面的距离到原点的距离,
。幅角
为实轴的正半轴正方向(逆时针)旋转到
的有向角度。

由于虚数无法比较大小。复数之间的大小关系只存在等于不等于两种关系,两个复数相等当且仅当实部虚部对应相等。对于虚部为

的复数之间是可以比较大小的,相当于实数之间的比较。

复数之间的运算满足结合律交换律分配律

由此定义复数之间的运算法则:

复数运算的加法满足平行四边形法则,乘法满足幅角相加,模长相乘

对于一个复数

,它的共轭复数是
,
称为
的复共轭
.

共轭复数有一些性质


0x03 复数中的单位根

复平面中的单位圆

07ab87eee3f8bebbd177f4b93d444003.png

其中

单位根,表示为
,可知

(顺便一提著名的欧拉幅角公式

其实是由定义来的...)

将单位圆等分成

个部分(以单位圆与实轴正半轴的交点一个等分点),以原点为起点,圆的这
等分点为终点,作出
个向量。

其中幅角为正且最小的向量称为

次单位向量,记为

有没有大佬帮我补张图啊,画不来

其余的

个向量分别为
,它们可以由复数之间的乘法得来

容易看出

对于

,它事实上就是

所以

关于单位根有两个性质

性质一(又称为折半引理):

证明一:

由几何意义,这两者表示的向量终点是一样的。

证明二:

由计算的公式:

其实由此我们可以引申出

性质二(又称为消去引理)

证明一:

由几何意义,这两者表示的向量终点是相反的,左边较右边在单位圆上多转了半圈。

证明二:

由计算的公式:

最后一步由三角恒等变换得到。


0x04 离散傅里叶变换(Discrete Fourier Transform)

首先我们单独考虑一个

项(
)的多项式
,其系数向量为
。我们将
次单位根的
~
次幂分别带入
得到其点值向量

这个过程称为离散傅里叶变换(Discrete Fourier Transform)

如果朴素带入,时间复杂度也是

的。

所以我们必须要利用到单位根

的特殊性质。

对于

考虑将其按照奇偶分组

则可得到

分类讨论

由上文提到的折半引理

对于

其中

由消去引理

注意,

取遍了
中的
个整数,保证了可以由这
个点值反推解出系数(上文已证明)。

于是我们可以知道

如果已知了

分别在
的取值,可以在
的时间内求出
的取值。

都是
一半的规模,显然可以转化为子问题递归求解。

时间复杂度:


0x05 离散傅里叶反变换(Inverse Discrete Fourier Transform)

使用快速傅里叶变换将点值表示的多项式转化为系数表示,这个过程叫做离散傅里叶反变换(Inverse Discrete Fourier Transform)

即由

维点值向量
推出
维系数向量

得到的离散傅里叶变换的结果。

我们构造一个多项式

设向量

的点值表示

我们考虑对

进行还原

于是

由和式的性质

对其进行化简

其公比为

此时

由等比数列求和公式

,此时
.

所以

带入原式

所以

.

其中

为原多项式
的系数向量
中的
.

由此得到:

对于多项式

由插值节点
做离散傅里叶变换得到的点值向量
。我们将
作为插值节点,
作为系数向量,做一次离散傅里叶变换得到的向量每一项都除以
之后得到的
就是多项式的系数向量

注意到

的共轭复数。

这个过程称为离散傅里叶反变换。


0x06 关于FFT在C++的实现

首先要解决复数运算的问题,我们可以使用C++STL自带的

依照精度要求
一般为

也可以自己封装,下面是我封装的复数类。

struct 

我们由上面的分析可以得到这个递归的写法。

bool 

但是这样的

要用到辅助数组,并且常数比较大。

能不能优化呢?

我们把每一次分组的情况推演出来

a35810235a899254afdb5fba6fa2b43b.png
递归分类的每一层

观察到每一个位置的数其实都是原来位置上的数的二进制后

了一下。

于是我们可以想,先将原数组调整成最底层的位置(很好调整吧)。

然后从倒数第二层由底向上计算。

这就是我们一般用来实现

算法。

考虑怎么合并?

算法中,合并操作被称作是蝴蝶操作。

虑合并两个子问题的过程,这一层有

项需要处理。假设
分别存在
中,
将要被存放在
中,合并的单位操作可表示为

只要将合并顺序换一下,再加入一个临时变量,合并过程就可以在原数组中进行。

合并过程如下:

至此,我们可以给出

算法的实现。
struct 

注意代码中的

,而在代码中需要得到的是

因为

都是
的次幂,所以
,且

所以

(可以由折半引理证明)。

其余配图

代码都很好理解。

至此快速傅里叶变换就结束了。

0x07 写在后面

参考资料

复数-Wikipedia

复平面-Wikipedia

Complex Number-Wikipedia

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值