Barrett 约减

优化整数除法/取模

Posted by TH911 on August 15, 2025

推荐一篇文章

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)$ 范围内的整数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;