python x中的指数.**y vs math.pow(x,y)

use*_*006 40 python math built-in pow

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

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

import math

print math.pow(10, 2)

print 10. ** 2
Run Code Online (Sandbox Code Playgroud)

pok*_*oke 81

使用幂运算符**会更快,因为它不会有函数调用的开销.如果你反汇编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         
Run Code Online (Sandbox Code Playgroud)

请注意,我在这里使用变量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
Run Code Online (Sandbox Code Playgroud)

因此,虽然速度powmath.pow速度差不多两倍,但它们仍然足够快,不会太在意.除非您能够将指数确定为瓶颈,否则如果清晰度降低,则没有理由选择一种方法而不是另一种方法.这尤其适用,因为pow例如提供集成的模运算.


阿尔芬在上面的评论中提出了一个很好的问题:

timeit显示math.pow**所有情况都慢.math.pow()无论如何有什么好处?有人知道它可以有什么优势吗?

math.pow内置函数pow和幂**函数的最大区别在于它总是使用浮点语义.因此,如果您出于某种原因想要确保返回一个浮点数,那么math.pow将确保此属性.

让我们想一个例子:我们有两个数字,i并且j不知道它们是浮点数还是整数.但我们希望得到一个浮动结果i^j.那么我们有什么选择呢?

  • 我们可以将至少一个参数转换为float然后执行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
Run Code Online (Sandbox Code Playgroud)

如你所见,math.pow实际上更快!如果你考虑一下,函数调用的开销现在也消失了,因为在所有其他选择中我们必须调用float().


此外,值得注意的是,通过为自定义类型实现特殊(和)方法可以覆盖**和的行为.因此,如果您不想要(无论出于何种原因),使用将不会那样做.pow__pow____rpow__math.pow


bra*_*a90 17

pow() 函数将允许您添加第三个参数作为模数。

例如:我最近在做的时候遇到了内存错误

2**23375247598357347582 % 23375247598357347583

相反,我做了:

pow(2, 23375247598357347582, 23375247598357347583)

这仅在几毫秒内返回,而不是普通指数占用的大量时间和内存。因此,在处理大数和并行模数时,pow() 更有效,但是在处理没有模数的较小数时,** 更有效。


wim*_*wim 5

好吧,它们确实用于不同的任务。

当您需要整数算术时使用pow(相当于x ** y使用两个参数)。

并使用math.pow你想浮动输出,如果任一参数为float和。

有关pow和之间差异的讨论math.pow,请参阅此问题


Wol*_*olf 5

仅针对协议:**运算符等效于内置pow函数的双参数版本,如果前两个参数是整数,则该pow 函数接受可选的第三个参数(模数)。

因此,如果您打算根据幂计算余数,请使用内置函数。该math.pow会给你合理的大小的参数错误的结果:

import math

base = 13
exp = 100
mod = 2
print math.pow(base, exp) % mod
print pow(base, exp, mod)
Run Code Online (Sandbox Code Playgroud)

当我运行这个时,我遇到0.0了第一种情况,这显然不可能是真的,因为 13 是奇数(因此它是整数幂)。该math.pow版本使用IEEE-754 双精度(52 位尾数,略小于 16 位小数)的有限精度,这会导致这里出现错误。

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

import math

base = 13
exp = 100
mod = 2
print math.pow(base, exp) % mod
print pow(base, exp, mod)
Run Code Online (Sandbox Code Playgroud)

math.pow函数在工程应用中具有(并且仍然具有)其优势,但对于数字理论应用,您应该使用内置pow函数。


一些网上例子


更新(不可避免的修正):
我删除的时间比较math.pow(2,100)pow(2,100)因为math.pow给出了一个错误的结果,而在例如,之间的比较pow(2,50),并math.pow(2,50)会一直公平(虽然不是一个现实使用的math-module功能)。我添加了一个更好的以及导致math.pow.


小智 5

**确实更快math.pow(),但如果你想要一个简单的二次函数,就像你的例子一样,使用产品会更快。

10.*10.
Run Code Online (Sandbox Code Playgroud)

然后会更快

10.**2
Run Code Online (Sandbox Code Playgroud)

对于一次操作(使用timeit),差异不大且不明显,但对于大量操作,差异可能很大。