2017-08-07 79 views
22

我意识到np.power(a, b)慢于np.exp(b * np.log(a))np.power做了哪些额外的工作?

import numpy as np 
a, b = np.random.random((2, 100000)) 
%timeit np.power(a, b) # best of 3: 4.16 ms per loop 
%timeit np.exp(b * np.log(a)) # best of 3: 1.74 ms per loop 

的结果是相同的(具有顺序1E-16的一些数值误差)。

np.power中做了哪些额外的工作?此外,我怎样才能自己找到这类问题的答案?

+6

整个源代码可在https://github.com/numpy/numpy上找到,我在那里找到了几个'power'函数,不能确定哪个是哪个(我没有花时间浏览它),但你可以尝试在那里,只需用引号“def power”作为开始搜索 –

+0

@OferSadan你能告诉我更多一点吗,你在哪里找到这些'power'函数,我自己找不到它们(轮流放NumPy是真的很大......) –

+0

在[github页面]顶部(https://github.com/numpy/numpy)有一个搜索字段。键入''def power“'发现3个命中。 – unutbu

回答

32

Under the hood两个表达式调用相应的C函数powexplogrunning a profiling on those in C++,没有任何numpy的代码,得到:

pow  : 286 ms 
exp(log) : 93 ms 

这与numpy的定时是一致的。因此,看起来主要区别在于C函数powexp(log)慢。

为什么?似乎共振的一部分是表达式对于所有输入都不相同。例如,具有负a和整数bpower作品而exp(log)失败:

>>> np.power(-2, 2) 
4 
>>> np.exp(2 * np.log(-2)) 
nan 

又如0 ** 0

>>> np.power(0, 0) 
1 
>>> np.exp(0 * np.log(0)) 
nan 

因此,exp(log)特技仅适用于的输入的子集,而power适用于所有(有效)输入。

除此之外,power保证根据IEEE 754 standard给出完全精度,而exp(log)可能遭受舍入误差。

+2

至于OP有关自己找答案的问题 - 我检查了调试器的类型:np.power,np.log,np.exp,它是ufunc,在numpy的文档中我发现这些在generate_umath.py中定义为:pow,log和npy_ObjectPower。最后一个实际上是在[此文件]中找到的C函数(https://raw.githubusercontent.com/numpy/numpy/d46df62746995481439b650790589e60a8070172/numpy/core/src/umath/funcs.inc.src),并返回'PyNumber_Power'和这实际上是Python的'pow' [根据文档](https://docs.python.org/3/c-api/number.html) – pierscin

+3

此外,'pow()'总是为您提供双精度的完整精度浮点数,即使在'exp()'和'log()'组合失去了几位数的情况下也是如此。 –

+0

如果您指定了'a = a,您实际上可以对“日志技巧”进行否定处理。astype(complex)'并拉动真实部分,但是你失去了速度优势 –