使用numpy或scipy可能会返回NaN的一些计算是什么?

65

在使用NumPy或SciPy时,最常见的会导致Python中出现NaN的操作是什么?

例如:

1e500 - 1e500
>>> nan

这种行为的原因是什么,为什么它不返回0?


5
你需要提供更具体的信息。如果你包含了库(包括 numpy 标签),那么这是一个完全开放式的问题。从2.6版本开始,特殊情况的行为现在旨在遵循 C99 附录 F。在早期版本的 Python 中,特殊情况的行为规定不够明确。 - will
5
您添加了numpy标签,但这与您的问题不相符:在Python中,0/0会引发ZeroDivisionError错误,而使用numpy(在底层使用C语言),您将得到一个NaN。 - user707650
5
也许这个问题比较宽泛,但它是一个好问题,因为它回答了一个经常出现的重要问题:在代码中得到一个 nan 值,而你不知道为什么。如果提问者重新表述问题,询问使用 numpy/scipy 时最常见/可能导致 nan 的原因,但不包括其他库,我会投票支持重新开放该问题。 - gg349
5
我认为原问题并没有“太宽泛”的问题。获得NaN的方式是有限的,了解所有方式是一个很好的目标。就我所知,原问题表述清晰,范围适当且符合主题。 - tmyklebu
17
对于可能的投票者:在您投票之前,请访问此元问题 - rene
显示剩余7条评论
1个回答

74

如果你不涉及操作浮点数环境并执行以下任何一项操作,你应该会在之前没有 NaN 的地方得到一个 NaN:

  • 0/0(分子和分母都是任意符号)
  • inf/inf(分子和分母都是任意符号)
  • inf - inf(-inf) + infinf + (-inf)(-inf) - (-inf)
  • 0 * infinf * 0(两个因子中有任意符号)
  • x < 0 时的 sqrt(x)
  • y = 0x 是无限大时的 fmod(x, y);其中 fmod 是浮点余数运算。

关于这些机器算术方面的规范参考是IEEE 754 规范。第 7.1 节描述了无效操作异常,当你即将得到 NaN 时会引发此异常。在 IEEE 754 中,“异常”与编程语言上下文中的含义不同。

许多特殊函数实现文档记录了它们在要实现的函数的奇点处的行为。例如,参见 atan2log 的手册页。

你特别询问了 NumPy 和 SciPy。我不确定这是否仅是说“我在询问 NumPy 后台发生的机器算术”还是“我在询问 eig() 等内容。” 我假设是前者,但本答案的其余部分尝试将其与 NumPy 中更高级别的函数进行模糊联系。基本规则是:如果函数的实现违反了上述任何原则,则会得到 NaN。

例如,对于 fft,如果输入值在 1e1010 或更大,则有可能得到 NaN,如果输入值在 1e-1010 或更小,则可能会导致精度损失而不报错。但除非输入完全荒谬的比例,否则在使用 fft 方面是相当安全的。

对于涉及矩阵数学的事情,如果你的数字很大矩阵极度病态,则可能会遇到 NaN(通常是通过 inf - inf 路线)。关于如何受到数值线性代数影响的完整讨论太长,不适合放在答案中。我建议在几个月的时间里阅读一本数字线性代数书籍(Trefethen 和 Bau 是受欢迎的)。

在编写和调试“不应该”生成 NaN 的代码时,我发现一个有用的技巧是告诉机器如果出现 NaN 则陷入陷阱。在 GNU C 中,我这样做:

#include <fenv.h>
feenableexcept(FE_INVALID);

10
别忘了那些显而易见的情况... nan + <任何数>, nan * <任何数>等等。(当然,你已经说过“在以前不存在nan的情况下”,这排除了这些情况。但还是值得明确提到nan会通过任何计算传播。) - Joe Kington
@JoeKington:是的,我的措辞很糟糕。不过那就是我想表达的意思;感谢你澄清了一下。 - tmyklebu
1
这是指哪个版本的Python?当我在Python 2.7.11和Python 3.5.1上将0/0相除时,会出现ZeroDivisionError。对于0.0 / 0.0也是如此。 - tba
3
这是一个关于NumPy的问题。 - tmyklebu
1
还有 np.arscin(-2) 或者其他在定义外被调用的函数。 - tyrex
IEEE 754规范的链接已经失效。 - luator

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