Python 数字幂的整数除法可以优化吗?
Python中有一个内置函数Python 数字幂的整数除法可以优化吗?,python,built-in,pow,Python,Built In,Pow,Python中有一个内置函数pow,它优化了a**b%c的计算。为什么没有计算a**b//c的函数 我将尝试在这里总结为什么a**b//c的计算不能优化,不太可能a**b%c 先决条件:计算a**b%c 让我们举一个示例:假设a=2和b=11。如果我们假设它相当慢,那么我们可以推断出b=1+2+8=2**0+2**1+0*2**2+2**3。在此之后,此推断可作为结果相乘的规则a,a**2,a**4,a**8。将前一个结果平方后指定每个结果。最后,a**11=a*(a**2)*(a**8)这个过
pow
,它优化了a**b%c
的计算。为什么没有计算a**b//c的函数 我将尝试在这里总结为什么a**b//c
的计算不能优化,不太可能a**b%c
先决条件:计算a**b%c
让我们举一个示例:假设a=2
和b=11
。如果我们假设它相当慢,那么我们可以推断出b=1+2+8=2**0+2**1+0*2**2+2**3
。在此之后,此推断可作为结果相乘的规则a
,a**2
,a**4
,a**8
。将前一个结果平方后指定每个结果。最后,a**11=a*(a**2)*(a**8)
这个过程只需要3次平方运算
如果我们推广这个过程,可以这样做:
a, b, r = 2, 11 , []
while b>0:
if b % 2: r.append(a)
b = b//2
a = a*a
else:
if b % 2: r.append(a)
print(r)
输出是r=[2,4,256]
。接下来,我们需要乘以这些乘数。可以使用functools import reduce中的命令reduce(lambda x,y:x*y,r)
完成此操作
最后,如果乘法器变得非常大,那么乘法器变得非常慢,因此我们需要将每个乘法器m
替换为其模m%c
,并在reduce
函数中执行相同的操作。最后,我们有:
from functools import reduce
def pow(a, b, c):
# returns a ** b % c
r = []
while b > 0:
if b % 2: r.append(a)
b = b // 2
a = (a * a) % c
else:
if b % 2: r.append(a)
return reduce(lambda x, y: (x * y) % c, r)
输出是4
,因为2**11%7
是4
我也在我的电脑上测试了结果2046457**1103207%71872
。输出为18249
,计算耗时9秒,而pow(204645711032071872)
立即给出相同的结果
更新:将a**b//c
插入计算
按照上述想法,我将尝试对a**b//c
的计算进行类似的优化。我假设平方的过程保持不变,这里的主要区别是我们需要考虑积分和残差部分,同时采取正方形(以前是容易的,因为积分部分并不重要)。如果x
是一个不可分割的部分,而y
是剩余部分,则我们有一个关系:
我们还需要为两个不同的乘数引入类似的计算:
我的脚本现在看起来像这样:
from functools import reduce
def pow(a, b, c):
#returns tuple (a ** b // c, a ** b % c)
print(f'calculating: {a}**{b} = ', end='')
r = []
ir = (a//c, a%c) # we keep integral and residual part of a instead of a
while b > 0:
if b % 2: r.append(ir)
b = b // 2
ir = (ir[0]*ir[0]*c + 2*ir[0]*ir[1]+ (ir[1]*ir[1])//c, (ir[1]*ir[1]) % c)
else:
if b % 2: r.append(ir)
out = reduce(lambda x, y: (c*x[0]*y[0] + x[0]*y[1] + x[1]*y[0] + (x[1] * y[1])//c, (x[1] * y[1]) % c), [(2, 2)]+[r[-1]])
print(' * '.join(str(n[0]*c+n[1]) for n in r), end=' = ')
print(' * '.join(str(n) for n in r),'=', out)
return out
pow(2,7,3)
输出
笔记
为什么现在还不是呢?我们可以看到,每个因子中的第二项始终很小,但这不是第一项的规则,如本例中的pow(26,31,35)
:
在这种情况下,我们无法避免a%b//c
的指数增长。这就是为什么a%b//c
没有内置函数对我来说似乎是合理的。这不是在博客(或白皮书)上更常见吗?在这方面你似乎不需要帮助……我在这里发布了一个类似问题的变体:@Oliver.R分享知识你已经发现自我回答的目的就是要用艰难的方式。(这一特定因素的有用性可能有争议;但“其他人会面临这个问题吗”也不是常规问题的标准。)@millimoose Fair points,谢谢你的见解-mathfux我为我不必要的评论道歉!
calculating: 2**7 = 2 * 4 * 16 = (0, 2) * (1, 1) * (5, 1) = (42, 2)
calculating: 26**31 = 26 * 676 * 456976 * 208827064576 * 43608742899428874059776 =
(0, 26) * (19, 11) * (13056, 16) * (5966487559, 11) * (1245964082840824973136, 16) =
(89709413964539398065824, 32)