我正在尝试实现快速取幂的方案。学位以二进制形式表示:
def pow_h(base, degree, module):
degree = bin(degree)[2:]
r = 1
for i in range(len(degree) - 1, -1, -1):
r = (r ** 2) % module
r = (r * base ** int(degree[i])) % module
return r
但功能不正常,哪里出错?
答案 0 :(得分:1)
如果当前指数是偶数或奇数,那么这种快速取幂必须采取不同的行为,但是你的代码中没有这样的检查。以下是一些提示:
要查找x**y
,您需要一个"累加器"变量来保存到目前为止计算的值。让我们使用a
。因此,您发现a*(x**y)
代码正在减少y
并且增加a
和/或x
,直到y
变为零并且a
是您的最终答案。
如果y
是偶数,请说y==2*k
,然后a*x**(2*k) == a*(x**2)**k
。这使y
减少到y//2
并将x
增加到x**2
。
如果y
为奇数,请说y==2k+1
,然后a*x**(2*k+1) == (a*x)*x**(2*k)
。这使y
减少到y-1
并将a
增加到a*x
。
你应该可以从这里算出算法。我没有使用模数:这应该很容易。
答案 1 :(得分:1)
正如我在评论中所说,内置pow
函数已经进行了快速模幂运算,但我认为这是一个合理的编码练习,可以自己实现。
你的算法很接近,但是你正在解决错误的问题。您需要将base
平方,而不是r
,并且您应该在乘法步骤后执行此操作。
def pow_h(base, degree, module):
degree = bin(degree)[2:]
r = 1
for i in range(len(degree) - 1, -1, -1):
r = (r * base ** int(degree[i])) % module
base = (base ** 2) % module
return r
#test
for i in range(16):
print(i, 2**i, pow_h(2, i, 100))
<强>输出强>
0 1 1
1 2 2
2 4 4
3 8 8
4 16 16
5 32 32
6 64 64
7 128 28
8 256 56
9 512 12
10 1024 24
11 2048 48
12 4096 96
13 8192 92
14 16384 84
15 32768 68
使用r * base ** int(degree[i])
是一个可爱的技巧,但使用if
语句可能比取幂更有效。并且您可以使用算术来获取degree
的位,而不是使用字符串,尽管bin
非常有效。无论如何,这是我的版本:
def pow_h(base, power, modulus):
a = 1
while power:
power, d = power // 2, power % 2
if d:
a = a * base % modulus
base = base * base % modulus
return a