Python中的哪个更快:x **。5或math.sqrt(x)?
我一直在想这个。 正如标题所说,哪个更快,实际function还是简单地提高到一半的功率?
UPDATE
这不是过早优化的问题。 这只是底层代码实际工作的一个问题。 Python代码的工作原理是什么?
我给Guido van Rossum发了一封电子邮件,因为我真的很想知道这些方法的不同之处。
我的电子邮件:
至less有三种方法可以在Python中做平方根:math.sqrt,'**'运算符和pow(x,.5)。 我只是好奇在每个这些的执行的差异。 谈到效率更好?
他的回应是:
战俘和**是等同的; math.sqrt不适用于复数,并链接到C sqrt()函数。 至于哪一个更快,我不知道…
根据意见,我已经更新了代码:
import time import math def timeit1(): s = time.time() for i in xrange(750000): z=i**.5 print "Took %f seconds" % (time.time() - s) def timeit2(arg=math.sqrt): s = time.time() for i in xrange(750000): z=arg(i) print "Took %f seconds" % (time.time() - s) timeit1() timeit2()
现在math.sqrt
函数直接在本地参数中,这意味着它具有最快的查找可能性。
更新:python版本似乎在这里。 我以前认为timeit1
会更快,因为当pythonparsing“i **。5”时,它会从语法上知道调用哪个方法( __pow__
或某个变体),所以它不必经历查找的开销那math.sqrt
变体呢。 但我可能是错的:
Python 2.5: 0.191000 vs. 0.224000
Python 2.6: 0.195000与0.139000
另外psyco似乎更好地处理math.sqrt
:
Python 2.5 + Psyco 2.0: 0.109000与0.043000
Python 2.6 + Psyco 2.0: 0.128000与0.067000
| Interpreter | x**.5, | sqrt, | sqrt faster, % | | | seconds | seconds | | |----------------+---------+---------+----------------| | Python 3.2rc1+ | 0.32 | 0.27 | 19 | | Python 3.1.2 | 0.136 | 0.088 | 55 | | Python 3.0.1 | 0.155 | 0.102 | 52 | | Python 2.7 | 0.132 | 0.079 | 67 | | Python 2.6.6 | 0.121 | 0.075 | 61 | | PyPy 1.4.1 | 0.083 | 0.0159 | 422 | | Jython 2.5.1 | 0.132 | 0.22 | -40 | | Python 2.5.5 | 0.129 | 0.125 | 3 | | Python 2.4.6 | 0.131 | 0.123 | 7 | #+TBLFM: $4=100*($2-$3)/$3;%.0f
在机器上产生的表格结果:
$ uname -vms Linux #42-Ubuntu SMP Thu Dec 2 02:41:37 UTC 2010 x86_64 $ cat /proc/cpuinfo | grep 'model name' | head -1 model name : Intel(R) Core(TM) i7 CPU 920 @ 2.67GHz
重现结果:
- 获取源代码:
git clone git://gist.github.com/783011.git gist-783011
- 安装
tox
:pip install tox
- 使用
tox.ini
文件从目录运行tox
。
- 优化的第一条规则: 不要这样做
- 第二条规则: 不要这样做
这里有一些时间(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
这个testing表明x**.5
稍快于sqrt(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
在另一台机器(Ubuntu,Python 2.6和3.1)上, math.sqrt(x)
总是快于x**.5
:
$ 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
你真的有多less根方根? 你想用Python编写一些3Dgraphics引擎吗? 如果没有,那么为什么要使用那些易于阅读的代码来隐藏代码呢? 在任何我可以预见的应用程序中,时间差会比任何人都注意到的要小。 我真的不打算放下你的问题,但似乎你过早的优化太过分了。
在这些微型基准testing中,math.sqrt会比较慢,因为在math命名空间中查找sqrt需要一点时间。 你可以稍微改善它
from math import sqrt
尽pipe如此,通过timeit进行了一些变化,显示出“x ** .5”的性能优势(4-5%),
有趣的是,在做
import math sqrt = math.sqrt
速度加快,速度差在1%以内,统计学意义很小。
我会重复Kibbee,并说这可能是一个不成熟的优化。
最有可能的是math.sqrt(x),因为它是针对平方根的优化。
基准将为您提供您正在寻找的答案。
使用Claudiu的代码,在我的机器上,即使“从math导入sqrt”x **。5更快,但使用psyco.full()sqrt(x)变得更快,至less200%
在Python 2.6中, (float).__pow__()
函数使用C pow()
函数,而math.sqrt()
函数使用C sqrt()
函数。
在glibc编译器中, pow(x,y)
的实现非常复杂,并且针对各种特殊情况进行了优化。 例如,调用C pow(x,0.5)
只需调用sqrt()
函数。
使用.**
或math.sqrt
速度的math.sqrt
是由C函数周围的包装引起的,速度很大程度上取决于系统上使用的优化标记/ C编译器。
编辑:
这里是我的机器上Claudiualgorithm的结果。 我得到了不同的结果:
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
什么是值得的(见吉姆的回答)。 在我的机器上运行python 2.5:
PS C:\> python -m timeit -n 100000 10000**.5 100000 loops, best of 3: 0.0543 usec per loop PS C:\> python -m timeit -n 100000 -s "import math" math.sqrt(10000) 100000 loops, best of 3: 0.162 usec per loop PS C:\> python -m timeit -n 100000 -s "from math import sqrt" sqrt(10000) 100000 loops, best of 3: 0.0541 usec per loop
有人评论了Quake 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。
克劳迪的结果与我的不同。 我在旧的P4 2.4Ghz机器上在Ubuntu上使用Python 2.6 …这是我的结果:
>>> timeit1() Took 0.564911 seconds >>> timeit2() Took 0.403087 seconds >>> timeit1() Took 0.604713 seconds >>> timeit2() Took 0.387749 seconds >>> timeit1() Took 0.587829 seconds >>> timeit2() Took 0.379381 seconds
sqrt对我来说一直是更快的…甚至Codepad.org现在似乎都认为sqrt在本地环境下更快( http://codepad.org/6trzcM3j )。 键盘似乎正在运行Python 2.5。 也许他们在Claudiu第一次回答时使用了2.4或更高版本?
事实上,即使使用math.sqrt(i)代替arg(i),对于sqrt我仍然可以获得更好的时间。 在这种情况下,timeit2()在我的机器上花了0.53秒到0.55秒,仍然比timeit1的0.56-0.60更好。
我想说,在现代的Python中,使用math.sqrt,并将其带到本地上下文中,或者使用somevar = math.sqrt或者从mathimport sqrt中。
更快的是,如果你进入math.py并将函数“sqrt”复制到你的程序中。 你的程序需要花费时间findmath.py,然后打开它,find你正在寻找的function,然后把它带回你的程序。 如果该function即使在“查找”步骤中速度更快,该function本身也必须非常快。 可能会把你的时间减半。 综上所述:
- 去math.py
- find函数“sqrt”
- 复制它
- 将函数粘贴到sqrt查找程序中。
- 时间吧。