先用较为直白简单的方式实现模n的指数运算(以a为底数,b为指数,模n)
def mod_pow_e(base, exponent, n):
res = 1
for i in range(exponent):
res = res * base
return res % n
原理很简单,将底数base连续乘指数exponent次,对得到的结果res模n,得到最终结果。该算法的时间复杂度为。
为了简化算法,观察以下式子:
其中
其中
不难发现,属于同一模n剩余类的数,乘任意一整数时,所得结果模n都相同。由乘法的交换律,我们可以发现更为广泛的规律:分别属于同一模n剩余类的两个数相乘所得的结果对n取模都相同。这里记为性质1,可以表达为:
性质1:
这是模运算的基本性质之一,下面简单证明该性质:
首先,根据带余除法,对给定的任意正整数和任意非负整数
,若用
除
,得到整数商
和整数余数
,则满足以下关系式:
定义除以
所得的余数为
模
,整数
称为模数,因此可以把上式写为:
令,
,于是存在整数
,
使得
,
。那么
从性质1, 可以推得另一性质:
性质2:
证明这一性质也是比较简单的:
有了这两条性质,我们就可以着手优化算法了,算法的基本形式如下:
其中,为底数,
为指数,
是一个乘数,
为模。
首先,由性质2,在每次进行指数运算时,可以先将底数模n,从而在不影响结果的情况下降低运算复杂度;然后,如果指数
为奇数,先将乘数乘底数,同时模n,使幂
降为一个偶数,然后让底数
为底数
的平方,同时模n,使幂
将为原来的一半,直到幂
降为1。最后,将底数
和乘数
相乘,结果模n,得到最终结果。
例子:
即底数为7,幂为5,乘数为1,模为4:
首先将底数模4:
此时幂为奇数,让乘数乘一个底数,同时模4:
此时幂为偶数,让底数平方,同时取模4,幂降为原来的一半:
此时幂仍为偶数,再次让底数平方,同时取模4,幂降为原来的一半:
现在,幂已经降为1,让底数1和乘数3相乘,结果模4,得到最后结果为3。
def mod_pow(base, exponent, n):
mul = 1
base = base % n # 取模n
while exponent > 1:
# 如果指数为奇数,乘以base并取模n
if exponent % 2:
mul = (mul * base) % n
exponent -= 1
# 将指数减半,同时底数平方并取模n
exponent = exponent // 2
base = (base * base) % n
return (base * mul) % n
该算法每次循环让指数降低为
,时间复杂度为