计算能力的速度(在python中)
我很好奇,为什么它乘法的速度要快于在python中的权力(尽管从我读过的内容来看,这在许多其他语言中也是如此)。 例如,它要快得多
x*x
比
x**2
我认为**运算符更一般,也可以处理分数的权力。 但是,如果这就是为什么它慢得多,为什么它不执行一个int指数检查,然后只是做乘法?
编辑:这是我尝试的一些示例代码...
def pow1(r, n):
for i in range(r):
p = i**n
def pow2(r, n):
for i in range(r):
p = 1
for j in range(n):
p *= i
现在,pow2只是一个简单的例子,显然不是最优化的!
但即使如此,我发现使用n = 2和r = 1,000,000,pow1需要约2500ms,pow2需要约1700ms。
我承认,对于n的大数值,pow1确实比pow2快得多。 但这并不令人感到意外。
基本上天真的乘法是O(n),其常数因子很低。 采取的权力是O(log n)具有较高的常数因子(有些特殊情况需要测试......分数指数,负指数等)。 编辑:只需要清楚,那就是O(n),其中n是指数。
当然,对于小n来说,天真的方法会更快,你只是真正实现了指数数学的一个小子集,所以你的常数因子可以忽略不计。
添加支票也是一项开支。 你总是希望那里的支票? 编译语言可以检查一个常量指数,看它是否是一个相对较小的整数,因为没有运行时成本,只是编译时成本。 解释型语言可能不会进行检查。
这取决于特定的实现,除非该语言指定了这种细节。
Python不知道你要给它分配什么指数。 如果它将是99%的非整数值,你是否希望代码每次检查一个整数,使运行时更慢?
在指数检查中这样做会减慢并非两次的简单次幂的情况,所以不一定是胜利。 但是,在指数已知的情况下(例如使用文字2),可以通过简单的窥孔优化来优化生成的字节码。 据推测,这根本不值得做(这是一个相当具体的案例)。
这是一个快速的概念证明,可以做这样的优化(可用作装饰器)。 注意:您需要字节播放模块来运行它。
import byteplay, timeit
def optimise(func):
c = byteplay.Code.from_code(func.func_code)
prev=None
for i, (op, arg) in enumerate(c.code):
if op == byteplay.BINARY_POWER:
if c.code[i-1] == (byteplay.LOAD_CONST, 2):
c.code[i-1] = (byteplay.DUP_TOP, None)
c.code[i] = (byteplay.BINARY_MULTIPLY, None)
func.func_code = c.to_code()
return func
def square(x):
return x**2
print "Unoptimised :", timeit.Timer('square(10)','from __main__ import square').timeit(10000000)
square = optimise(square)
print "Optimised :", timeit.Timer('square(10)','from __main__ import square').timeit(10000000)
其中给出了时间:
Unoptimised : 6.42024898529
Optimised : 4.52667593956
[编辑]其实,再想一想,有一个很好的理由说明为什么这个优化没有完成。 不能保证有人不会创建一个覆盖__mul__
和__pow__
方法并为每个方法做不同的事情的用户定义类。 唯一能安全地做到这一点的方法是,如果你能保证堆栈顶部的对象具有相同的结果“x **2
”和“ x*x
”,但是解决这个问题要困难得多。 例如。 在我的例子中是不可能的,因为任何对象都可以传递给平方函数。