(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 ++来解决这个问题。不使用库来处理大整数就可以解决这个问题。
答案 0 :(得分:0)
您可以使用您引用的身份,只需要另一个相似的身份:(a+b) mod m = (a mod m) + (b mod m)
。
目标是将x*y mod m
乘以不超过溢出限制的任何中间值(在本例中为2 ^ 64),其中x
的起始值小于m
(如果不是{ t,减少mod m
),y
可能大于m
,x*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 < m
和2 * m < 2^64
开始,然后是2 * x < 2^64
,所以我们可以乘以2而不会溢出。)完成后,为每个术语mod m
添加结果(你你可以随时保持一笔运行金额。)
这些操作都不会超过2 ^ 64,因此不会溢出。这适用于m
小于2 ^ 64/2 = 2 ^ 63的任何值以及小于x
的任何整数y
和m
。
这不一定是最快的方法,随时找到更高效的东西。对于初学者,将较小的m
与溢出限制进行比较,我们可以将y
重写的术语的基数越大。