Barrett 约简

Barrett 约简是一种对于固定模数 \(n\) 快速计算

\[c=a\bmod n \]

的方法。

BF

众所周知地,我们定义模运算

\[a\bmod n=a-\left\lfloor\dfrac{a}{n}\right\rfloor\times n \]

因此,暴力计算模运算需要计算除法,考虑除法器设计复杂,并且可能不是恒定时间指令,时间和安全性都不优。

Algo 1

假设固定模数 \(n\),并且除以 \(R\) 可以快速计算(后者在普通计算机上可以取 \(2\) 的整数次幂,实现为右移运算)。

Barrett 约简的思想是使用 \(\dfrac{m}{R}\) 估计 \(\dfrac{1}{n}\)。容易得到 \(m=\dfrac{R}{n}\),为了使它成为整数,我们将其取下整,由于 \(n\) 是固定的,因此 \(m\) 可以预处理。

需要指出 Barrett 约简后结果的值域由 \([0,n)\) 变为 \([0,2n)\),这是精度丢失导致的。

更具体的精度要求是

\[a\lt n^2\lt R. \]

对于 \(32\) 位整型的计算,要求 \(R\)\(2^{64}\),这样 \(m\) 可以有 \(32\) 位以上的精度,注意过程中涉及 \(128\) 位整型的计算。

struct Barrett {
  int64_t m, p;
  void init(int pp) {
    m = ((__int128)1 << 64) / pp;
    p = pp;
  }
  int64_t operator()(int64_t x) {
    return x - ((__int128(x) * m) >> 64) * p;
  }
} mod;

Algo 2

对于模乘运算,例如 \(c=a\times b\bmod n\),假设 \(b,n\) 均固定,我们可以预处理 \(\left\lfloor\dfrac{bR}{n}\right\rfloor\),然后使用

\[ab-\left\lfloor\dfrac{a\left\lfloor\dfrac{bR}{n}\right\rfloor}{R}\right\rfloor \]

代替 \(ab\bmod n\)

思想与 \(\text{Algo 1}\) 类似。

posted @ 2024-07-28 17:32  weilycoder  阅读(34)  评论(0编辑  收藏  举报