FFT的迭代程序实现——hdu1402

2024-06-22 18:58

本文主要是介绍FFT的迭代程序实现——hdu1402,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    《快速傅里叶变换FFT的迭代实现》描述了最简单的FFT的迭代实现,在此基础上可以用它进行大整数乘法或者多项式乘法。不过,还需要考虑IDFT的快速实现。IDFT有2种实现方式。第一种仿照FFT,观察IDFT的定义式,和DFT的定义本质上没有区别,利用单位复根的性质可以写出IFFT。第二种方法则利用共轭的性质:


      即:逆变换等于共轭的变换的共轭,所以可以复用FFT的实现代码。关键算法确定后,还要实现诸如确定补齐长度、位倒置、复数运算、输入输出转换等具体问题。hdu1402,用FFT做大数乘法。

     当然,这个程序还有很多可以优化的地方,在循环控制等方面,优化以后的效果也相当显著。大家可以去UOJ的模板题看看跑的最快的FFT是怎么写的。


#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;#define EPS 1E-6
#define is0(x) ( -EPS < (x) && (x) < EPS )double const PI = acos(-1.0);//定义复数及其运算
struct complex_t{double real;double imag;complex_t(double a=0.0,double b=0.0):real(a),imag(b){}complex_t(complex_t const&rhs):real(rhs.real),imag(rhs.imag){}
};complex_t operator + (complex_t const&lhs,complex_t const&rhs){return complex_t( lhs.real + rhs.real, lhs.imag + rhs.imag );
}complex_t operator - (complex_t const&lhs,complex_t const&rhs){return complex_t( lhs.real - rhs.real, lhs.imag - rhs.imag );
}complex_t operator * (complex_t const&lhs,complex_t const&rhs){return complex_t(lhs.real * rhs.real - lhs.imag * rhs.imag,lhs.real * rhs.imag + lhs.imag * rhs.real);
}//定义全局数组
#define SIZE 65536
int Size = 0;
char A[SIZE];
char B[SIZE];
char C[SIZE+SIZE] = {'\0'};
complex_t Xa[SIZE+SIZE],Ya[SIZE+SIZE];
complex_t Xb[SIZE+SIZE],Yb[SIZE+SIZE];
complex_t Xc[SIZE+SIZE],Yc[SIZE+SIZE];//将字符串转为复数序列,n为序列长度,非字符串长度
void string2Complex(char const s[],int n,complex_t c[]){fill(c,c+n,complex_t());int len = strlen(s);for(int i=0;s[i];++i){c[i].real = (double)(s[len-1-i]-'0');}return;
}//雷德算法,调整系数位置,n为数组长度,从0开始
void Rader(complex_t const a[],int n,complex_t b[]){copy(a,a+n,b);for(int i=1,j=n>>1,k;i<n-1;++i){if ( i < j ) swap(b[i],b[j]);k = n >> 1;while( j >= k ) j -= k, k >>= 1;if ( j < k ) j += k;}
}//FFT,n为序列长度
void FFT(complex_t const x[],int n,complex_t y[]){Rader(x,n,y);//最外层循环for(int i=1;(1<<i)<=n;++i){int m = 1 << i;complex_t wm(cos(2.0*PI/(double)m),-sin(2.0*PI/(double)m));//中间循环n/m次for(int j=0;j<n;j+=m){complex_t w(1.0);for(int k=0;k<(m>>1);++k){complex_t t( w * y[j+k+m/2] );complex_t u(y[j+k]);y[j+k] = u + t;y[j+k+m/2] = u - t;w = w * wm;}}}
}int main(){while( EOF != scanf("%s%s",A,B) ){//确定序列长度int la = strlen(A);int lb = strlen(B);Size = la + lb;for(int i=0;;++i){if( Size <= (1<<i) ){Size = 1<<i;break;}}//转换string2Complex(A,Size,Xa);string2Complex(B,Size,Xb);//FFTFFT(Xa,Size,Ya);FFT(Xb,Size,Yb);//逐项乘,顺便共轭for(int i=0;i<Size;++i){Yc[i] = Ya[i] * Yb[i];Yc[i].imag = - Yc[i].imag;}//FFTFFT(Yc,Size,Xc);Xc[Size].real = 0.0;//再对Xc共轭除以N得到结果,但此处只关心实部for(int i=0;i<Size;++i) Xc[i].real /= (double)Size;//将复数序列转化为合理的输出int carry = 0;int head = SIZE + SIZE - 2;for(int i=0;i<Size;++i){int t = (int)(Xc[i].real + 0.5) + carry;C[SIZE+SIZE-2-i] = (char)(t % 10) + '0';if ( t % 10 ) head = SIZE + SIZE - 2 - i;carry = t / 10;}if ( carry ) head = SIZE + SIZE - 1 - Size;while( carry ){--head;C[head] = '0' + (char)(carry%10);carry /= 10;}printf("%s\n",C+head);}return 0;
}


这篇关于FFT的迭代程序实现——hdu1402的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1085133

相关文章

Mybatis从3.4.0版本到3.5.7版本的迭代方法实现

《Mybatis从3.4.0版本到3.5.7版本的迭代方法实现》本文主要介绍了Mybatis从3.4.0版本到3.5.7版本的迭代方法实现,包括主要的功能增强、不兼容的更改和修复的错误,具有一定的参考... 目录一、3.4.01、主要的功能增强2、selectCursor example3、不兼容的更改二、

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

多线程篇(阻塞队列- LinkedBlockingDeque)(持续更新迭代)

目录 一、LinkedBlockingDeque是什么 二、核心属性详解 三、核心方法详解 addFirst(E e) offerFirst(E e) putFirst(E e) removeFirst() pollFirst() takeFirst() 其他 四、总结 一、LinkedBlockingDeque是什么 首先queue是一种数据结构,一个集合中

多线程篇(阻塞队列- LinkedBlockingQueue)(持续更新迭代)

目录 一、基本概要 1. 构造函数 2. 内部成员 二、非阻塞式添加元素:add、offer方法原理 offer的实现 enqueue入队操作 signalNotEmpty唤醒 删除线程(如消费者线程) 为什么要判断if (c == 0)时才去唤醒消费线程呢? 三、阻塞式添加元素:put 方法原理 图解:put线程的阻塞过程 四、非阻塞式移除:poll方法原理 dequ

六、我们应当怎样做需求调研:迭代

前面我一直在反复强调这样一个观点,需求分析不是一蹴而就的,是一个反复迭代的过程。它将从第一次需求分析开始,一直持续到整个项目生命周期。为什么这样说呢?让我们一起来分析分析。  在第一次的需求分析阶段,我们在一段时期内需要与客户进行反复地讨论,这个过程往往是这样一个反复循环的过程:需求捕获->需求整理->需求验证->再需求捕获••••••  需求捕获,就是我们与客户在一起开研讨会

多线程篇(阻塞队列- ArrayBlockingQueue)(持续更新迭代)

目录 一、源码分析 1. 先看个关系图 2. 构造方法 3. 核心属性 4. 核心功能 入队(放入数据) 出队(取出数据) 5. 总结 一、源码分析 1. 先看个关系图 PS:先看个关系图 ArrayBlockingQueue是最典型的有界阻塞队列,其内部是用数组存储元素的, 初始化时需要指定容量大小利用 ReentrantLock 实现线程安全。 在生产者

多线程篇(并发相关类- 原子操作类)(持续更新迭代)

目录 前言 一、原子变量操作类(AtomicLong为例) 1. 前言 2. 实例 二、JDK 8新增的原子操作类LongAdder 三、LongAccumulator类原理探究 前言 JUC包提供了一系列的原子性操作类,这些类都是使用非阻塞算法CAS实现的,相比使用锁实现原子性操作这在性能上有很大提高。 由于原子性操作类的原理都大致相同,这里讲解最简单的AtomicLo

PMP–一、二、三模–分类–14.敏捷–技巧–帮助团队交付价值的执行实践迭代和增量如何帮助交付工作产品

文章目录 技巧一模14.敏捷--实践--帮助团队交付价值的执行实践--持续集成--在不同层面测试、验收测试驱动开发 (ATDD) 、测试驱动开发和行为驱动开发、刺探 。90、 [单选] 敏捷项目的第一次迭代即将开始。发起人召集团队、Scrum主管、产品负责人和其他项目干系人参加启动会议。发起人强调需要在项目尽可能早的时候以最小的成本识别和应对项目风险。与会者实现发起人要求的最佳方式是什么?

设计模式-行为型模式-迭代器模式

1.迭代器模式的定义         迭代器模式提供一种对容器对象中的各个元素进行访问的方法,而不需要暴露该对象的内部细节;         在软件系统中,容器对象有两个职责:一是存储数据,二是遍历数据;从依赖性上看,前者是基本职责,而后者是可以变化的,又是可以分离的,因此可以将遍历数据的行为从容器中抽取出来,封装到迭代器对象中,由迭代器来提供遍历数据的行为,这将简化聚合对象的设计,更加符合单