我想了很久了。就像题目说的,哪个更快,是实际函数还是简单地取1 / 2次幂?

更新

这不是一个过早优化的问题。这只是一个底层代码如何实际工作的问题。Python代码的工作原理是什么?

我给Guido van Rossum发了一封邮件,因为我真的很想知道这些方法的区别。

我的电子邮件:

在Python中至少有3种方法来求平方根:math。返回值, '**'运算符和pow(x,.5)。我只是好奇它们之间的区别 每一个的实现。说到效率 是更好吗?

他的回答:

Pow和**是等价的;数学。根号方根不适用于复数, 并链接到C的sqrt()函数。至于哪一个是 快点,我不知道……


当前回答

我最近解决的SQRMINSUM问题需要在一个大型数据集上重复计算平方根。在我做其他优化之前,我历史上最老的2个提交,唯一的区别是用sqrt()替换**0.5,从而将PyPy中的运行时从3.74秒减少到0.51秒。这几乎是克劳狄测量的400%的巨大改进的两倍。

其他回答

有人评论《雷神之锤3》中的“快速牛顿-拉弗森平方根”……我用ctypes实现了它,但与本机版本相比,它非常慢。我将尝试一些优化和替代实现。

from ctypes import c_float, c_long, byref, POINTER, cast

def sqrt(num):
 xhalf = 0.5*num
 x = c_float(num)
 i = cast(byref(x), POINTER(c_long)).contents.value
 i = c_long(0x5f375a86 - (i>>1))
 x = cast(byref(i), POINTER(c_float)).contents.value

 x = x*(1.5-xhalf*x*x)
 x = x*(1.5-xhalf*x*x)
 return x * num

这是另一个使用struct的方法,比ctypes版本快3.6倍,但仍然是C的1/10。

from struct import pack, unpack

def sqrt_struct(num):
 xhalf = 0.5*num
 i = unpack('L', pack('f', 28.0))[0]
 i = 0x5f375a86 - (i>>1)
 x = unpack('f', pack('L', i))[0]

 x = x*(1.5-xhalf*x*x)
 x = x*(1.5-xhalf*x*x)
 return x * num

在python 2.6中,(float).__pow__()函数使用C pow()函数,math.sqrt()函数使用C sqrt()函数。

在glibc编译器中,pow(x,y)的实现相当复杂,并且针对各种例外情况进行了很好的优化。例如,调用C pow(x,0.5)只调用sqrt()函数。

**或数学使用速度的差异。sqrt是由围绕C函数的包装器引起的,速度很大程度上取决于系统上使用的优化标志/C编译器。

编辑:

这是克劳狄算法在我机器上的结果。我得到了不同的结果:

zoltan@host:~$ python2.4 p.py 
Took 0.173994 seconds
Took 0.158991 seconds
zoltan@host:~$ python2.5 p.py 
Took 0.182321 seconds
Took 0.155394 seconds
zoltan@host:~$ python2.6 p.py 
Took 0.166766 seconds
Took 0.097018 seconds

我最近解决的SQRMINSUM问题需要在一个大型数据集上重复计算平方根。在我做其他优化之前,我历史上最老的2个提交,唯一的区别是用sqrt()替换**0.5,从而将PyPy中的运行时从3.74秒减少到0.51秒。这几乎是克劳狄测量的400%的巨大改进的两倍。

如果您进入math.py并将函数“sqrt”复制到您的程序中,则会更快。程序找到math.py,然后打开它,找到要找的函数,然后将其带回程序,这需要时间。如果该函数即使使用“查找”步骤也更快,那么函数本身必须非常快。可能会让你的时间缩短一半。总而言之:

转到math.py 找到函数“√” 复制它 将函数粘贴到程序中作为根号查找器。 它的时间。

优化的第一条规则:不要这么做 第二条规则:先别这么做

以下是一些计时(Python 2.5.2, Windows):

$ python -mtimeit -s"from math import sqrt; x = 123" "x**.5"
1000000 loops, best of 3: 0.445 usec per loop

$ python -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)"
1000000 loops, best of 3: 0.574 usec per loop

$ python -mtimeit -s"import math; x = 123" "math.sqrt(x)"
1000000 loops, best of 3: 0.727 usec per loop

这个测试表明x**。5比√(x)略快。

对于Python 3.0,结果正好相反:

$ \Python30\python -mtimeit -s"from math import sqrt; x = 123" "x**.5"
1000000 loops, best of 3: 0.803 usec per loop

$ \Python30\python -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)"
1000000 loops, best of 3: 0.695 usec per loop

$ \Python30\python -mtimeit -s"import math; x = 123" "math.sqrt(x)"
1000000 loops, best of 3: 0.761 usec per loop

Math.sqrt (x)总是比x**快。5在另一台机器上(Ubuntu, Python 2.6和3.1):

$ python -mtimeit -s"from math import sqrt; x = 123" "x**.5"
10000000 loops, best of 3: 0.173 usec per loop
$ python -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)"
10000000 loops, best of 3: 0.115 usec per loop
$ python -mtimeit -s"import math; x = 123" "math.sqrt(x)"
10000000 loops, best of 3: 0.158 usec per loop
$ python3.1 -mtimeit -s"from math import sqrt; x = 123" "x**.5"
10000000 loops, best of 3: 0.194 usec per loop
$ python3.1 -mtimeit -s"from math import sqrt; x = 123" "sqrt(x)"
10000000 loops, best of 3: 0.123 usec per loop
$ python3.1 -mtimeit -s"import math; x = 123" "math.sqrt(x)"
10000000 loops, best of 3: 0.157 usec per loop