Python中的指数函数x.**y与math.pow(x, y)的比较

2024-06-17 08:13:53 发布

您现在位置:Python中文网/ 问答频道 /正文

使用math.pow或**运算符哪个更有效?我应该什么时候用一个代替另一个?

到目前为止,我知道x**y可以返回intfloat,如果使用十进制 函数pow将返回一个浮点数

import math

print math.pow(10, 2)

print 10. ** 2

Tags: 函数import运算符mathfloatintprint浮点数
3条回答

使用power运算符**将更快,因为它没有函数调用的开销。如果反汇编Python代码,可以看到这一点:

>>> dis.dis('7. ** i')
  1           0 LOAD_CONST               0 (7.0) 
              3 LOAD_NAME                0 (i) 
              6 BINARY_POWER         
              7 RETURN_VALUE         
>>> dis.dis('pow(7., i)')
  1           0 LOAD_NAME                0 (pow) 
              3 LOAD_CONST               0 (7.0) 
              6 LOAD_NAME                1 (i) 
              9 CALL_FUNCTION            2 (2 positional, 0 keyword pair) 
             12 RETURN_VALUE         
>>> dis.dis('math.pow(7, i)')
  1           0 LOAD_NAME                0 (math) 
              3 LOAD_ATTR                1 (pow) 
              6 LOAD_CONST               0 (7) 
              9 LOAD_NAME                2 (i) 
             12 CALL_FUNCTION            2 (2 positional, 0 keyword pair) 
             15 RETURN_VALUE         

注意,我在这里使用变量i作为指数,因为像7. ** 5这样的常量表达式实际上是在编译时计算的。

现在,在实践中,这种差异并没有那么重要,正如你在计时时所看到的:

>>> from timeit import timeit
>>> timeit('7. ** i', setup='i = 5')
0.2894785532627111
>>> timeit('pow(7., i)', setup='i = 5')
0.41218495570683444
>>> timeit('math.pow(7, i)', setup='import math; i = 5')
0.5655053168791255

所以,虽然powmath.pow的速度大约是后者的两倍,但它们仍然足够快,不需要太多关注。除非你真的能将指数化识别为一个瓶颈,否则如果清晰度降低,就没有理由选择一种方法而不是另一种方法。这尤其适用,因为^{}提供了一个集成的模操作。


阿尔夫在上面的评论中问了一个好问题:

timeit shows that math.pow is slower than ** in all cases. What is math.pow() good for anyway? Has anybody an idea where it can be of any advantage then?

与内置的pow和幂运算符**的最大区别在于它始终使用浮点语义。因此,如果出于某种原因,您想确保返回的结果是float,那么math.pow将确保此属性。

举个例子:我们有两个数字,ij,不知道它们是浮点数还是整数。但是我们想要一个i^j的浮点结果。我们有什么选择?

  • 我们至少可以将其中一个参数转换为浮点,然后执行i ** j
  • 我们可以做i ** j并将结果转换为浮点(当ij是浮点时,会自动使用浮点指数,因此结果是相同的)。
  • 我们可以使用math.pow

那么,让我们来测试一下:

>>> timeit('float(i) ** j', setup='i, j = 7, 5')
0.7610865891750791
>>> timeit('i ** float(j)', setup='i, j = 7, 5')
0.7930400942188385
>>> timeit('float(i ** j)', setup='i, j = 7, 5')
0.8946636625872202
>>> timeit('math.pow(i, j)', setup='import math; i, j = 7, 5')
0.5699394063529439

如您所见,math.pow实际上更快!如果你仔细想想,函数调用的开销现在也没有了,因为在所有其他选择中,我们都必须调用float()


此外,值得注意的是,**pow的行为可以通过为自定义类型实现特殊的__pow__(和__rpow__)方法来重写。因此,如果您不想这样做(无论出于什么原因),那么使用math.pow就不会这样做。

嗯,他们是为不同的任务,真的。

如果需要整数运算,请使用pow(相当于带两个参数的x ** y)。

如果其中一个参数是float,并且需要float输出,则使用math.pow

有关powmath.pow之间的区别的讨论,请参见本question

仅对于协议:如果前两个参数是整数类型,则**运算符调用built-in ^{} function,后者接受可选的第三个参数(模)。

所以,如果你想计算来自异能的余数,使用内置函数。math.pow可能会给出错误的结果:

import math

base = 13
exp = 100
mod = 2
print math.pow(base, exp) % mod
print pow(base, exp, mod)

当我运行这个程序时,我得到了0.0在第一个例子中,这显然不是真的,因为13是奇数(因此所有的积分幂)。math.pow版本使用的精度有限,这会导致错误。

为了公平起见,我们必须说,math.pow可以更快:

import timeit
print timeit.timeit("math.pow(2, 100)",setup='import math')
print timeit.timeit("pow(2, 100)")

以下是我的输出:

0.240936803195
1.4775809183

一些在线示例

相关问题 更多 >