自从去年下半年接触三维重构以来,听得最多的词就是傅立叶变换,后来了解到这个变换在图像处理里面也是重点中的重点。

本身自己基于高数知识的理解是傅立叶变换是将一个函数变为一堆正余弦函数的和的变换。而图像处理里则强调它是将图像信息从空间域往频率域转化的重要手段。最近从头学起数字图像处理,看完傅立叶变换之后,对于其中的计算方法快速傅立叶变换产生了好奇。于是搜索了下FFT,发现杭电上有几个这样的题目,其中点击率最高的是hdu1402*大数乘法。

大数乘法本来是一个n方的算法,经过FFT之后可以变为nlogn,于是看了下算法导论中多项式与FFT一节,大致弄清楚了FFT的原理和简单实现。

1.多项式的两种表示:系数表示和点对表示,两种表示之间可以互相转化,一个叫做赋值,一个叫做插值,插值是一个解带有克里蒙德行列式的过程。

2.为了让多项式乘法更快进行,可以选取一些特殊的数值作为赋值,这些特殊数值就是单位复根。

3.单位复根有相消引理和折半引理,这些可以使赋值以及插值的时间复杂度降低

4.以某个单位复根代入多项式得到的表达式就是离散傅立叶变换。(向量->数值)

5.继续分析多项式表示,可以引出一个蝴蝶操作,以及利用一个二进制平摊反转置换的预处理,使FFT可以迭代进行。

6.同时逆FFT可以采用和FFT相同的方式实现。

7.大数乘法可以看成两个多项式相乘,然后令变量为10的结果。

自学一个新的算法其实最容易的入门方式就是找一组数据试一试,在计算(1,2,3,4)的离散傅里叶变换之后自己就更清楚为什么蝴蝶操作是可以进行的。

假设两个4321相乘,那么n扩展为8

1.fft数组初始化就是(1,2,3,4,0,0,0,0)。而目的是求出()这个对应的值

2.以wn0为例:

系数形成的树如下:

第一次进行n=2的傅里叶变换之后,系数如下:

第二次进行n=4的傅里叶变换之后,系数如下:

而在这步变化里同时体现了蝶形操作:(k)与(k+n/2的关系)

hdu1402:---代码实现:

#include <iostream>
#include <cmath>
#include <string.h>
using namespace std;
#define N 200005
#define PI acos(-1.0)
struct complex
{
double r,i;
complex(double real=0.0,double image=0.0)
{
r=real;
i=image;
}
//以下为三种虚数运算的定义
complex operator+(const complex o)
{
return complex(r+o.r,i+o.i);
}
complex operator-(const complex o)
{
return complex(r-o.r,i-o.i);
}
complex operator*(const complex o)
{
return complex(r*o.r-i*o.i,r*o.i+i*o.r);
}
}x1[N],x2[N];
char a[N/],b[N/];
int sum[N]; //结果存在sum里 void bitrev(complex *y,int l) //二进制平摊反转置换 O(logn)
{
register int i,j,k;
for(i=,j=l/;i<l-;i++)
{
if(i<j) swap(y[i],y[j]); //交换互为下标反转的元素
//i<j保证只交换一次
k=l/;
while(j>=k) //由最高位检索,遇1变0,遇0变1,跳出
{
j-=k;
k/=;
}
if(j<k) j+=k;
}
}
void fft(complex *in,int n)
{
int i,j,k;
complex u,t;
bitrev(in,n);
for(int i=;i<=n;i=i*)
{
complex wn(cos((*PI)/i),sin((*PI)/i));//初始化单位复根
for(j=;j<n;j=j+i)
{
complex w(,);
for(k=j;k<j+i/;k++)
{
u=in[k];
t=w*in[k+i/];
in[k]=u+t;
in[k+i/]=u-t;
w=w*wn;
}
}
}
}
void antifft(complex *in,int n)
{
complex x,y;
int i,j,k;
bitrev(in,n);
for(int i=;i<=n;i=i*)
{
complex init(cos((*PI*-)/i),sin((*PI*-)/i));
for(j=;j<n;j=j+i)
{
complex w(,);
for(k=j;k<j+i/;k++)
{
x=in[k];
y=w*in[k+i/];
in[k]=x+y;in[k+i/]=x-y;
w=w*init;
}
}
}
for(int i=;i<n;i++)
in[i]=in[i].r/n;
} int main() { while(~scanf("%s%s",a,b))
{
//提取系数并逆序
int na=strlen(a);
int nb=strlen(b); int n=;
//expand while(n<na* || n<nb*) n=n*; //将次数界变成2^n
for(int i=na-;i>=;i--)
{
x1[na--i].r=a[i]-'';x1[na--i].i=;
} for(int i=nb-;i>=;i--)
{
x2[nb--i].r=b[i]-'';x2[nb--i].i=;
} for(int i=na;i<n;i++)
{
x1[i].i=;x1[i].r=;
}
for(int i=nb;i<n;i++)
{
x2[i].i=;x2[i].r=;
} //分别傅里叶变换
fft(x1,n);
fft(x2,n);
//点值相乘得到新的傅里叶变换数值
for(int i=;i<n;i++)
x1[i]=x1[i]*x2[i];
//逆傅里叶变换得到系数,*10求和
antifft(x1,n);
memset(sum,,sizeof(sum));
//四舍五入
for(int i=;i<n;i++)
sum[i]=x1[i].r+0.5;
for(int i=;i<n;i++) //进位
{
sum[i+]+=sum[i]/;
sum[i]%=;
}
while(sum[n]<= && n>) n--; //检索最高位 for(int i=n;i>=;i--)
putchar(sum[i]+''); //倒序输出
printf("\n");
}
return ; }

代码参照:http://blog.csdn.net/u011328276/article/details/10020723

PS:csdn这份代码没有每次将sum初始化,有时会造成错误结果。

Accepted 1402 375MS 7492K 3484 B G++

离散傅立叶变换与快速傅立叶变换(DFT与FFT)的更多相关文章

  1. 为什么要进行傅立叶变换?傅立叶变换究竟有何意义?如何用Matlab实现快速傅立叶变换

    写在最前面:本文是我阅读了多篇相关文章后对它们进行分析重组整合而得,绝大部分内容非我所原创.在此向多位原创作者致敬!!!一.傅立叶变换的由来关于傅立叶变换,无论是书本还是在网上可以很容易找到关于傅立叶 ...

  2. $\mathcal{FFT}$·$\mathcal{Fast \ \ Fourier \ \ Transformation}$快速傅立叶变换

    \(2019.2.18upd:\) \(LINK\) 之前写的比较适合未接触FFT的人阅读--但是有几个地方出了错,大家可以找一下233 啊-本来觉得这是个比较良心的算法没想到这么抽搐这个算法真是将一 ...

  3. 快速傅立叶变换(FFT)

    多项式 系数表示法 设\(f(x)\)为一个\(n-1\)次多项式,则 \(f(x)=\sum\limits_{i=0}^{n-1}a_i*x_i\) 其中\(a_i\)为\(f(x)\)的系数,用这 ...

  4. 快速傅立叶变换(FFT)算法

    已知多项式f(x)=a0+a1x+a2x2+...+am-1xm-1, g(x)=b0+b1x+b2x2+...+bn-1xn-1.利用卷积的蛮力算法,得到h(x)=f(x)g(x),这一过程的时间复 ...

  5. BZOJ 2194 快速傅立叶变换之二 | FFT

    BZOJ 2194 快速傅立叶变换之二 题意 给出两个长为\(n\)的数组\(a\)和\(b\),\(c_k = \sum_{i = k}^{n - 1} a[i] * b[i - k]\). 题解 ...

  6. NVIDIA GPU的快速傅立叶变换

    NVIDIA GPU的快速傅立叶变换 cuFFT库提供GPU加速的FFT实现,其执行速度比仅CPU的替代方案快10倍.cuFFT用于构建跨学科的商业和研究应用程序,例如深度学习,计算机视觉,计算物理, ...

  7. FFT快速傅立叶变换的工作原理

    实数DFT,复数DFT,FFTFFT是计算DFT的快速算法,但是它是基于复数的,所以计算实数DFT的时候需要将其转换为复数的格式,下图展示了实数DFT和虚数DFT的情况,实数DFT将时域中N点信号转换 ...

  8. 【CodeVS 3123】高精度练习之超大整数乘法 &【BZOJ 2197】FFT快速傅立叶

    第一次写法法塔,,,感到威力无穷啊 看了一上午算导就当我看懂了?PS:要是机房里能有个清净的看书环境就好了 FFT主要是用了巧妙的复数单位根,复数单位根在复平面上的对称性使得快速傅立叶变换的时间复杂度 ...

  9. BZOJ_2179_FFT快速傅立叶_(FFT)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=2179 超大整数乘法 分析 FFT模板题. 把数字看成是多项式,x是10.然后用FFT做多项式乘 ...

随机推荐

  1. 微软正式公布Visual Studio 2013 Update 3 (2013.3) RTM

     昨天微软的Visual Studio 2013 Update 3(Visual Studio 2013.3)正式公布(RTM)了,做为微软认证金牌合作的葡萄城控件,我们组织力量第一时间进行翻译. ...

  2. HDU 1796 容斥原理 How many integers can you find

    题目连接   http://acm.hdu.edu.cn/showproblem.php?pid=1796 处男容斥原理  纪念一下  TMD看了好久才明白DFS... 先贴代码后解释 #includ ...

  3. redis研究笔记

    本文链接:http://blog.csdn.net/u012150179/article/details/38077851 一. redis Redis is an in-memory databas ...

  4. 浅谈web前端开发阅历

    WEB前端研发工程师,在国内算是一个朝阳职业,这个领域没有学校的正轨教育,大多数人都是靠本人自学成才.本文次要引见本人从事web开发以来(从大二至今)看过的书籍和本人的成长过程,目的是给想了解Java ...

  5. ThinkPHP - 组织分类结构

  6. WPF自学笔记

    WPF使用哪几种元素作为顶级元素: 1. Window元素 2. Page元素(与Window元素类似,用于可导航的应用程序) 3. Application元素(定义应用程序资源和启动设置) PS:在 ...

  7. 新技能get: 使用whois查询不明网址的信息

    1.站长之家-->Whois反查 http://whois.chinaz.com/ 进入whois.chinaz.com,输入要查询的网址,选择查询即可.

  8. C++的发展,特点和源程序构成

    最近一段时间在学习C++,也借了几本相关的书籍.因为之前主要用C#写程序,大概写了也有两年了吧.所以在回过头来学习C++,还是挺快的.但是我觉得光看书是不行的,要写!!因此我想把我整个学习C++的过程 ...

  9. /etc/group文件详解

    Linux /etc/group文件与/etc/passwd和/etc/shadow文件都是有关于系统管理员对用户和用户组管理时相关的文件.linux /etc/group文件是有关于系统管理员对用户 ...

  10. 关于Spring的BeanPostProcessor

    BeanPostProcessor接口作用是:如果我们需要在Spring容器完成Bean的实例化.配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProcess ...