












而 pow(g, a, p) 之所以能“秒算”,是因为它在底层使用了高度优化的快速幂算法结合模运算(Exponentiation by Squaring with Modular Reduction)。
它的精妙之处在于“边算边约减”——在每一次平方或乘法运算后,立刻对中间结果进行取模操作。这样,整个计算过程中的所有中间变量都被死死地控制在
p 的范围之内,彻底避免了产生巨大中间值的问题。
这里举例说明 pow(3, 13, 7) ,即表示 计算 3^13 % 7 的结果 , 其核心是要将 3^13 分解成多个数的乘积 , 计算机中,最快最简单的就是3不变, 将指数13进行分解
如果按照你直觉中的“先算出完整结果再取模”,我们需要先算 3^13 ,这等于 1594323,然后再用 1594323 除以 7 求余数。如果指数更大,这个数字会大到计算机直接爆内存。
而快速幂算法的“边算边约减”和“二进制分解”是这样操作的:
首先,我们将指数 13 写成二进制:1101 , 在二进制中,每一位代表一个权重:
第 0 位是 1 - 代表 2^0 = 1 第 1 位是 0 - 代表 2^1 = 2 第 2 位是 1 - 代表 2^2 = 4 第 3 位是 1 - 代表 2^3 = 8
所以,13=8+4+1,而且可以观察出来,二进制中,低位的1如果为x ,它旁边高位的1就代表是x的2倍,即2x了
这样,我们带入底数3 , 也即如果 3^x 的下一个高位如果是1 , 就是 3^(2x) , 也即是 (3^x)^2 , 也即低高位都是1 , 位数的3^x 的 平方 就是下一个高位的结果
那么数学上,3^13 就可以拆解为:3^8 * 3^4 * 3^1 = 3^(8+4+1)
第二步:开始迭代计算(核心过程)
我们准备两个变量:结果(res) = 1,底数(base) = 3。我们从二进制的最低位(最右边)开始往左看:
【第 1 轮】处理二进制的最后一位(1)
【第 2 轮】处理二进制的倒数第二位(0)
【第 3 轮】处理二进制的倒数第三位(1)
base 已经通过连续平方代表了 3^4 。res = res × base % 7 → 3 × 4 % 7 = 12 % 7 = 5base = 4 × 4 % 7 = 16 % 7 = 2。(再次取模)。【第 4 轮】处理二进制的最高位(1)
base 代表了 3^8 。res = res × base % 7 → 5 × 2 % 7 = 10 % 7 = 3。base = 2 × 2 % 7 = 4。所以最后的结果就是3 , 这里我们总结一下:
我们可以看到,整个过程中,我们从来没有计算过像 1594323 这样的大数。每一次乘法之后,我们都立刻 % 7
这就是为什么 Python 的 pow(g, a, p) 能够“秒算”:它利用二进制把巨大的指数拆解成了少量的平方和乘法操作
时间复杂度从 O(a)降到了 O(log a) 并且死死地把所有中间数字控制在模数 p 的范围内,彻底避免了内存爆炸。
尊重别人的劳动成果 转载请务必注明出处:https://www.cnblogs.com/5201351/p/20331011
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。