Python-使用内置与数学模块进行数学运算

Python-使用内置与数学模块进行数学运算,python,performance,python-2.7,Python,Performance,Python 2.7,如果x是一个数字。在python中,x**(1/2.0)[或者甚至x**(0.5)]和sqrt(x)做完全相同的事情。这两种方法都将返回给定数字的平方根。对于sqrt,尽管我们必须导入数学模块(form math import sqrt)。是否有任何理由使用一种方法而不是另一种方法?我想知道:因为必须导入sqrt(),它会更快吗?如果计算一个常数整数的平方根,**运算符可能比sqrt快几倍,但是当使用变量时,sqrt比**和数学都快。sqrt: In [38]: %timeit -n100000

如果x是一个数字。在python中,
x**(1/2.0)
[或者甚至
x**(0.5)
]和
sqrt(x)
做完全相同的事情。这两种方法都将返回给定数字的平方根。对于
sqrt
,尽管我们必须导入数学模块(
form math import sqrt
)。是否有任何理由使用一种方法而不是另一种方法?我想知道:因为必须导入
sqrt()
,它会更快吗?

如果计算一个常数整数的平方根,
**
运算符可能比
sqrt
快几倍,但是当使用变量时,
sqrt
**
数学都快。sqrt
:

In [38]: %timeit -n1000000 3**.5
1000000 loops, best of 3: 46.7 ns per loop

In [39]: %timeit -n1000000 sqrt(3)
1000000 loops, best of 3: 312 ns per loop

In [40]: %timeit -n1000000 math.sqrt(3)
1000000 loops, best of 3: 377 ns per loop

In [41]: x=3

In [42]: %timeit -n1000000 x**.5
1000000 loops, best of 3: 469 ns per loop

In [43]: %timeit -n1000000 sqrt(x)
1000000 loops, best of 3: 327 ns per loop

In [44]: %timeit -n1000000 math.sqrt(x)
1000000 loops, best of 3: 430 ns per loop

这完全取决于你想做什么

对于一个简单的表达式,操作符可能会超出
math.sqrt
,但是如果需要用作回调,那么使用
math.sqrt
会比使用操作符生成lambda执行得更好

In [4]: %timeit math.sqrt(3)
10000000 loops, best of 3: 148 ns per loop

In [5]: %timeit 3**.5
100000000 loops, best of 3: 19.5 ns per loop

In [12]: %timeit -n 1000 map(lambda e: e**.5, range(1,100))
1000 loops, best of 3: 31.3 us per loop

In [13]: %timeit -n 1000 map(math.sqrt, range(1,100))
1000 loops, best of 3: 14.6 us per loop

如果您想直接查看python字节码来深入了解这些差异,我建议使用
dis
模块。下面是一个例子,说明了为什么数学版本不同

>>> import math
>>> import dis
>>>
>>> def builtin(number):
...     return number ** 0.5
... 
>>> def with_math(number):
...     return math.sqrt(number)
... 
>>> dis.dis(builtin)
  2           0 LOAD_FAST                0 (number)
              3 LOAD_CONST               1 (0.5)
              6 BINARY_POWER        
              7 RETURN_VALUE        
>>> dis.dis(with_math)
  2           0 LOAD_GLOBAL              0 (math)
              3 LOAD_ATTR                1 (sqrt)
              6 LOAD_FAST                0 (number)
              9 CALL_FUNCTION            1
             12 RETURN_VALUE  

可能应该忽略
with_math
选项中的前两个命令,因为它们不必每次调用时都发生。但是你可以看到这两个函数实际上非常相似。主要区别在于,数学版用一个
调用函数
替换了
加载常数
二进制幂
。虽然查找会使启动速度变慢,但从长远来看,
math
版本会更快,因为您可以在很大程度上忽略前6个周期。

您可以轻松地使用。。。可能有细微的差别。。。如果您只需要sqrt,我只需要使用
sqrt=lambda x:x**0.5
。。。但是如果你需要其他的数学知识,请使用数学库。。。早期优化是python中的一大罪过
x**(1/2)
无法实现您在python 2.7中所期望的效果。@Wooble感谢我现在修复了它。我正准备这样做:Pyou为每个循环执行不同数量的循环。这并不重要。如果两个测试用例的比较结果相等,那就太好了。方法查找要了你的命。当您从math导入sqrt
,然后调用
sqrt(x)
,这比
**
快得多。公平地说,在两者中使用变量而不是int常量会使它们更接近<代码>3**.5
可以进行优化,并且只能运行一次。@Wooble当我得知Python试图进行这种优化时,我会感到惊讶。据我所知,python不尝试任何优化,因为即使是基本运算符也可以更改。如果我错了,请纠正我。这并不慢;您正在执行OP没有执行的属性查找。@Wooble您完全正确,再次查看输出并更新了答案。我没有对您的答案进行投票。你能告诉我为什么每个循环的次数不同吗?@JebediahKerman:timeit很神奇,它自己选择循环的次数。@Wooble我认为如果每个循环的次数相等,结果会更有意义method@JebediahKerman当前位置除非它不知怎么坏了,否则它不重要。它用来确定要运行多少个循环的算法是为了使结果正确。不过,你可以随意强迫它运行更多的程序来确认你得到的结果是一样的。@JebediahKerman:我不知道;我不认为那很重要。timeit返回一个平均值,因此,它在执行计算时有一些启发性的想法。