分享

FFT(最详细最通俗的入门手册)

 imelee 2018-08-06

正文:

文章写的有点急。有错误的地方望指出
我学习 FFT 是一个比较慢的过程。 期间反反复复。 我写这篇博文只是一个非常浅显的理解。同时也可以帮助初学者在学习FFT的时候。有所偏重。避免太多思维上的负担。

直接正题吧:

首先:本身并不负责多项式之间的乘法。

只是一种变换。

则是DFT的快速算法。(分治 提高效率)

利用 。我们快速的将多项式变换为利于计算的形式

用这种方便计算的形式计算出来两个多项式的乘积。

这时候我们虽然已经得到目标多项式。但其形式并不是我们想要的

所以 之后利用 的 逆运算 又快速的变换回去

我们记:的逆运算为 1

对于一个次多项A的表示。最常见的形式(系数表达):

2

小学生手算 系数形式 的 多项式乘法 的 复杂度是

如果我们知道了一个次多项式 的曲线上的个不同的的点。

我们是可以计算出来这个多项式的

把系数看做未知数。列出来n个方程组。解出来这n个系数。

也就是说,给出曲线上的n个点:

我们可以确定其系数形式;

我们称这种表达一个多项式的方法叫:点值表达

他有很多优点。比如可以时间内计算一个多项式乘法

再给出一个多项式:

设与在取相同x的点值表达为:

这里 ,

则为:

3

非常方便。顺其自然;

之所以与多取一些点。是因为的次数界增加。

取点不足会导次数界达不到

对于一个次多项式。随机求其n个不同的点的朴素方法复杂度是

假设 n为偶数。那么我们把。重组为两个多项式:

设其系数的下标为偶数组成的多项式为:

设其系数的下标为奇数组成的多项式为:

所以有:

4

好像并不会优化运算。

因为

依然有可能会组成n个不同的数字。

那么我们要计算的规模不会减半。

如果我们恰当选取一些x。是否会优化运算呢。

例如:

各个数字平方后。得到的集合大小减半:

因为

那么

但是这种关系不会传递下去。平方后得到的数字全是不小于0的数字。

再次递归又回到了原来的形式。很尴尬。

不过这启迪我们。取相反数。然后平放。可以把问题规模减半。但再一次递归就失效了。是否存在不失效的取值呢。

如果对于一个有偶数个元素的数字集合。每个元素平方后。得到的新集合。去除重复元素后。集合大小能够减半。并且得到的新集合如果为偶数。新集合依然满足上面的性质。我们称这个集合有 折半 的性质。

如果我们可以快速的找到一个满足折半性质的自变量的取值集合.

分治就是可行的。

有一种东西。可以满足我们的需求。

那就是 —— n次单位复数根

(使用复数确实让人有顾虑。这也是我学习FFT时最大 思想负担)

我们定义

那么形如

的复数有诸多良好的性质。

例如:

上面的性质可以用数学归纳法得到(较为简单。这里不做证明

我们记:

我会告诉你 多项式在x取下面的值时。有助于我们进行DFT

上面的n个复数称为。n次单位复数根。(n次单位复数根是指这n个数)

如果我们x取时。根据刚才的分解:

因为三角函数的周期性:

我们有:

所以:

则:

惊不惊喜,意不意外。

的取值集合取单位复数根。不但满足折半的性质。而且还有一定的规律性。与原集合保持一致。

这意味着我们只需要计算取:

问题范围减半。并且如果n为偶数。再次平方依然集合大小减半。

记:

那么,当我们得到:

这意味着我们得到了所有的

则:

即得到了:

其中

当然。FFT的计算 n要取2的整数次幂 。这是因为每次减半。我们可以把不足的系数用0填充。

上面过程可以看作 ,取单位复数根计算目标y向量,如下图:

本着尽可能简单的原则。我们不在特别的说这个矩阵。

因为之前说关于系数的n个方程必然可解。所以上面的矩阵:

必然存在逆矩阵5。(有线性代数基础的,或许不陌生)

可能你还是有点迷惑。没关系:

如果我们把FFT看作计算上面特别的矩阵相乘的算法呢。

利用FFT我们可以快速得到:

同时 。我可以直接告诉你:

的逆矩阵为:

因为我直接给你了答案。。。所以怀疑的话。我们可以计算一下看看。

我们记Y=E*D

上面可以看作等比数列求和。

当时:

当时,令:

因为:

所以,时:

所以。Y为单位矩阵。E,D互为逆矩阵得证。

所以:

所以。其实就是的变为得到。

并且所得目标向量每个元素除掉n就可以了6

FFT的高效实现:

通常。我们希望FFT的实现尽可能快。所以FFT算法也都使用迭代结构而不是递归结构。

下面介绍一种常用的去递归方法。

首先。上面介绍的FFT是只能处理2的整数次幂的次数界的多项式

所以不特别说明。都有(系数不足的用0补足)

对于递归的第一步:

输入数组

被分解为,偶数和奇数两个部分数

下标二进制形式右起第一个字符为 0 被分配到左集合

下标二进制形式右起第一个字符为 1 被分配到右集合

更一般的。对于第k次递归:

下标右起第k个字符为 0 被分配到它所在问题的左集合

下标右起第k个字符为 1 被分配到它所在问题的右集合

那么对于一个2进制形式的数字 B。将其表示为(注意:):

根据之前分析。这个数字递归后将会被分配到的位置为:

所以。对于一个数字的二进制形式的前k位对称过来。就是递归后的位置。

例如:,

我们调用FFT前对数组进行一次上述重拍。

便可 自底向上迭代 实现FFT

总结:

由于递归结构的FFT较好理解。而理解递归结构的FFT后。

不难写出非递归结构

所以在这里我们对递归结构的FFT基本框架做一个总结。

因为使用到了复数。所以不可避免的 。我们以下计算都在复数范围的

方便起见。我们用符号:来表示复数

那么多项式:

令:

当n=1时:

n>1时:

令: ,

计算与

计算完成后,令:

返回

————————————————————————

我对上述思想解释一下

A在处的值保存在Y中。

并返回给上一层。所以对于当前调用:

当 时:

模版

给出一个迭代结构的FFT模版:

定义复数:

struct Complex
{
    double x,y;
    Complex(double x1=0.0 ,double y1=0.0)
    {
        x=x1;
        y=y1;
    }
    Complex operator -(const Complex &b)const
    {
        return Complex(x-b.x,y-b.y);
    }
    Complex operator +(const Complex &b)const
    {
        return Complex(x+b.x,y+b.y);
    }
    Complex operator *(const Complex &b)const
    {
        return Complex(x*b.x-y*b.y,x*b.y+y*b.x);
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

去递归:

void change(Complex y[],int len)
{
    int i,j,k;
    for(i=1,j=len/2;i<len-1;i++)
    {
        if(i<j)swap(y[i],y[j]);
        k=len/2;
        while(j>=k)
        {
            j-=k;
            k/=2;
        }
        j+=k;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

迭代结构的FFT

on== 1 时:
on==-1 时:
void FFT(Complex y[],int len,int on)
{
    change(y,len);
    for(int h=2;h<=len;h<<=1)
    {
        Complex wn(cos(on*2*pi/h),sin(on*2*pi/h));
        for(int j=0;j<=len;j+=h)
        {
            Complex w(1,0);
            for(int k=j;k<j+h/2;k++)
            {
                Complex u=y[k];
                Complex t=w*y[k+h/2];
                y[k]=u+t;
                y[k+h/2]=u-t;
                w=w*wn;
            }
        }
    }
    if(on==-1)
        for(int i=0;i<len;i++)
        y[i].x/=len;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多