long modPow(long x, long y)
{
//Caculates x raised to the y-power modulo MOD
//in O(log(y)) time by using repeated squaring
long r = 1;
while(y > 0){
if( (y&1) != 0) {
r = (r * x) % MOD;
}
x = (x * x)%MOD;
y >>= 1;
}
return r;
}
但我对此功能感到困惑,计算x^y%MOD
的模块值;
为什么功能需要x = (x * x)%MOD;
?
这对我没有意义。
答案 0 :(得分:1)
tl; dr:这是一个优化。
想象一下,x是2,MOD是3.注意,x唯一用于将r乘以x。
现在假设我们正方形x。 x * x = 4.现在,r * 4%3将等于1,2,3,4,5 ......对于r = 1,2,3,4,5 ......哦!它与x是1相同。事实上,如果你将x设置为x * x%3而不是x * x,你会得到相同的结果。
但下一步呢? 4 * 4 = 16,%3 = 1. 1 * 1 = 1,%3也= 1.因此,无论我们是提前还是迟到或从不修改操作,我们都会陷入相同的残差。
答案 1 :(得分:1)
在每次通过下面显示的循环时,低位被移出y
,其中y
开始为基数x
将被提升到的指数
long r = 1;
while(y > 0){
if( (y&1) != 0) {
r = (r * x) % MOD;
}
x = (x * x)%MOD;
y >>= 1;
}
例如,如果y = 0b1101
或13十进制,那么xʸ = x¹³ = x¹⁺⁴⁺⁸ = x·x⁴·x⁸
和if( (y&1) != 0) r = (r * x) % MOD
部分会将r
乘以x
乘以第一个,第三个,当x
的当前值是原始值的第一,第四和第八幂时,第四次通过。
请注意,因为(a·b) mod p ≡ ((a mod p)·(b mod p)) mod p
,每次乘法后都可以应用mod
函数。应用它经常最小化乘法所需的位数。
答案 2 :(得分:0)
在@jwpat7的回答中详细说明一下,让我们想一想为什么
(x % MOD)*(x % MOD) ≡ (x*x) % MOD
。
对于某些自然人x
和x = n*MOD + r
n
,我们总是可以r
为r < MOD
(如果x < MOD
也隐含x = r
1}}和n = 0
)。
现在,我们总是得到x % MOD = (n*MOD + r) % MOD = r
,因此我们得到了
(x % MOD)*(x % MOD) = r * r
。
另一方面,考虑(x*x) % MOD
评估的内容:
x*x = (n*MOD + r)*(n*MOD +r) = n*n*MOD*MOD + 2*n*r*MOD + r*r
,因此我们得到(x*x) % MOD = (n*n*MOD*MOD + 2*n*r*MOD + r*r) % MOD = r*r
这就是为什么Patashu说你是早还是晚应用模运算符并不重要,因为余数r
实际上与模运算有关,也是唯一的到下一次迭代。
答案 3 :(得分:0)
忘记模块化部分一段时间,并问自己,“如何有效地计算n ^为正整数的x ^ n?”您可以用一个乘法计算x ^ 2:x * x。您可以使用两次乘法计算x ^ 3:x ^ 3 = x * x ^ 2。您可以使用两次乘法计算x ^ 4:x ^ 4 = x ^ 2 ^ 2 = x ^ 2 * x ^ 2。您可以通过此递归计算x ^ n:
For even n = 2*m, x^n = (x^2)^m.
For odd n = 2*m + 1, x^n = x * (x^m)^2.
所以,我们得到x ^ 10 as:
x^10 = (x^2)^5
= x^2 * (x^4)*2
计算x ^ 2,x ^ 4,x ^ 8,x ^ 10,进行4次乘法。
请注意,这是一种很好的通用方法,但不能保证最有效。例如,尝试x ^ 15。这个方法给你x *(x ^ 2)^ 7 = x * x ^ 2 *(x ^ 2)^ 6 = x * x ^ 2 ^(x ^ 4)^ 3 = x ^ x ^ 2 * x ^ 4 *(x ^ 4)^ 2。您计算x ^ 2,x ^ 4,x ^ 8,然后x * x ^ 2 * x ^ 4 * x ^ 8,进行6次乘法。更快
y = x^3 = x * x^2, 2 multiplications.
x^15 = y^5 = y * (y^2)^2, 3 more multiplications,
This is a total of 5 multiplications.
实际上,对于指数n,将一个加法链定义为从1开始到n结束的数字序列,其中列表中的每个数字是序列中前2个数字的总和(您可以重复)
15的算法给出了
1,2,3,6,7,14,15。
较短的是
1,2,3,6,12,15。
事实证明,在计算上难以找到以目标数结束的最短加法链。