如何在存在整数溢出时计算此模数

时间:2014-01-04 04:59:11

标签: math numbers modulo

(10^{17}-1)*(10^{17}-1) mod 10^{18}

我正在解决编程问题,并且我将整数保持为64位长整数。以上是我无法解决的特例。 (ab)mod m =(a mod m)(b mod m)mod m,此处不成立,因为(a mod m)(b mod m)仍会溢出64位整数。我该如何解决这个问题?我只把17次力量作为例子。即使对于范围内的所有整数(10 ^ {10},10 ^ {18} -1),问题仍然存在。

编辑:我正在使用C ++来解决这个问题。不使用库来处理大整数就可以解决这个问题。

1 个答案:

答案 0 :(得分:0)

您可以使用您引用的身份,只需要另一个相似的身份:(a+b) mod m = (a mod m) + (b mod m)

目标是将x*y mod m乘以不超过溢出限制的任何中间值(在本例中为2 ^ 64),其中x的起始值小于m(如果不是{ t,减少mod m),y可能大于mx*y可能会溢出。如果m小于溢出限制的一半,我们可以这样做。

解决方案很简单:只需为x*y逐位执行基本乘法操作,并按模m的每一步执行。

x开始,y小于m(如果不是,请先将其缩小)。以y + ...的形式写a_0 * 2^0 + a_1 * 2^1 + a_2 * 2^2,其中a_n为0或1(表示该术语是否存在)。 (Aka,以二进制形式写y。)现在我们有:

x * (a_0 * 2^0 + a_1 * 2^1 + a_2 * 2^2 + ...) mod m

x的每个字词上分发y

(x * a_0 * 2^0) + (x * a_1 * 2^1) + (x * a_2 * 2^2) + ... mod m

然后使用原始乘法标识:对于上面的每个项,将x乘以2 mod m,直到达到该项的所需幂为2。 (从x < m2 * m < 2^64开始,然后是2 * x < 2^64,所以我们可以乘以2而不会溢出。)完成后,为每个术语mod m添加结果(你你可以随时保持一笔运行金额。)

这些操作都不会超过2 ^ 64,因此不会溢出。这适用于m小于2 ^ 64/2 = 2 ^ 63的任何值以及小于x的任何整数ym

这不一定是最快的方法,随时找到更高效的东西。对于初学者,将较小的m与溢出限制进行比较,我们可以将y重写的术语的基数越大。