首页 > 其他分享 >FFT

FFT

时间:2024-07-11 15:18:45浏览次数:11  
标签:F1 limits 多项式 sum FFT 单位根

这东西对初中生挺友好的。


前置知识

  1. 复数
    形如 \(a+bi(a,b\in \mathbb{R})\) 的数叫复数,其中 \(i^2=-1\)。
    复数乘法:\((a+bi)(c+di)=ac-bd+(ad+bc)i\)。乘法分配律即可。

  2. 复平面
    以 \(a\) 为 \(x\) 轴,\(b\) 为 \(y\)轴所组成的平面叫复平面。每个复数都对应复平面上一点。

  3. 单位根
    以原点为圆心,\(1\) 为半径所形成的圆叫单位圆。以 \((1,0)\) 为起点,用 \(n\) 个点圆上的点将单位圆分成 \(n\) 等分。容易发现,这 \(n\) 个点正好是 \(w^n=1\) 的 \(n\) 个解。


如图为一个单位圆和一些单位根。

按角度大小记这 \(n\) 个点为 \(w_n^0,w_n^1\dots w_n^{n-1}\),当 \(n\) 为 \(2\) 的次幂时,有如下性质:

  1. \(w_n^k=-w_n^{k+\frac{n}{2}}\),也就是说他们两两互为相反数。
  2. \(w_n^k=w_n^{n+k}\),说明单位根有周期性。
  3. 当 \(n\) 个单位根平方后,他们依然是两两互为相反数。

这些性质决定了我们为什么选它来求值。


FFT

其实就是将两个多项式转化成点值表示相乘在转回来的过程。

设 \(F(x)=\sum\limits_{i=0}^m a_ix^i\),\(m\)是两个多项式相乘后的次数。默认 \(n\) 为最小的大于 \(m\) 的 \(2\) 的次幂(方便计算)。将 \(F\) 按次数奇偶分成两个函数。

\[f_0(x^2)=\sum\limits_{i=0}^{n/2-1}a_{2i}x^{i} \]

\[f_1(x^2)=\sum\limits_{i=0}^{n/2-1}a_{2i+1}x^{i} \]

\[F(x)=f_0(x^2)+xf_1(x^2) \]

显然 \(f_0,f_1\) 都是偶函数,也就是说 \(x\) 的值与 \(-x\) 是相等的。因此,我们还可以表示出

\[F(-x)=f_0(x^2)-xf_1(x^2) \]

所以要取的点和多项式的次数都变为了原来的一半,可以用递归处理。但对于 \(f_0,f_1\) 而言所有的点值都是正的,不存在相反数,无法递归。所以我们尝试寻找一些更特殊的数,单位根正好满足这个性质,因为所有单位根平方后依然是两两互为相反数的。

举个例子:

这是当 \(n=4\) 时递归的 \(x\) 值。

这是当 \(n=8\) 时的 \(x\) 值。

当递归到只剩一个常数项时,递归结束。

我们可以用相同的方式将另一个多项式的点值求出来。


当我们求出两个多项式点值并相乘后,如何将点值重新转化为系数呢?

我个人认为这很人类智慧。

设相乘后的多项式为 \(G(x)=\sum\limits_{i=0}^{n-1} b_ix^i\),将 \(w_n^0,w_n^{-1},\dots w_n^{1-n}\) 带入得到的多项式中进行 \(\text{FFT}\),再将所得的多项式的每一项除以 \(n\) 就是每一项对应的系数。

证明 :

设 \(c_k=\sum\limits_{i=0}^{n-1}b_i(w_n^{-k})^i\),将 \(b_i\) 用多项式表示 \(b_i=\sum\limits_{j=0}^{n-1}a_j(w_n^i)^j\),带入上式中

\[\begin{aligned} c_k&=\sum\limits_{i=0}^{n-1}(\sum\limits_{j=0}^{n-1}a_j(w_n^i)^j)(w_n^{-k})^i\\ &=\sum\limits_{i=0}^{n-1}\sum\limits_{j=0}^{n-1} a_j(w_n^i)^j(w_n^{-k})^i\\ &=\sum\limits_{i=0}^{n-1}\sum\limits_{j=0}^{n-1}a_j(w_n^{j-k})^i\\ &=\sum\limits_{j=0}^{n-1}a_j\sum\limits_{i=0}^{n-1}(w_n^{j-k})^i \end{aligned} \]

当 \(j=k\) 时, \(c_k=na_j\)。
当 \(j \ne k\) 时

\[\begin{aligned} \sum\limits_{i=0}^{n-1}(w_n^{j-k})^i&=\frac{(w_n^{j-k})^n-1}{w_n^{j-k}-1}\\&=\frac{(w_n^n)^{j-k}-1}{w_n^{j-k}-1}\\ &=0 \end{aligned} \]

所以,\(c_k=na_j\)。\(\frac{c_k}{n}\) 就是我们要求的系数。


至此,\(\text{FFT}\) 的所有流程都已完成。

模板题

代码(递归)

bool _Start;
#include <bits/stdc++.h>
using namespace std;
#define il inline
#define Tp template<typename T>
#define Ts template<typename T,typename... _T>
Tp il void read(T& x) {
	x=0;bool f=0;char c=getchar();
	for(;!isdigit(c);c=getchar()) f|=c=='-';
	for(;isdigit(c);c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	x=(f?-x:x);
}Ts il void read(T& x,_T&... y) {read(x),read(y...);}
using comp=complex<double>;
const double pi=acos(-1);
const int N=1<<21;
int n,m;
comp A[N],B[N];
void FFT(comp F[],int n,int tp) {
	if(n==1) return ;
	comp F0[(n>>1)+5],F1[(n>>1)+5];
	for(int i=0;i<n;i+=2)
		F0[i>>1]=F[i],F1[i>>1]=F[i+1];
	FFT(F0,n>>1,tp),FFT(F1,n>>1,tp);
	comp wn=exp(comp(0,2*pi*tp/n)),w=1;
	for(int i=0;i<(n>>1);i++,w*=wn) {
		F[i]=F0[i]+w*F1[i];
		F[i+(n>>1)]=F0[i]-w*F1[i];
	}
}
void mul(comp f[],comp g[]) {
	int lim=1;
	while(lim<=n+m) lim<<=1;
	FFT(f,lim,1),FFT(g,lim,1);
	for(int i=0;i<lim;i++) f[i]*=g[i];
	FFT(f,lim,-1);
	for(int i=0;i<lim;i++) f[i]/=lim;
}
bool _End;
int main() {
	fprintf(stderr,"Memory: %.4lf Mib\n",abs(&_End-&_Start)/1048576.0);
	read(n,m);
	for(int i=0,x;i<=n;i++) read(x),A[i]=x;
	for(int i=0,x;i<=m;i++) read(x),B[i]=x;
	mul(A,B);
	for(int i=0;i<=n+m;i++) printf("%d ",(int)(A[i].real()+0.5));
	return 0;
}


优化

balabalabala.

标签:F1,limits,多项式,sum,FFT,单位根
From: https://www.cnblogs.com/kbzcz/p/18077264/FFT

相关文章

  • 离散傅里叶变换(DFT)和快速傅里叶变换(FFT)
    离散傅里叶变换(DFT)和快速傅里叶变换(FFT)是信号处理和数字信号处理中的基本工具。它们用于将时间域的信号转换为频率域的表示,帮助分析信号的频谱成分。1.离散傅里叶变换(DFT)1.1DFT的基本概念DFT是将离散时间信号转换为频域表示的工具。对于长度为N的离散信号x[n],其DFT定义为:......
  • FFT 学习笔记
    \(\text{FFT}\)学习笔记多项式确定一个多项式,往往只需要知道每一次项前的系数是多少即可。众所周知,一个朴素的多项式往往可以被写成\[f(x)=\sum_{n\ge0}a_nx^n\]的形式,在这种形式下的两个多项式\(f,g\)的乘积\(h\)往往可以按照\[h(x)=(f*g)(x)=\sum_{n\ge0}(\sum_{i=0......
  • FFT 学习笔记
    \(\text{FFT}\)学习笔记多项式确定一个多项式,往往只需要知道每一次项前的系数是多少即可。众所周知,一个朴素的多项式往往可以被写成\[f(x)=\sum_{n\ge0}a_nx^n\]的形式,在这种形式下的两个多项式\(f,g\)的乘积\(h\)往往可以按照\[h(x)=(f*g)(x)=\sum_{n\ge0}(\sum_{i=0......
  • FFT & NTT 复习笔记
    快速变换设原多项式为\(F(x)=\sum_{i\in[0,n)}a_ix^i\),其中\(n=2^k,k\in\mathbbZ^+\)。我们要求\(\foralli\in[0,n),\hata_i=F(t_i)\),其中\(t\)是一个长度为\(n\)且两两互不相同的序列。显然\(F\)可以被一组\(\hata,t\)唯一确定,即点值表示......
  • 探索信号世界的奥秘:MATLAB中的傅里叶变换、滤波器与FFT仿真设计
    探索信号世界的奥秘:MATLAB中的傅里叶变换、滤波器与FFT仿真设计一、引言:信息技术的脉搏——信号处理二、技术概述:理论与实践的桥梁傅里叶变换滤波器设计FFT(快速傅里叶变换)代码示例:基本FFT应用三、技术细节:深入理解背后的数学原理傅里叶变换原理滤波器设计原理FFT算法解......
  • 揭开FFT时域加窗的奥秘
    FFT–SpectralLeakage假设用于ADC输出数据分析的采样点数为N,而采样率为Fs,那我们就知道,这种情况下的FFT频谱分辨率为δf,那么δf=Fs/N。如果此时我们给ADC输入一个待测量的单频Fin,如果此时Fin除以δf不是整数,就会产生频率泄露。要尽可能保证测得的FFT不会产生频谱泄露,有两......
  • FFT&hash
    1.FFT常看常新啊,比如突然发现complex比手写快!注意实部和虚部的函数分别是real()和imag()#include<bits/stdc++.h>usingnamespacestd;#definerep(i,j,k)for(inti=(j);i<=(k);++i)#definedow(i,j,k)for(inti=(j);i>=(k);--i)#defineprpair#definepbpush_back#d......
  • 27、matlab傅里叶变换:fft()函数
    1、fft 快速傅里叶变换语法Y=fft(X)使用快速傅里叶变换(FFT)算法计算X的离散傅里叶变换(DFT)。Y=fft(X,n)返回n点DFT。Y=fft(X,n,dim)返回沿维度dim的傅里叶变换。例如,如果X是矩阵,则fft(X,n,2)返回每行的n点傅里叶变换含噪信号1)原始信号加噪声......
  • 基于FPGA的图像一维FFT变换IFFT逆变换verilog实现,包含tb测试文件和MATLAB辅助验证
    目录1.算法运行效果图预览2.算法运行软件版本3.部分核心程序4.算法理论概述5.算法完整程序工程1.算法运行效果图预览fpga仿真结果matlab调用FPGA的仿真结果进行图像显示2.算法运行软件版本vivado2019.2matlab2022a3.部分核心程序..................................
  • FFT 学习笔记
    FFT学习笔记1.多项式与卷积1.1多项式对于多项式\(F(x)=a_0+a_1x+a_2x^2+a_3x^3+\dots+a_nx^n\),我们称\(a_0,a_1,\dots,a_n\)为它的系数,这种表示法叫做系数表示法。定义\(F(x)\)的\(n\)次项系数为\(f_n\)。我们有:\[F(x)=\sum_{i=0}^nf_ix^i\]1.2卷积考虑两个多......