NTT就是对FFT进行了改进,上一篇中讲了FFT,可以看到FFT所用的单位根 w n k w_n^k wnk 的实部和虚部都是通过正弦和余弦函数计算而来的,所以不可避免地会有很多浮点数运算
所以NTT就是在整数范围内寻找和单位根有相同性质的那些数,可以提升计算的精度
这种整数被找到了,就是原根
对于一个正整数 n,小于等于 n 且与 n 互质的正整数的个数,记作 φ ( n ) \varphi(n) φ(n),有
φ ( x ) = x ( 1 − 1 P ( 1 ) ) ( 1 − 1 P ( 2 ) ) . . . . . . ( 1 − 1 P ( n ) ) \varphi(x) = x(1 - \frac{1}{P(1)})(1 - \frac{1}{P(2)})......(1 - \frac{1}{P(n)}) φ(x)=x(1−P(1)1)(1−P(2)1)......(1−P(n)1)其中 P ( k ) P(k) P(k) 为 x x x 的质因数,且相同的 P ( k ) P(k) P(k) 只会出现一次
如:
φ ( 99 ) = 99 × ( 1 − 1 3 ) × ( 1 − 1 11 ) = 60 φ ( 15 ) = 99 × ( 1 − 1 3 ) × ( 1 − 1 5 ) = 8 \begin{aligned} \varphi(99) &= 99 ×(1 - \frac{1}{3})×(1 - \frac{1}{11}) \\ &= 60 \\ \varphi(15) &= 99 ×(1 - \frac{1}{3})×(1 - \frac{1}{5}) \\ &= 8 \end{aligned} φ(99)φ(15)=99×(1−31)×(1−111)=60=99×(1−31)×(1−51)=8
定义:假设 m > 1 m > 1 m>1,且 g c d ( a , m ) = 1 gcd(a, m) = 1 gcd(a,m)=1 ( a a a、 m m m 互质),那么使得 a r ≡ 1 m o d    m a^r ≡ 1 \mod m ar≡1modm 成立的最小的整数 r r r,称为 a a a 对模 m m m 的阶,记作
δ m ( a ) \delta_m(a) δm(a)
如果有
δ m ( a ) = φ ( m ) \delta_m(a) = \varphi(m) δm(a)=φ(m)则称 a a a 为模 m m m 的一个原根
举个例子:
设 m = 7 m = 7 m=7,则 φ ( m ) = 7 × ( 1 − 1 7 ) = 6 \varphi(m) = 7×(1-\frac{1}{7})=6 φ(m)=7×(1−71)=6
一个一个取 a a a
a = 2 , 2 3 = 8 ≡ 1 m o d    7 得 到 δ 7 ( 2 ) = 3 ∵ 3 < 6 , ∴ δ 7 ( 2 ) ≠ φ ( 7 ) 2 不 是 模 7 的 原 根 a = 3 , 3 k ≠ 1 m o d    7 , k ∈ [ 1 , 5 ] 3 6 = 729 ≡ 1 m o d    7 得 到 δ 7 ( 3 ) = 6 ∵ 6 = 6 , ∴ δ 7 ( 3 ) = φ ( 7 ) 3 是 模 7 的 原 根 \begin{aligned} a = 2, & 2^3 = 8 ≡ 1 \mod 7\\ &得到\delta_7(2) = 3\\ & ∵ 3 < 6,∴\delta_7(2) ≠ \varphi(7)\\ & 2不是模7的原根\\ a = 3, & 3^k ≠ 1 \mod 7,k∈[1, 5]\\ & 3^6 = 729 ≡ 1 \mod 7\\ &得到\delta_7(3) = 6\\ & ∵ 6 = 6,∴\delta_7(3) = \varphi(7)\\ & 3是模7的原根 \end{aligned} a=2,a=3,23=8≡1mod7得到δ7(2)=3∵3<6,∴δ7(2)̸=φ(7)2不是模7的原根3k̸=1mod7,k∈[1,5]36=729≡1mod7得到δ7(3)=6∵6=6,∴δ7(3)=φ(7)3是模7的原根
原根就具有单位根的性质,使得它可以和单位根一样进行运算
原根存在的条件是:
m = 2 , 4 , p n , 2 p n m = 2, 4, p^n, 2p^n m=2,4,pn,2pn,这里 p p p 为奇素数, n n n 为正整数
这里我们取
g P − 1 n m o d    P = w n g^{\frac{P-1}{n}} \mod P= w_n gnP−1modP=wn其中 g g g 是 P P P 的原根,这样就可以用左式代替右式进行类FFT计算,即用整数代替了浮点数
这里 P P P 通常取998244353、1004535809,它们的原根 g g g 均为 3
那NNT就是将FFT中的单位根换成了原根
如果说FFT的核心代码如下的话:
x = a[j + k];
y = w * a[j + k + mid];
a[j + k] = x + y;
a[j + k + mid] = x - y;
那NNT的核心代码就是这样:
x = a[j + k];
y = w * a[j + k + mid];
a[j + k] = (x + y) % P;
a[j + k + mid] = (x - y + P) % P;