为什么“np.inf // 2”结果是NaN而不是无穷大?

41

我有点失望,np.inf // 2的计算结果是np.nan而不是像正常的除法一样是np.inf

难道选择naninf更好吗?我是否遗漏了什么原因?


floor_divide 可能比分别执行这两个操作更有效率。 - Mark Ransom
9
我认为inf是整数除法的错误结果,因为inf不是整数。虽然nan也不是整数,但它至少能够表达所提出的问题没有正确答案的事实,也就是说,不存在一个整数 x 能使得 x*2 等于inf。这就是我的看法。 - sepp2k
@0x5453 - 你说得对。那么问题是,为什么在这里,“nan”被认为比“inf”更好的选择? - Aguy
@sepp2k,总的来说我同意你的答案,尽管我不确定原因是因为np.inf不是整数。13.2 // 2返回6.0。13.2和np.inf都是浮点类型。 - Ethan
1
@phuclv:我很确定INF除以任何东西,除了INF或NaN之外,仍然是+-INF。但这是针对常规除法而言的,不是针对地板除法;我不知道IEEE-754是否定义了该操作;C语言没有它,现实世界中的FPUs也没有它。(您可以将舍入模式设置为截断或朝向-Inf,并仍然获得Inf。) - Peter Cordes
显示剩余8条评论
3个回答

33
我将成为一个只是指出C级别实施的人,而不试图解释意图或理由。
*mod = fmod(vx, wx);
div = (vx - *mod) / wx;

看起来为了计算浮点数的「divmod」(当您只是进行地板除法时调用),它首先计算模数并且 float('inf') % 2 只有意义上的结果是 NaN,所以当计算 vx - mod 时,得到的结果就是 NaN,因此整个过程都传播了 NaN。
简而言之,由于地板除法的实现使用了模数计算,而该模数是 NaN,因此地板除法的结果也最终变为 NaN

6
如果这确实是实现浮点数取整除法的 C 代码,那么它可能是正确的,但非常令人不满意。你只是把问题推到了下一步。 - Mark Ransom
8
我知道,我很想看到一个更好的答案。但是也有可能的推理是“直到现在没有人真正考虑过这个问题”,如果是这种情况,恐怕这就是唯一的答案。 - Tadhg McDonald-Jensen
为什么不只使用一行代码,将 div = (vx - *mod) / wx; 中的 *mod 替换为其上方等号后面的部分呢? - rautamiekka
@rautamiekka 这是计算模数和地板除法的源代码,它需要保留模数。 - Tadhg McDonald-Jensen
@TadhgMcDonald-Jensen 所以这个值稍后会被重复使用? - rautamiekka
@rautamiekka 如果您按照答案中的链接,您将亲眼看到它是如何使用的。 - Tadhg McDonald-Jensen

25

与取模运算一起构成 divmod 操作的一部分,地板除法是相对于模定义的。

二进制算术运算符

地板除法和模运算符通过以下等式相互连接:x == (x//y)*y + (x%y)。地板除法和模也与内置函数 divmod() 相关:divmod(x, y) == (x//y, x%y)

这个等式不能适用于 x = inf——余数 inf % y 未定义——使得 inf // y 不明确。这意味着 nan 至少和 inf 一样好。为简单起见,CPython 实际上只实现了 divmod 并且通过舍弃结果的一部分来推导出 // 和 % — 这意味着 // 从 divmod 继承 nan


1

无穷大不是一个数。例如,你甚至不能说 无穷大减去无穷大等于零。所以你会遇到像这样的限制,因为NumPy是一个数值数学包。我建议使用一个符号数学包,比如SymPy,它可以处理许多不同的表达式,包括无穷大:

import sympy as sp

sp.floor(sp.oo/2)
sp.oo - 1
sp.oo + sp.oo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接