代码中出现的错误,不应该根据延迟评估运行

时间:2015-03-03 15:59:17

标签: python-2.7 numpy runtime-error divide-by-zero

我将以下代码作为函数的一部分:

px = x2 - x1
py = y2 - y1
pz = z2 - z1

div = px*px + py*py    

u = ((x0 - x1) * px + (y0 - y1) * py) / div

u=行在运行时返回RuntimeWarning: invalid value encountered in divide。这是因为偶尔div=行返回零。

但是,如果我将u=行重写为:

u = np.where(div != 0, ((x0 - x1) * px + (y0 - y1) * py) / div, 0)

它仍会返回相同的运行时警告。

此代码输出所需的数字,但我认为np.where函数是懒惰的。如果不是这种情况,那么我写的其他代码中有可能加速(因此我问这个问题)。 我错过了什么? np.where函数是否计算'True'和'False输入,然后根据布尔值选择一个?

请注意,这是我最终得到的解决方案:

np.seterr(invalid='ignore')
u = np.where(div != 0, ((x0 - x1) * px + (y0 - y1) * py) / div, 0)
np.seterr(invalid='warn')

虽然这也很好:

u = np.zeros_like(div)
divb = div != 0
u[divb] = ((x0[divb] - x1[divb]) * px[divb] + 
        (y0[divb] - y1[divb]) * py[divb]) / div[divb]

(这是我认为的np.where所做的......)

这两种解决方案的速度大致相同,但两者都比np.where函数慢。

欢迎任何解释/建议! 感谢。

1 个答案:

答案 0 :(得分:2)

自从最早的矢量化语言(例如APL,MATLAB)以来,程序员一直在努力解决这个问题。

我过去使用的一个解决方案是(有条件地)将1加到除数中:

u = ((x0 - x1) * px + (y0 - y1) * py) / (div + (div==0))

它并非在所有情况下都有效,但可能在此情况下,因为只有当divpx都为0时,py才会显示为0。在这种情况下分子也是0. 0/1 = 0

使用较小的值剪切div(这可能是最快的解决方案):

..../np.maximum(div,1e-16)

numpy divide by zero的SO快速搜索发现了其他问题。例如:

https://stackoverflow.com/a/26248892/901925 建议使用errstate上下文关闭警告:

with numpy.errstate(divide='ignore'):
    u = .../div

divide适用于1/0等案件,invalid案件需要0/0。但ignore最终会将infnan放入返回数组中。因此,您仍需要测试(div==0)以获得0值。

虽然我更喜欢这种形式的外观:

with np.errstate(invalid='ignore'):
    u = np.where(div==0, 0, .../div)

沃伦的评论解释了为什么where不起作用。参数在传递给函数之前进行求值。延迟评估需要Python解释器的合作。它通常是语法的一部分(例如if|&)。