Barrett 约减
Barrett 约减优化整数除法/取模
取变量的模其实是非常慢的,而 Barrett 可以在一定情况下将取模化为两次乘法、一次右移以及至多两次减法。
令模数为 \(p\)。
容易发现:
\[x\bmod p=x-p\left\lfloor\dfrac xp\right\rfloor
\]
考虑快速求出 \(\left\lfloor\dfrac xp\right\rfloor\)。
Barrett 选取了 \(m,k\),使得:
\[m=\left\lfloor\dfrac{2^k}{p}\right\rfloor
\]
因此有:
\[\dfrac xp\approx\dfrac{mx}{2^k}
\]
-
取 \(2^k>x(p-1)\) 时可以精确计算。
-
取 \(2^k>x\) 时可以保证 \(\left\lfloor\dfrac xp\right\rfloor\) 的误差为 \(0\) 或 \(1\)。
因此计算出来的 \(x-p\cdot\dfrac{mx}{2^k}\) 的取值范围为 \([0,2p)\)。特判即可。
代码实现
一般去 \(m=\dfrac{2^{64}}{p}\),可以处理 \(\left[-2^{63},2^{63}\right)\) 范围内的整数。
typedef long long ll;
typedef __int128 lll;
struct Barrett{
ll p,m;
inline void build(int P){
p=P;
m=((lll)1<<64)/p;
}
inline ll operator ()(ll x){
ll ans=x-((lll)x*m>>64)*p;
if(ans>=p){
ans-=p;
}
return ans;
}
}Barrett;

浙公网安备 33010602011771号