在使用NumPy或SciPy时,最常见的会导致Python中出现NaN
的操作是什么?
例如:
1e500 - 1e500
>>> nan
这种行为的原因是什么,为什么它不返回0?
在使用NumPy或SciPy时,最常见的会导致Python中出现NaN
的操作是什么?
例如:
1e500 - 1e500
>>> nan
这种行为的原因是什么,为什么它不返回0?
如果你不涉及操作浮点数环境并执行以下任何一项操作,你应该会在之前没有 NaN 的地方得到一个 NaN:
0/0
(分子和分母都是任意符号)inf/inf
(分子和分母都是任意符号)inf - inf
或 (-inf) + inf
或 inf + (-inf)
或 (-inf) - (-inf)
0 * inf
和 inf * 0
(两个因子中有任意符号)x < 0
时的 sqrt(x)
y = 0
或 x
是无限大时的 fmod(x, y)
;其中 fmod
是浮点余数运算。关于这些机器算术方面的规范参考是IEEE 754 规范。第 7.1 节描述了无效操作异常,当你即将得到 NaN 时会引发此异常。在 IEEE 754 中,“异常”与编程语言上下文中的含义不同。
许多特殊函数实现文档记录了它们在要实现的函数的奇点处的行为。例如,参见 atan2
和 log
的手册页。
你特别询问了 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);
nan + <任何数>
, nan * <任何数>
等等。(当然,你已经说过“在以前不存在nan的情况下”,这排除了这些情况。但还是值得明确提到nan会通过任何计算传播。) - Joe Kington
0/0
会引发ZeroDivisionError错误,而使用numpy(在底层使用C语言),您将得到一个NaN。 - user707650nan
值,而你不知道为什么。如果提问者重新表述问题,询问使用numpy/scipy
时最常见/可能导致nan
的原因,但不包括其他库,我会投票支持重新开放该问题。 - gg349