FFT(快速傅里叶变换)

FFT(快速傅里叶变换)

前置知识

\(1.复数\)

\(2.单位根\)

\(3.循环结构\)

\(4.C++\)

1.复数

  • \(定义:形如a+bi的数,其中i^2=-1\)
  • \(计算:1.(a+bi)+(c+di)=(a+c)+(b+d)i\)

    \(\ \ \ \ \ \ \ \ \ \ \ 2.(a+bi)-(c+di)=(a-c)+(b-d)i\)

    \(\ \ \ \ \ \ \ \ \ \ \ 3.(a+bi)(c+di)=(ac-bd)+(ad+bc)i\)

  • \(向量表示法\)

    \(用x表示实部(没有i的部分),用y表示虚部(i前的系数)\)

    \(性质1.复数乘法满足向量模角相加\)

    \(证明:arctan(\frac{a}{b})+arctan(\frac{c}{d})=arctan(\frac{\frac{a}{b}+\frac{c}{d}}{1-\frac{ac}{bd}})=arctan(\frac{ad+bc}{bd-ac})\)

    \(是不是巨简单!\)

2.单位根

  • \(定义:n次单位根是n次幂为1的复数。它们位于复平面的单位圆上,\)
    \(构成正n边形的顶点,其中一个顶点是1。\)
  • \(显然,\omega_n^0=\omega_n^n=1,\omega_n=(cos(\frac{2\pi}{n}),sin(\frac{2\pi}{n})),n个复数为\omega_n^1,\omega_n^2...\omega_n^n\)
  • \(性质:\omega_{n}^k=\omega_{2n}^{2k}\)

正题

\(令A(x)=a_0+a_1x^1...a_nx^n\)

\(则A(x)=(a_0+a_2x^2...a_{2\lfloor\frac{n}{2}\rfloor}x^{2\lfloor\frac{n}{2}\rfloor})+(a_1x+a_3x^3...a_{2\lfloor\frac{n}{2}\rfloor+1}x^{2\lfloor\frac{n}{2}\rfloor+1}),令左边的为A_1(x^2),右边的为xA_2(x^2),A(x)=A_1(x^2)+xA_2(x^2)\)

\(将\omega_n^k(k<\frac{n}{2})带入得\)

\(A(\omega_n^k)=A_1(\omega_n^{2k})+\omega_n^kA_2(\omega_n^{2k})\)

\(将\omega_n^{k+\frac{n}{2}}带入得\)

\(A(\omega_n^k)=A_1(\omega_n^{2k})-\omega_n^kA_2(\omega_n^{2k})\)

\(我们发现2式只有系数不同,所以可以在k\in[0,\frac{n}{2}-1]时顺便把k\in[\frac{n}{2},n-1]计算出来,就可以实现以下时间\)

\[ T(n)=\left\{
\begin{array}{rcl}
2T(\frac{n}{2})+n&& {1<n}\1&& {n=1}
\end{array} \right. \]

\(时间复杂度为O(nlog_2n)\)


细节

  1. 为使序列长度为\(2^m\),把不足位补0
  2. 把下标奇偶分类后的位置其实就是2进制下的反转,所以可以通过迭代(非递归)实现,实际效率也是递归版的\(1.5\)~\(2\)倍

\(\mathfrak{Talk\ is\ cheap,show\ you\ the\ code.}\)

#include<cstdio>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
# define read read1<int>()
# define Type template<typename T>
Type inline T read1(){
    T n=0;
    char k;
    bool fl=0;
    do (k=getchar())=='-'&&(fl=1);while('9'<k||k<'0');
    while(47<k&&k<58)n=(n<<3)+(n<<1)+(k^48),k=getchar();
    return fl?-n:n;
}
# define f(i,l,r) for(int i=(l);i<=(r);++i)
# define fre(k) freopen(k".in","r",stdin);freopen(k".ans","w",stdout)
const double PI=acos(-1);
class complex{
    public:
        double x,y;
        complex(){x=y=0;}
        complex(double _x,double _y):x(_x),y(_y){}
        complex operator * (complex b){return complex(x*b.x-y*b.y,x*b.y+y*b.x);}
        complex operator + (complex b){return complex(x+b.x,y+b.y);}
        complex operator - (complex b){return complex(x-b.x,y-b.y);}
        complex operator * (double u){return complex(x*u,y*u);}
        complex& operator *= (complex b){return *this=*this*b;}
        complex& operator += (complex b){return *this=*this+b;}
        complex& operator -= (complex b){return *this=*this-b;}
};
class Array{
    private:
        vector<int>a;
    public:
        Array(){}
        void push(int n){a.push_back(n);}
        Array(int* l,int* r){while(l!=r)push(*l),++l;}
        int size(){return a.size();}
        int& operator [] (const int x){return a[x];}
};
void FFT(const int len,vector<complex>&a,const int Ty,int *r=NULL){
    if(!r){
        r=new int[len];
        r[0]=0;int L=log2(len);
        f(i,0,len-1){
            r[i]=(r[i>>1]>>1)|((i&1)<<L-1);
            if(i<r[i])swap(a[i],a[r[i]]);
        }
    }
    for(int i=1;i<len;i<<=1){
        complex T(cos(PI/i),Ty*sin(PI/i));
        for(int W=i<<1,j=0;j<len;j+=W){
            complex n(1,0);
            for(int k=0;k<i;++k,n*=T){
                complex x(a[j+k]),y(n*a[i+j+k]);
                a[j+k]=x+y;
                a[i+j+k]=x-y;
            }
        }
    }
}
Array operator * (Array x,Array y){
    int n=x.size()-1,m=y.size()-1;
    int limit=1;
    while(limit<=n+m)limit<<=1;
    vector<complex>_x(limit+1),_y(limit+1);
    Array ans;
    f(i,0,n)_x[i]=complex(x[i],0);
    f(i,0,m)_y[i]=complex(y[i],0);
    FFT(limit,_x,1);
    FFT(limit,_y,1);
    f(i,0,limit)_x[i]*=_y[i];
    FFT(limit,_x,-1);
    f(i,0,n+m)ans.push((int)(_x[i].x/limit+0.5));
    return ans;
}
void into(int n,Array &x){
    f(i,0,n)x.push(read);
}
Array x,y,ans;
int main(){
    int n=read,m=read;
    into(n,x),into(m,y);
    ans=x*y;
    f(i,0,n+m)printf("%d ",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/SYDevil/p/12051014.html

时间: 2024-08-12 00:32:32

FFT(快速傅里叶变换)的相关文章

准零基础搞懂FFT快速傅里叶变换及其实现程序(二)

上一篇文章我们了解了DFT的原理,FFT是基于DFT的更适合计算机运算的算法,本文我们就正式开始学习FFT的原理. 首先我么先来宏观的看一下FFT.如果我们把整个FFT的算法看成一个黑盒子的话,那么它的输入就是时间波形信号,比如声音波形(横轴为时间,纵轴为振幅).外什么FFT要比DFT速度更快呢?下面(图1)解释了FFT和DFT的(对于计算机的)算法复杂度 图1 从上面的数学表达式可以看出,一个1024采样点的FFT比DFT块了102.4倍.如果傅里叶变换的数量级更大,FFT的速度优势会更明显.

FFT —— 快速傅里叶变换

问题: 已知A[], B[], 求C[],使: 定义C是A,B的卷积,例如多项式乘法等. 朴素做法是按照定义枚举i和j,但这样时间复杂度是O(n2). 能不能使时间复杂度降下来呢? 点值表示法: 我们把A,B,C看作表达式. 即: A(x)=a0 + a1* x + a2 * x2 +... 将A={(x1,A(x1)), (x2,A(x2)), (x3,A(x3))...}叫做A的点值表示法. 那么使用点值表示法做多项式乘法就很简单了:对应项相乘. 那么,如何将A和B转换成点值表示法,再将C转

【Delphi】如何在三轴加速器的频谱分析中使用FFT(快速傅里叶变换)算法

关于傅里叶变换的作用,网上说的太过学术化,且都在说原理,已经如何编码实现,可能很多人有个模糊影响,在人工智能,图像识别,运动分析,机器学习等中,频谱分析成为了必备的手段,可将离散信号量转换为数字信息进行归类分析. 今天这里将的不是如何实现,而是如何使用傅里叶变换 但频谱分析中,涉及到的信号处理知识对大部分软件开发的人来说,太过于晦涩难懂,傅里叶变换,拉普拉斯,卷积,模相,实数,虚数,复数,三角函数等等,已经能让软件工程师望而却步,造成懂知识的人无法开发,懂开发的人无法分析,而同时具备两种技能的人

FFT快速傅里叶变换

摘自:https://www.cnblogs.com/RabbitHu/p/FFT.html 快速傅里叶变换(FFT)是一种能在O(nlogn)O(nlog?n)的时间内将一个多项式转换成它的点值表示的算法. 点值表示:设A(x)是一个n−1次多项式,那么把n个不同的x代入,会得到n个y.这n对(x,y)唯一确定了该多项.由多项式可以求出其点值表示,而由点值表示也可以求出多项式. 设有两个n−1次多项式A(x)和B(x)),我们的目标是——把它们乘起来.普通的多项式乘法是O(n^2),但有趣的是

【bzoj2179】FFT快速傅里叶变换(优化高精度乘法)

#include<bits/stdc++.h> using namespace std; #define pi acos(-1) typedef complex<double> C; const int N=201100; int n,m,l,r[N],ans[N]; C a[N],b[N]; char s[N],t[N]; void fft(C *a,int f){ for(int i=0;i<n;++i) if(r[i]>i) swap(a[i],a[r[i]]);

【模板】FFT快速傅里叶变换

1 struct Complex{ 2 double x, y; 3 inline Complex(double xx=0, double yy=0){ 4 x=xx; y=yy; 5 } 6 inline Complex operator + (Complex a){ 7 return Complex(x+a.x, y+a.y); 8 } 9 inline Complex operator - (Complex a){ 10 return Complex(x-a.x, y-a.y); 11 }

浅谈FFT(快速傅里叶变换)

本文主要简单写写自己学习FFT的经历以及一些自己的理解和想法. FFT的介绍以及入门就不赘述了,网上有许多相关的资料,入门的话推荐这篇博客:FFT(最详细最通俗的入门手册),里面介绍得很详细. 为什么要学习FFT呢?因为FFT能将多项式乘法的时间复杂度由朴素的$O(n^2)$降到$O(nlogn)$,这相当于能将任意形如$f[k]=\sum\limits _{i+j=k}f[i]*f[j]$的转移方程的计算在$O(nlogn)$的时间内完成.因此对于想要进阶dp的同学来说,FFT是必须掌握的技能

FFT 快速傅里叶变换

这个东西很神奇,看了半天网上的解释和课件,研究了很长时间,算是大概明白了它的原理. 话不多说先上图. 我们要求的h(x)=f(x)*g(x),f(x)=Σai*x^i,g(x)=Σbi*x^i. 朴素求复杂度是n2的,但一个x次多项式在平面上可以由x+1个点唯一插值表示,所以我们可以先用求出x+1个点(xi,f(xi))和(xi,g(xi)),再求出(xi,f(xi)*g(xi)),就可以反解出    h(x)的表达式. 那么我们需要在nlogn的时间内干完这两步,首先xi的取值需要特殊取,令x

快速傅里叶变换FFT

快速傅里叶变换FFT DFT是信号分析与处理中的一种重要变换.但直接计算DFT的计算量与变换区间长度N的平方成正比,当N较大时,计算量太大,直接用DFT算法进行谱分析和信号的实时处理是不切实际的. 1.直接计算DFT 长度为N的有限长序列x(n)的DFT为: 2.减少运算量的思路和方法 思路:N点DFT的复乘次数等于N2.把N点DFT分解为几个较短的DFT,可使乘法次数大大减少.另外,旋转因子WmN具有周期性和对称性. (考虑x(n)为复数序列的一般情况,对某一个k值,直接按上式计算X(k)值需

快速傅里叶变换(FFT)算法【详解】

快速傅里叶变换(Fast Fourier Transform)是信号处理与数据分析领域里最重要的算法之一.我打开一本老旧的算法书,欣赏了JW Cooley 和 John Tukey 在1965年的文章中,以看似简单的计算技巧来讲解这个东西. 本文的目标是,深入Cooley-Tukey  FFT 算法,解释作为其根源的“对称性”,并以一些直观的python代码将其理论转变为实际.我希望这次研究能对这个算法的背景原理有更全面的认识. FFT(快速傅里叶变换)本身就是离散傅里叶变换(Discrete