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
  • 安装toxpip 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本身也必须非常快。 可能会把你的时间减半。 综上所述:

  1. 去math.py
  2. find函数“sqrt”
  3. 复制它
  4. 将函数粘贴到sqrt查找程序中。
  5. 时间吧。