【发布时间】:2011-10-02 00:41:52
【问题描述】:
引用“Python Programming: An Introduction to Computer Science”
我们可以取平方根 使用求幂**。使用 math.sqrt 效率更高。
“有点”,但程度如何?
【问题讨论】:
-
您可以随时使用
timeit自行测量。根据记录,math.sqrt对我来说只快了大约 5%。
标签: python exponentiation
引用“Python Programming: An Introduction to Computer Science”
我们可以取平方根 使用求幂**。使用 math.sqrt 效率更高。
“有点”,但程度如何?
【问题讨论】:
timeit 自行测量。根据记录,math.sqrt 对我来说只快了大约 5%。
标签: python exponentiation
理论上,hammar's answer 和 duffymo's answer 是很好的猜测。但实际上,在我的机器上,它没有更高效:
>>> import timeit
>>> timeit.timeit(stmt='[n ** 0.5 for n in range(100)]', setup='import math', number=10000)
0.15518403053283691
>>> timeit.timeit(stmt='[math.sqrt(n) for n in range(100)]', setup='import math', number=10000)
0.17707490921020508
部分问题在于. 操作。如果您将sqrt 直接导入命名空间,您会得到轻微的改进。
>>> timeit.timeit(stmt='[sqrt(n) for n in range(100)]', setup='from math import sqrt', number=10000)
0.15312695503234863
那里的关键词:轻微。
进一步的测试表明,随着数量的增加,您从使用sqrt 中获得的好处也会增加。但仍然不是很多!
>>> timeit.timeit(stmt='[n ** 0.5 for n in range(1000000)]', setup='import math', number=1)
0.18888211250305176
>>> timeit.timeit(stmt='[math.sqrt(n) for n in range(1000000)]', setup='import math', number=1)
0.18425297737121582
>>> timeit.timeit(stmt='[sqrt(n) for n in range(1000000)]', setup='from math import sqrt', number=1)
0.1571958065032959
【讨论】:
实现不用猜,看代码即可!
math.sqrt 是标准 C 库中关于 sqrt 的精简包装器:参见 mathmodule.c, line 956
** 运算符根据参数的类型有多种实现,但在浮点指数的情况下,它最终会从标准 C 库中分派到pow(请参阅floatobject.c line 783)。
现代 CPU 通常具有特殊的平方根指令,而一般的求幂例程不使用这些指令(例如,比较和对比 glibc 中用于 x86-64 的 pow 和 sqrt 的实现)。但是,一旦添加了所有解释器开销(字节码、类型检查、方法分派等),原始速度的差异就不再那么重要了,并且可能会受到诸如您是否直接调用 sqrt 或查看它等问题的支配通过math 模块(如其他答案中的时间所示)。
【讨论】:
** 必须支持任何指数,而math.sqrt 知道它始终是0.5。 math.sqrt 因此可以使用更专业(因此可能更有效)的算法。
【讨论】:
** 的最佳实现可以简单地分支到 math.sqrt。这可能会产生几乎无法衡量的影响。
我的猜测是 math.sqrt 使用 Newton's method,它以二次方收敛,而求幂使用其他更慢的东西。
【讨论】:
math.sqrt 可能是 C 数学函数 sqrt 的别名,它是使用适合您平台的最佳算法实现的。如果您的 CPU 支持 SSE 指令,您将获得一个 sqrt* 指令系列,其中所有成员都尽可能快。
这里有一个稍微不同的方法。我们想要一个比平方根大的 int。两种方式(不同意平方数但没关系):
>>>timeit.timeit(stmt='[int(n**0.5)+1 for n in range(1000000)]', setup='', number=1)
0.481772899628
>>>timeit.timeit(stmt='[ceil(sqrt(n)) for n in range(1000000)]', setup='from math import sqrt, ceil', number=1)
0.293844938278
>>>timeit.timeit(stmt='[int(ceil(sqrt(n))) for n in range(1000000)]', setup='from math import sqrt, ceil', number=1)
0.511347055435
所以数学函数更快...直到您将浮点数转换为整数。 (我需要对值做很多比较,虽然我还没有测试过,但比较整数应该比比较浮点数便宜。)
但是,嘿,它是 Python。您处于太多抽象之上,无法尝试以这种粒度级别优化性能。
【讨论】: