离散傅立叶变换与快速傅立叶变换(DFT与FFT)
自从去年下半年接触三维重构以来,听得最多的词就是傅立叶变换,后来了解到这个变换在图像处理里面也是重点中的重点。
本身自己基于高数知识的理解是傅立叶变换是将一个函数变为一堆正余弦函数的和的变换。而图像处理里则强调它是将图像信息从空间域往频率域转化的重要手段。最近从头学起数字图像处理,看完傅立叶变换之后,对于其中的计算方法快速傅立叶变换产生了好奇。于是搜索了下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)的更多相关文章
- 为什么要进行傅立叶变换?傅立叶变换究竟有何意义?如何用Matlab实现快速傅立叶变换
写在最前面:本文是我阅读了多篇相关文章后对它们进行分析重组整合而得,绝大部分内容非我所原创.在此向多位原创作者致敬!!!一.傅立叶变换的由来关于傅立叶变换,无论是书本还是在网上可以很容易找到关于傅立叶 ...
- $\mathcal{FFT}$·$\mathcal{Fast \ \ Fourier \ \ Transformation}$快速傅立叶变换
\(2019.2.18upd:\) \(LINK\) 之前写的比较适合未接触FFT的人阅读--但是有几个地方出了错,大家可以找一下233 啊-本来觉得这是个比较良心的算法没想到这么抽搐这个算法真是将一 ...
- 快速傅立叶变换(FFT)
多项式 系数表示法 设\(f(x)\)为一个\(n-1\)次多项式,则 \(f(x)=\sum\limits_{i=0}^{n-1}a_i*x_i\) 其中\(a_i\)为\(f(x)\)的系数,用这 ...
- 快速傅立叶变换(FFT)算法
已知多项式f(x)=a0+a1x+a2x2+...+am-1xm-1, g(x)=b0+b1x+b2x2+...+bn-1xn-1.利用卷积的蛮力算法,得到h(x)=f(x)g(x),这一过程的时间复 ...
- BZOJ 2194 快速傅立叶变换之二 | FFT
BZOJ 2194 快速傅立叶变换之二 题意 给出两个长为\(n\)的数组\(a\)和\(b\),\(c_k = \sum_{i = k}^{n - 1} a[i] * b[i - k]\). 题解 ...
- NVIDIA GPU的快速傅立叶变换
NVIDIA GPU的快速傅立叶变换 cuFFT库提供GPU加速的FFT实现,其执行速度比仅CPU的替代方案快10倍.cuFFT用于构建跨学科的商业和研究应用程序,例如深度学习,计算机视觉,计算物理, ...
- FFT快速傅立叶变换的工作原理
实数DFT,复数DFT,FFTFFT是计算DFT的快速算法,但是它是基于复数的,所以计算实数DFT的时候需要将其转换为复数的格式,下图展示了实数DFT和虚数DFT的情况,实数DFT将时域中N点信号转换 ...
- 【CodeVS 3123】高精度练习之超大整数乘法 &【BZOJ 2197】FFT快速傅立叶
第一次写法法塔,,,感到威力无穷啊 看了一上午算导就当我看懂了?PS:要是机房里能有个清净的看书环境就好了 FFT主要是用了巧妙的复数单位根,复数单位根在复平面上的对称性使得快速傅立叶变换的时间复杂度 ...
- BZOJ_2179_FFT快速傅立叶_(FFT)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=2179 超大整数乘法 分析 FFT模板题. 把数字看成是多项式,x是10.然后用FFT做多项式乘 ...
随机推荐
- 使用python网络库下载
下载1000次网页资源 1,普通循环方式下载1000次,非常慢 #!/usr/bin/python # -*- coding: utf-8 -*- import sys import os impor ...
- QQ聊天原理初识
1:qq之间文件的传输是通过p2p通信进行的. 2:qq之间的表情发送实际上就是文字的发送,是client再接受到文字之后在本地自己进行转换 3:qq之间的通信既能够通过udp也能够通过Tcp 尽管u ...
- 设计模式的C++实现 2.工厂模式
工厂模式,实例化对象,用工厂方法取代new操作. 工厂模式基本与简单工厂模式差点儿相同,简单工厂中每次加入一个子类必须在工厂类中加入一个推断分支,这违背了开闭原则.而工厂模式的解决方法是将简单工厂中的 ...
- poj 3128 Leonardo's Notebook(置换的幂)
http://poj.org/problem?id=3128 大致题意:输入一串含26个大写字母的字符串,能够把它看做一个置换.推断这个置换是否是某个置换的平方. 思路:具体解释可參考url=ihxG ...
- MVC3 验证码
public ActionResult GetValidateCode() { string code = CreateValidateC ...
- ADO.NET(一)
- Axure使用
(一) Axure rp的界面 1-主菜单工具栏 大部分类似office软件,不做详细解释,鼠标移到按钮上都有对应的提示. 2-主操作界面 绘制产品原型的操作区域,所有的用到的元件都拖到该区域. 3 ...
- seajs + easyui [转]
* *content seajs+easyui使用 */ /** * 首先来看看在seajs中jquery和jquery插件如何使用 */ 1.jquery.js define(function(re ...
- Ubuntu中文输入法
这里是Ubuntu12.04,刚把系统语言设成英文,发现输入法没有了. 看看下面是如何找回来的吧. Ubuntu上的输入法主要有小小输入平台(支持拼音/二笔/五笔等),Fcitx,Ibus,Scim等 ...
- Visual Studio调试技巧 -- Attach to Process #Reprinted#
from:http://www.cnblogs.com/lyosaki88/p/3481338.html 一般写完代码时,我们通常会启动调试运行一下看看是否正确,启动运行的方式无非是F5-- Star ...