python中的指数:x**y vs math.pow(x, y) [英] Exponentials in python: x**y vs math.pow(x, y)
问题描述
使用 math.pow
或 **
运算符哪个更有效?我什么时候应该使用一个?
到目前为止,我知道 x**y
可以返回 int
或 float
如果您使用小数函数 pow
将返回一个浮点数
导入数学打印( math.pow(10, 2) )打印(10.**2)
使用幂运算符 **
会更快,因为它不会产生函数调用的开销.如果反汇编 Python 代码,您可以看到这一点:
请注意,我在这里使用变量 i
作为指数,因为像 7 这样的常量表达式.** 5
实际上是在编译时计算的.
现在,在实践中,这种差异并不重要,正如您在计时时所看到的:
<预><代码>>>>从时间导入时间>>>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因此,虽然 pow
和 math.pow
的速度大约是其两倍,但它们仍然足够快,不必太在意.除非您确实可以将求幂确定为瓶颈,否则如果清晰度降低,就没有理由选择一种方法而不是另一种方法.这尤其适用,因为 pow
提供了一个集成的例如模运算.
Alfe 在上面的评论中提出了一个很好的问题:
<块引用>timeit
显示 math.pow
在所有情况下都比 **
慢.math.pow()
到底有什么用?有没有人知道它可以有什么优势?
math.pow
与内置 pow
和幂运算符 **
的最大区别在于它总是 使用浮点语义.因此,如果您出于某种原因想要确保返回浮点数,那么 math.pow
将确保此属性.
让我们想一个例子:我们有两个数字,i
和 j
,并且不知道它们是浮点数还是整数.但是我们想要一个 i^j
的浮点结果.那么我们有哪些选择?
- 我们可以将至少一个参数转换为浮点数,然后执行
i ** j
. - 我们可以执行
i ** j
并将结果转换为浮点数(当i
或j
浮动,所以结果是一样的). - 我们可以使用
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
都不会这样做.
Which one is more efficient using math.pow
or the **
operator? When should I use one over the other?
So far I know that x**y
can return an int
or a float
if you use a decimal
the function pow
will return a float
import math
print( math.pow(10, 2) )
print( 10. ** 2 )
Using the power operator **
will be faster as it won’t have the overhead of a function call. You can see this if you disassemble the Python code:
>>> 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
Note that I’m using a variable i
as the exponent here because constant expressions like 7. ** 5
are actually evaluated at compile time.
Now, in practice, this difference does not matter that much, as you can see when timing it:
>>> 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
So, while pow
and math.pow
are about twice as slow, they are still fast enough to not care much. Unless you can actually identify the exponentiation as a bottleneck, there won’t be a reason to choose one method over the other if clarity decreases. This especially applies since pow
offers an integrated modulo operation for example.
Alfe asked a good question in the comments above:
timeit
shows thatmath.pow
is slower than**
in all cases. What ismath.pow()
good for anyway? Has anybody an idea where it can be of any advantage then?
The big difference of math.pow
to both the builtin pow
and the power operator **
is that it always uses float semantics. So if you, for some reason, want to make sure you get a float as a result back, then math.pow
will ensure this property.
Let’s think of an example: We have two numbers, i
and j
, and have no idea if they are floats or integers. But we want to have a float result of i^j
. So what options do we have?
- We can convert at least one of the arguments to a float and then do
i ** j
. - We can do
i ** j
and convert the result to a float (float exponentation is automatically used when eitheri
orj
are floats, so the result is the same). - We can use
math.pow
.
So, let’s test this:
>>> 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
As you can see, math.pow
is actually faster! And if you think about it, the overhead from the function call is also gone now, because in all the other alternatives we have to call float()
.
In addition, it might be worth to note that the behavior of **
and pow
can be overridden by implementing the special __pow__
(and __rpow__
) method for custom types. So if you don’t want that (for whatever reason), using math.pow
won’t do that.
这篇关于python中的指数:x**y vs math.pow(x, y)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!