Discrete Fourier transform
向量
其中
Inverse transform
性质:
因此
假设加减乘除时间复杂度为
注意使用的1
2
3
4
5
6reverse(a+1, a+n);
// compute DFT
for (long i = 0; i < n; i++)
a[i] *= 1.0/n;
Decimation in time FFT
Cooley-Tukey是一种radix-2分治算法,把偶数下标的子序列的Fourier
transform与奇数下标的子序列的Fourier transform,用
Decimation in time在变换之后对下标进行bitreverse操作。
使用Stockham FFT可以省去bitreverse操作。
Decimation in frequency FFT
Sande-Tukey是另一种radix-2分治算法,把前一半子序列的Fourier
transform与后一半子序列的Fourier transform,用
Decimation in frequency在变换之前对下标进行bitreverse操作。如果Decimation in time的DFT与Decimation in frequency的IDFT一起用,可以省略两处bitreverse操作。
DIF的bufferfly操作不适合fused multiply-add。
Memory-bound
FFT是memory-bound的。比较快的实现会在N较大时使用递归,而N较小时使用迭代。
Number theoretic transform
DFT可以用于复数以外的其他ring,常用于
使用128
bits模数需要高效的u64*u64%u64
,其中模数是常数。
硬件除法指令(32 bits、64 bits)
DIV
指令性能很低。
1 | extern inline u64 mul_mod(u64 a, u64 b, u64 m) |
到AVX-512也没有提供把两个64 bits乘数的积放在一个128 bits寄存器的指令,GCC没有提供用乘法、移位等模拟的u128除以u64的常量除法。
64位mantissa浮点数(32 bits、64 bits)
当模数u64*u64%u64
。
由等式
两边模
即用u64
乘法计算u64
。
round时若向上取整了,减数会大于被减数。若
1 | u64 mul_mod(u64 a, u64 b, u64 P) |
存储(long double)a*b*Q
代替(long double)a*b/P
能快些。此时
编译器生成的常量除法(32 bits)
对于固定的模u64%u32
的高效代码。llvm的lib/Transforms/Utils/IntegerDivision.cpp
。
Montgomery modular multiplication+Barret reduction(32 bits)
Faster arithmetic for number-theoretic transforms,用乘法和移位代替除法。
快速计算u64%u32
,用乘法和移位代替除法。设
因此
令if (r >= P) r -= P;
)即可修正余数。
令
1 | extern inline u64 barrett_30_2(u64 a, u64 P, u64 M) |
当模数为常量时,该算法不如编译器生成的常量除法。若模数不固定时可以考虑使用。
Cyclic convolution
两个长为
Linear convolution
两个长为
第
Zero pad原序列到长度
范围和精度
向量卷积需要注意精度问题。
使用complex<double>
计算convolution,需要保证结果每一项的实数部分在Number.MIN_SAFE_VALUE
、Number.MAX_SAFE_INTEGER
)范围内,
设每项系数的绝对值小于等于complex<double>
。
complex<double>
还要受到浮点运算误差影响。根据Roundoff
Error Analysis of the Fast Fourier Transform,没仔细看,relative
error均值为log2(n)*浮点运算精度*变换前系数最大值
,对于结果
对于模
关于精度,另外可参考https://github.com/simonlindholm/fft-precision/blob/master/fft-precision.md。
1004535809 (=479*2**21+1), 998244353 (=119*2**23+1), 897581057
(=107*2**23+1),这三个数均小于INT32_MAX
(两个+-P之间的数加减不会超出int32_t表示范围),且可表示为
设
下面考察模P多项式乘法,碰到精度问题时的两种应对方案:sqrt decomposition、Chinese remainder theorem。
方案0:sqrt decomposition(FFT, NTT)
适用于FFT与NTT。 取
适当选择
求出
如上朴素方案需要4次长为
一种优化方案是使用Toom-2 (Karatsuba)计算
容易扩展到cube root decomposition等。对于number theoretic
transform,分成
优化0:实部表示低位、虚部表示高位
FFT可以计算复数的DFT,但在朴素的多项式乘法中,FFT只作用于实数向量,虚数部分浪费了。 sqrt decomposition把一个系数拆分成两项,我们可以把两项装载到实数部分和虚数部分。 具体方法如下:
取正整数
分解
注意每一项绝对值的值域变为
右边同余于
正是我们需要的形式。
这个优化需要2次长为
优化1:正交计算两个实系数向量DFT(FFT)
这是另一种利用向量的虚数部分的方法。
换言之,计算一个复数向量的DFT,可以通过简单变换,得到实数部分向量的DFT与实数部分向量的DFT。买一送一。
分解
需要2次长为
奇偶项优化(FFT)
该优化可以和其他方式叠加。
把
偶次项