C++中避免整数溢出的模函数

cod*_*jam 1 c++ sum integer-overflow modulus c++11

如果我有 2 个intlong long变量,调用它们aand b,并且我想计算 sum (a + b) mod p,其中 p 是一个大素数整数,我如何利用 C++ 中的模运算符来获得所需的结果?

我试过(a + b) % p,但这有时a + b会导致溢出,因为会在应用 mod 之前溢出。

我尝试过的其他类似方法似乎可以避免溢出,但会给出不正确的结果。

在这种情况下,如何使用模运算符正确计算所需的总和,同时避免溢出?

Bet*_*eta 6

a %= p
b %= p
c = p-a

if(b==c)
  sum = 0
if (b<c)
 sum = a+b
if (b>c)
 sum = b-c
Run Code Online (Sandbox Code Playgroud)

编辑:诀窍是避免任何可能导致溢出的计算,而不知道限制在哪里。我们所知道的是给定的 a、b 和 p 都低于极限——也许刚好低于极限。

在前两个步骤 ( a%=p;b%=p;) 之后,我们知道a<pb<p。我们还是不敢加a+b,因为那个总和可能会超过 p 并突破限制*。但是我们可以看到我们还剩下多少空间c = p-a,这是安全的,因为我们知道c<=p并且c>0。(所述类型是无符号的,但我们也可以避免负数,因为它们的限制有时与限制的负数相差一个,我记不得了。)

如果 b=c,则 b=pa,所以 a+b=p,所以总和 (mod p) 为零。

如果b<c,则a+b<p,所以我们可以安全地计算a+b(并且不需要应用模)。

如果b>c,那么它是不是安全的计算a+b,但我们知道,我们正在寻找的数量a+b-p,我们可以为改写b-(p-a)的,我们已经有bp-a,所以我们可以有把握地执行减法。

(*)没错,我说“不敢”。这是一个完美的词。

  • 好的。也许解释一下为什么它有效也会有帮助。 (3认同)