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;
posted @ 2025-08-15 22:01  TH911  阅读(12)  评论(0)    收藏  举报