为什么此功能有效计算模块化功率值?

时间:2013-03-27 02:15:39

标签: java algorithm

我在SRM 573's solution here:

中看到了这个功能
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;
这对我没有意义。

4 个答案:

答案 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

对于某些自然人xx = n*MOD + r n,我们总是可以rr < 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。

事实证明,在计算上难以找到以目标数结束的最短加法链。