FFTNTT代码技巧

这篇博客是拿来解释FFT模板中那些过度压行的产物的。
1.

int& upd(int &x){ return x+=x>>31&mod; }

所有负数 x > > 31 x>>31 x>>31后为 − 1 -1 1
所以这个是快速将负数加上一个 m o d    \mod {} mod
为啥搞负数?
因为我们可以在每次加法后 − m o d -mod mod,减法后不管,然后调用这个函数。
这个也可以用在乘负数,模完之后再把负的答案调回正的,
反正大家的加法取模优化都要非负环境。

2.预处理单位根

	w[Wl] = 1;
	rep(i,Wl+1,Wl2-1) w[i] = 1ll * w[i-1] * pw % mod;
	per(i,Wl-1,1) w[i] = w[i<<1];

因为就算我们需要n次单位根,但是只需要一半。
所以我们就把 n n n次单位根存在 [ n 2 , n − 1 ] [\frac n2,n-1] [2n,n1]的位置上。
对于 n 2 \frac n2 2n次单位根等也同理。

3.NTT的 u n s i g n e d   l o n g   l o n g \rm unsigned\ long\ long unsigned long long 优化

void NTT(int *A,int n,int tp){
	static int r[maxn];
	static unsigned long long a[maxn];
	if(tp^1) reverse(A+1,A+n);
	rep(i,0,n-1) r[i] = r[i>>1]>>1|(i&1)<<lg[n]-1,a[i] = (A[r[i]] += A[r[i]] >> 31 & mod);
	for(int L=1;L<n;L<<=1) for(int s=0,L2=L<<1;s<n;s+=L2) for(int k=s,x=L,t;k<s+L;k++,x++)
		t=w[x]*a[k+L]%mod,a[k+L]=a[k]-t+mod,a[k]+=t;
	rep(i,0,n-1) A[i] = a[i] % mod;
	if(tp^1) rep(i,0,n-1) A[i] = 1ll * A[i] * inv[n] % mod; 
}

首先如果是 I D F T IDFT IDFT,我们可以翻转数组后做,这是因为 ω n i = − ω n n − i \omega_n^i = -\omega_n^{n-i} ωni=ωnni
刚好是我们需要的变换,这样我们就只需要一半的单位根即可完成 D F T DFT DFT
多写写 F F T FFT FFT就可以发现是可以简化到循环内只有3条加减乘除语句的。
一次乘法,两次加减。
可以使用函数优化加减取模,但这还是不够快。
可以使用 u n s i g n e d   l o n g   l o n g \rm unsigned\ long\ long unsigned long long后加减完全不模。
但是这个方法有点险但是实际上很稳。
因为模数都是 998244353 998244353 998244353
分析一下加减对于每个数都只有 O ( log ⁡ n ) O(\log n) O(logn)次,我们把这个数字在下面估计为 20 20 20
那么最坏情况,
在乘法的时候,可以造成一个 998244353 × ( 998244353 log ⁡ n ) = 19929835765927772180 > 2 64 = 18446744073709551616 998244353 \times (998244353 \log n) = 19929835765927772180 > 2^{64} = 18446744073709551616 998244353×(998244353logn)=19929835765927772180>264=18446744073709551616
位数太多不直观,我们取个 log ⁡ 10 \log_{10} log10
log ⁡ 10 19929835765927772180 = 19.29950371986229427535856388548 \log_{10}19929835765927772180 =19.29950371986229427535856388548 log1019929835765927772180=19.29950371986229427535856388548
log ⁡ 10 18446744073709551616 = 19.265919722494796493679289262368 \log_{10}18446744073709551616 = 19.265919722494796493679289262368 log1018446744073709551616=19.265919722494796493679289262368
毫厘之差。
但是,单位根是均匀分布的。
F F T FFT FFT的蝴蝶变换是复杂的。
所以平均情况下大概的平均数值要在上面的基础上 ÷ 4 \div 4 ÷4,也就是开 l o n g   l o n g \rm long\ long long long就行的范围。
但是这只是平均, n n n个位置都经过 log ⁡ \log log轮变换后炸 l o n g   l o n g \rm long \ long long long的概率还是很高的( n = 10000 n=10000 n=10000都能炸)。
最坏情况的平均值应该是在 19929835765927772180 ÷ 2 19929835765927772180 \div 2 19929835765927772180÷2
因为每次加减的数有均匀的单位根加权,大概只会加一半。
但是经过实际测试最坏情况的测试最大值和 n n n大概有如下关系:
n = 10000 n = 10000 n=10000时 , 1.1 × 2 63 1.1 \times 2^{63} 1.1×263
n = 100000 n = 100000 n=100000时 , 1.3 × 2 63 1.3\times 2^{63} 1.3×263
n = 1000000 n = 1000000 n=1000000时 , 1.6 × 2 63 1.6\times 2^{63} 1.6×263
再大就超过 F F T FFT FFT的适用范围了。
注意这个是最坏情况的测试最大值,也就是随机了很多组也构造了很多组(但是构造的数据并没有比随机的强很多)后最坏情况的最大值。
实际上用这个方法写个仙人掌计数跑 1 e 5 1e5 1e5可以跑进 0.5 s 0.5s 0.5s
有图为证,目前为 r k 2 rk2 rk2
在这里插入图片描述
实际上理论最坏的情况比我们的最大容忍值只大了一丁点,实际运行(我真的认为)毫无问题。
事实上 2 64 99824435 3 2 = 18.51168699066378905130903454712 \frac {2^{64}}{998244353^2} = 18.51168699066378905130903454712 9982443532264=18.51168699066378905130903454712
这, 1 e 5 1e5 1e5是不会出任何问题的,只要你不把 > 998244353 >998244353 >998244353的数拿进去 N T T NTT NTT

大于 3 e 5 3e5 3e5的多项式题在如今高级算法迭起,动不动 O ( n log ⁡ n ) O(n\log n) O(nlogn) 3 s 3s 3s O I OI OI界是真的不会有太多的。
所以我会一直用这个方法来写我的多项式题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FPGA FFT(Field Programmable Gate Array Fast Fourier Transform)是一种基于FPGA的快速傅里叶变换算法的实现。FPGA是一种可重新配置的硬件设备,可以根据需要重新编程来实现不同的功能和算法。 FPGA FFT的源代码是指实现FFT算法所需的硬件描述语言(如VHDL或Verilog)代码。该代码将定义FFT算法的各个模块和数据流,以及控制器逻辑,用于在FPGA上实现FFT运算。 该源代码通常包括以下模块: 1. 快速傅里叶变换模块(FFT Module):该模块用于将输入信号进行FFT变换,并输出变换后的频谱数据。 2. 数据缓存模块(Data Buffer Module):该模块用于存储输入信号和变换结果的中间数据。在FFT运算中,需要对输入信号进行重排列和临时存储,以便进行分阶段的计算。 3. 控制器模块(Controller Module):该模块用于控制整个FFT算法的执行过程。它包括时钟控制、数据输入输出控制和模块之间的数据流控制。 4. 时序逻辑和数据通路:该部分代码描述了各个模块之间的时钟信号和数据传输路径,确保各个模块按照正确的时序进行计算和通信。 FPGA FFT代码需要根据具体的FFT算法和硬件平台进行设计和实现。代码的编写需要对FFT算法和硬件描述语言有一定的了解,同时也需要具备硬件设计和调试的能力。使用合适的开发工具和仿真环境,可以对代码进行调试和验证,确保其在目标FPGA上能够正确运行。 总结起来,FPGA FFT代码是一种用于实现FFT算法的硬件描述语言代码,它的设计和实现需要对FFT算法、硬件平台和硬件描述语言有一定的了解和经验。通过编写和调试源代码,可以在FPGA上实现FFT运算,用于信号处理、通信系统等应用中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值