FFT与多项式乘法

article/2025/8/15 4:17:34

网上关于FFT在信号处理中应用的文章并不少,这里尽量少说废话,直接说如何用FFT实现多项式乘法。

 

多项式乘法,通常是用系数乘积的方式完成,这样的时间复杂度是O(n^2) n为多项式项数。系数乘法可以满足大多数的乘法需求,然而当位数大于1000时,此法用起来就显得捉襟见肘

通过引入FFT,我们可以将这个复杂度降到O(nlogn)

基本概念

1.多项式的两种表示法

系数表示法:即平时看到的多项式:Σi=0~n-1 a[i]*(x^i)
点值表示法:一个最高次为n-1次的多项式f(x),可以表示为n个其图像上点(x,y),例如2x^2+3x+1可以表示为(0,1) (1,6) (2,15)
两种方法可以互相转换,而点值表示法下两多项式相乘是非常方便的,只要将同一个x对应的两式y值相乘,就是新多项式对应的点值,当然,所取点值数量需要与结果多项式相符,例如:
(x+1)*(2x+1) = 2x^2+3x+1
x+1 -> (0,1) (1,2) (2,3)
2x+1 -> (0,1) (1,3) (2,5)
{(0,1) (1,2) (2,3)}*{(0,1) (1,3) (2,5)} -> (0,1) (1,6) (2,15) -> 2x^2+3x+1
而两种表示法的转换就是DFT(离散傅里叶变换,Discrete Fourier Transform)和IDFT(逆离散傅里叶变换,Inversed Discrete Fourier Transform),但是基于实数的DFT和IDFT效率仍为n^2,在此不做累述

2.复根

既然实数不行,那么我们就用性质特殊的虚数。如果读者不知道虚数,也许问题也不大,把i当成一个具有特别性质的数学符号来理解吧
在本文中,我们定义n次复根为满足x^n=1的复数x,其中n为正整数。如4次复根有4个,分别是 1,i,-1,-i。 
由欧拉公式 e^(ix)=(cos x+isin x),我们可以得到e^(2πi)=1。那么若k为整数,e^(2kπi/n)就是一个n次复根。为方便表述,我们定义w(n,k)=e^(2kπi/n)。通过欧拉公式,我们也可以将e的指数幂形式转化为我们熟知的a+bi形式(后文并不需要这个转化,这里提到是为了提醒读者:我们所说的复根仍然是普通的复数)。
复根有一些特殊性质,所以可以加速DFT和IDFT
1、w(n,2*k)=w(n/2,k) //n为偶数
2、w(n,k)=-w(n,k+n/2) //n为偶数
理解了如上性质以后,就可以开始学习FFT了

快速傅里叶变换

原理

快速傅里叶之所以快,就是因为它使用分治策略,将多项式分为奇次项和偶次项处理。
对于A(x)=a[0]+a[1]*x+a[2]*x^2+...+a[n-1]x^(n-1) //n为偶数
设O(x)=a[1]+a[3]*x+a[5]*x^2+...+a[n-1]x^(n/2-1)
E(x)=a[0]+a[2]*x+a[4]*x^2+...+a[n-2]x^(n/2-1)
则有A(x)=x*O(x^2)+E(x^2)
FFT将n次复根{w(n,0),w(n,1)...w(n,n-1)}作为点值的x,根据复根性质1,x^2=(w(n,k))^2=w(n/2,k) 于是,结合上面的式子,我们成功地将n项问题转化为了n/2项问题
那么k大于n/2时怎么办呢?由复根性质2,w(n,k-n/2)=-w(n,k) 所以w(n,k)^2=w(n,k-n/2)^2,只要计算出w(n,k-n/2)对应的O和E函数值,w(n,k)也就自然求出了,这就是所谓的蝴蝶操作
分治的终点是当n=1,y[i]=a[i]*w(1,0)=a[i],时间效率O(nlogn)
因为每次分治都需要n为偶数,n必须为2的幂,如果不足就补上系数为0的项
根据如上叙述,可以写出fft的递归实现方法,虽然后面的迭代实现更为优秀,但是强烈建议先理解递归算法,因为这是理解FFT的基础

递归快速傅里叶变换的伪代码

RECURSIVE-FFT(a)n=a.lengthif n==1return aE={a[0],a[2],...,a[n-2]} O=(a[1],a[3],...,a[n-1]}y_E=RECURSIVE-FFT(E);y_O=RECURSIVE-FFT(O);for k=0 to n/2-1w=e^(2πki/n) y[k]=y_E[k]+w*y_O[k]y[k+n/2]=y_E[k]-w*y_O[k]return y
其中a为系数向量,返回的y数组即为n次复根对应的n个值

高效FFT实现

上述代码花费了大量空间用于创建和维护数组,而我们可以使用迭代法避免这一部分的空间使用
为了迭代,首先数组被分治到的部分必须连续,观察递归调用的过程可以发现,分治是按照二进制的末位开始分类的,如n=8时,分治顺序如下
0,1,2,3,4,5,6,7
(0,2,4,6)(1,3,5,7)
(0,4)(2,6)(1,5)(3,7)
写成二进制000,100,010,110,001,101,011,111
将二进制翻转000,001,010,011,100,101,110,111这不正是0~7的单增序列吗?
原理是翻转后末位变首位,而高位恰恰决定了数的大小
于是我们递推预处理出rev数组
void get_rev(int bit)
{for(int i=0;i<(1<<bit);i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
}
然后根据rev对a重新排序,就可以进行迭代fft了,我们已知含一个元素的DFT为系数本身,那么将其按次序使用蝴蝶操作两两合并就能得到两个元素的DFT,然后再合并得到四元素DFT,以此类推,就可以得到整个式子的DFT
typedef complex<double> cd;//C++ 自带复数类,需要头文件complex
void fft(cd *a,int n)
{for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);for(int step=1;step<n;step<<=1){cd wn=exp(cd(0,PI/step));//exp:e的幂,此处计算单位根for(int j=0;j<n;j+=step<<1){cd wnk(1,0);//cd构造函数:cd(实数部分,虚数部分/i);for(int k=j;k<j+step;k++){//蝴蝶操作cd x=a[k];cd y=wnk*a[k+step];a[k]=x+y;a[k+step]=x-y;wnk*=wn;}}}
}
至此,DFT已经实现完成了,那么IDFT呢?
DFT的过程中,我们实际上相当于给系数向量a乘上了一个矩阵,如下图

那么我们只需乘上它的逆矩阵即可
可以证明,对于矩阵每一项取倒数再除以n就是该矩阵的逆矩阵
于是含IDFT的FFT代码如下,当计算DFT时传入参数1,计算IDFT时传入-1
void fft(cd *a,int n,int dft)
{for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);for(int step=1;step<n;step<<=1){cd wn=exp(cd(0,dft*PI/step));for(int j=0;j<n;j+=step<<1){cd wnk(1,0);for(int k=j;k<j+step;k++){cd x=a[k];cd y=wnk*a[k+step];a[k]=x+y;a[k+step]=x-y;wnk*=wn;}}}if(dft==-1) for(int i=0;i<n;i++) a[i]/=n;
}
最后附上FFT计算高精度乘法的代码,高精度乘法的每一位都可以看做是多项式的一个系数,只不过需要注意进位操作
 
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<complex>
using namespace std;
int n;
typedef complex<double> cd;
#define maxl 2097153
#define PI 3.14159265358979
char s1[maxl],s2[maxl];
cd a[maxl];
cd b[maxl];
int rev[maxl];
void get_rev(int bit)
{for(int i=0;i<(1<<bit);i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
}
void fft(cd *a,int n,int dft)
{for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);for(int step=1;step<n;step<<=1){cd wn=exp(cd(0,dft*PI/step));for(int j=0;j<n;j+=step<<1){cd wnk(1,0);for(int k=j;k<j+step;k++){cd x=a[k];cd y=wnk*a[k+step];a[k]=x+y;a[k+step]=x-y;wnk*=wn;}}}if(dft==-1) for(int i=0;i<n;i++) a[i]/=n;
}
int output[maxl];
int main()
{//freopen("fft.in","r",stdin);scanf("%s%s",s1,s2);int l1=strlen(s1);int l2=strlen(s2);int s=2,bit=1;for(bit=1;(1<<bit)<l1+l2-1;bit++)s<<=1;//maybe wiping the"-1" is betterfor(int i=0;i<l1;i++) a[i]=(double)(s1[l1-i-1]-'0');for(int i=0;i<l2;i++) b[i]=(double)(s2[l2-i-1]-'0');//for(int i=0;i<8;i++) printf("%d %d\n",i,rev[i]);get_rev(bit);fft(a,s,1);fft(b,s,1);for(int i=0;i<s;i++) a[i]*=b[i];fft(a,s,-1);for(int i=0;i<s;i++) {output[i]+=(int)(a[i].real()+0.5);//取实数四舍五入,此时虚数部分应当为0或由于浮点误差接近0output[i+1]+=output[i]/10;output[i]%=10;}int i;for(i=l1+l2;!output[i]&&i>=0;i--);if(i==-1) printf("0");for(;i>=0;i--) printf("%d",output[i]);putchar('\n');
}

 

http://chatgpt.dhexx.cn/article/v1F8SUIS.shtml

相关文章

多项式乘法

实验题目&#xff1a;多项式乘法问题 实验内容与要求 一元稀疏多项式简单计算器的基本功能是&#xff1a; &#xff08;1)输入并建立多项式。&#xff1b; &#xff08;2&#xff09;输出多项式&#xff0c;输出形式为整数序列&#xff1a;n,c1,e1,c2,e2,…,cn,en,其中n是多项…

多项式乘法运算终极版

在上一篇文章中 http://blog.csdn.net/acdreamers/article/details/39005227 介绍了用快速傅里叶变 换来求多项式的乘法。可以发现它是利用了单位复根的特殊性质&#xff0c;大大减少了运算&#xff0c;但是这种做法是对复数系数的矩阵 加以处理&#xff0c;每个复数系数的实…

多项式乘法(FFT)

1 前言 作为一名OI选手&#xff0c;至今未写过fft相关的博客&#xff0c;真是一大遗憾&#xff0c;这也导致我并没有真正推过fft的所有式子 这一篇fft的博客我将详细介绍多项式乘法&#xff0c;易于理解&#xff0c;主要是为了等我啥时候忘了回来看&#xff0c;当然&#xff0…

分治算法-03多项式乘法问题

多项式乘法 简介 多项式的运算表示是一个很常见的算法问题。 问题描述 给予两个多项式A(x)与B(x)&#xff0c;得出C(x)A(x)B(x)。例如&#xff0c;A(x)32x3x24x3&#xff0c;B(x)2x2&#xff0c;C(x)64x9x210x33x44x^5。 问题分析 一般情况下&#xff0c;使用系数表示多项式&a…

【数据结构】——多项式乘法

题目要求 从字符文件输入两个多项式的非零系数及对应的指数&#xff0c;建立多项式的链式存储结构&#xff0c;计算这两个多项式的乘积&#xff0c;输出乘积多项式的全部非零系数及对应的指数到另一字符文件中。 算法原理 两个多项式的乘法&#xff0c;可以借助两个多项式的…

多项式乘法(FFT)详解

本文只探讨多项式乘法(FFT)在信息学中的应用 如有错误或不明欢迎指出或提问&#xff0c;在此不胜感激 多项式 1. 系数表示法 一般应用最广泛的表示方式 用A(x)表示一个x-1次多项式&#xff0c;a[i]为 xi x i 的系数&#xff0c;则A(x) ∑n−10 ∑ 0 n − 1 a[i] * xi x i…

2.2 多项式乘法与加法运算(线性结构,C)

多项式乘法与加法运算 设计函数分别求两个一元多项式的乘积与和题意理解题意理解和积 求解思路多项式表示两种表示方式在事先已经知道具体多少项的时候&#xff0c;本题较好的实现方法&#xff1a;动态数组链表表示多项式的方法 程序框架如何读入多项式读入多项式的完整程序 加…

多项式乘法问题

多项式乘法问题 实验目的&#xff1a;设计一个一元稀疏多项式简单计算器。 实验内容与要求&#xff1a; 一元稀疏多项式简单计算器的基本功能是&#xff1a; &#xff08;1&#xff09;输入并建立多项式&#xff1b; &#xff08;2&#xff09;输出多项式&#xff0c;序列…

网络协议之视频直播核心技术讲解

网络视频直播存在已有很长一段时间&#xff0c;随着移动上下行带宽提升及资费的下调&#xff0c;视频直播被赋予了更多娱乐和社交的属性&#xff0c;人们享受随时随地进行直播和观看&#xff0c;直播的打开时间和延迟变成了影响产品功能发展重要指标。 那么&#xff0c;问题来了…

直播软件搭建技术原理:CDN 与直播

直播软件搭建技术原理&#xff1a;CDN 与直播 很多直播都是基于 CDN 来实现的。而通过声网的服务&#xff0c;或基于声网SDK与 CDN 结合&#xff0c;还可以实现在直播中的连麦互动、白板同步等强调实时性的场景。本文源自社区投稿&#xff0c;介绍了该场景下的一些基础知识。如…

暑期实习+秋招面经合集(更新ing)

大纲 开篇 自我介绍 &#xff1a;面试官你好&#xff0c;我叫林飞武&#xff0c;是一名通信工程大三学生&#xff0c;对计算机专业有着浓厚兴趣并且未来有志于在互联网的测试领域有深入发展。全套学习了计算机专业的专业课&#xff0c;计算机网络&#xff0c;操作系统等&#…

DNSPod十问王征:为什么你的网站无人问津?

&#x1f4e2; DNSPod十八周年庆将至&#xff0c;下期十问交给你来提问——《你&#xff0c;十问DNSPod》&#xff01;评论区留下你想问DNSPod团队的问题&#xff0c;一旦提问被选中&#xff0c;将得到十八周年纪念T恤&#xff01;详情请移步至DNSPod公众号十八周年庆推送。 广…

阿里云ACP认证考试笔记

课件&#xff1a;https://gitee.com/HanFerm/technical-documentation/tree/master/阿里云acp教材 本文档为公开内容 一、ACP是干嘛的 内容范围&#xff1a; 历史 二、阿里云综述 技术架构 优势 三、弹性计算 ECS ECS的组成与功能 ECS是由多个并列又相互关联的产品概念组成…

在互联网上,没有人知道你是一条狗?

1993 年&#xff0c;《纽约客》&#xff08;The New Yorker&#xff09;杂志刊登一则由彼得施泰纳&#xff08;Peter Steiner&#xff09;创作的漫画&#xff1a;标题是【On the Internet, nobody knows you’re a dog.】 这则漫画中有两只狗&#xff1a;一只黑狗站在电脑椅上…

分库分表和NewSQL如何选择?分库分表真的适合你的系统吗?

曾几何时&#xff0c;“并发高就分库&#xff0c;数据大就分表”已经成了处理 MySQL 数据增长问题的圣经。 面试官喜欢问&#xff0c;博主喜欢写&#xff0c;候选人也喜欢背&#xff0c;似乎已经形成了一个闭环。 但你有没有思考过&#xff0c;分库分表真的适合你的系统吗&am…

分库分表不一定适合你的系统,聊聊分库分表和NewSQL如何选择

曾几何时&#xff0c;“并发高就分库&#xff0c;数据大就分表”已经成了处理 MySQL 数据增长问题的圣经。 面试官喜欢问&#xff0c;博主喜欢写&#xff0c;候选人也喜欢背&#xff0c;似乎已经形成了一个闭环。 但你有没有思考过&#xff0c;分库分表真的适合你的系统吗&am…

分库分表真的适合你的系统吗?聊聊分库分表和NewSQL如何选择

曾几何时&#xff0c;“并发高就分库&#xff0c;数据大就分表”已经成了处理 MySQL 数据增长问题的圣经。 面试官喜欢问&#xff0c;博主喜欢写&#xff0c;候选人也喜欢背&#xff0c;似乎已经形成了一个闭环。 但你有没有思考过&#xff0c;分库分表真的适合你的系统吗&am…

分库分表和 NewSQL 到底怎么选?

文章来源&#xff1a;【公众号&#xff1a;CoderW】 目录 背景分表分库分库分表的成本NewSQLNewSQL 平滑接入方案NewSQL 真的有那么好吗&#xff1f;NewSQL 的应用分库分表和 NewSQL 到底怎么选&#xff1f; 背景 曾几何时&#xff0c;“并发高就分库&#xff0c;数据大就分表”…

软考初级-信息处理技术员

22年下半年也是顺利通过了软考初级-信息处理技术员&#xff0c;明年再报一次软设&#xff0c;今年上半年软设下午题没过&#xff0c;总结还是代码敲的少&#xff0c;想的太多hh&#xff0c;下面来看看我总结的上午题考点&#xff0c;非常感谢我好友老郑教我指点了我excel的函数…

学术交流 | InForSec 2023年网络空间安全国际学术研究成果分享及青年学者论坛

隐私计算研习社 InForSec定于2023年4月8日&#xff5e;9日&#xff08;周六、日&#xff09;在南方科技大学举办“InForSec 2023年网络空间安全国际学术研究成果分享及青年学者论坛”。本次学术活动将邀请在网络空间安全顶级会议上发表论文的研究者分享他们的最新研究成果&…