为啥 NaN^0 == 1

Posted

技术标签:

【中文标题】为啥 NaN^0 == 1【英文标题】:Why does NaN^0 == 1为什么 NaN^0 == 1 【发布时间】:2013-07-25 16:14:25 【问题描述】:

早期代码打高尔夫球的地方提示为什么会:

>NaN^0
[1] 1

NA^0 为 1 非常有意义,因为 NA 缺少数据,并且 任何 数字增加到 0 将给出 1,包括 -InfInf。然而NaN 应该代表not-a-number,那么为什么会这样呢?当?NaN 的帮助页面指出:

在 R 中,基本上所有的数学函数(包括基本的 Arithmetic),应该与 +/- InfNaN 一起正常工作 输入或输出。

基本规则应该是与Infs的调用和关系确实是 具有适当数学极限的语句。

涉及NaN 的计算将返回NaNNA: 这两个不能保证,可能取决于 R 平台(因为 编译器可能会重新排序计算)。

这背后是否有哲学上的原因,还是仅仅与 R 如何表示这些常数有关?

【问题讨论】:

我不知道 R 但在我机器上的 Python 中也发生了同样的错误:1**nan 返回 1.0 @hivert 至少在 R 的情况下^ 是一个不只是调用C 函数pow 的函数,它检查基数为 1 或指数为 0,如果任一为 TRUE,则在调用 pow 之前返回 1.if((x1 = INTEGER(s1)[i1]) == 1 || (x2 = INTEGER(s2)[i2]) == 0); REAL(ans)[i] = 1.; 我不相信NA^0 == 1 有多大意义,因为Inf^0 是一个不确定的形式。也就是说,当被视为极限时,我们不能仅从这种形式确定原始极限的值是多少。例如,当 n 接近无穷大时,exp(n)^*(1/n) 接近 e,但 n^(1/n) 接近 1,即使两者看起来都像 Inf^0 对此的评论:“任何增加到 0 的数字都会给出 1,包括 -Inf 和 Inf”:对于 -Inf 和 +Inf,值应该是 NaN,因为这些是不确定的限制。当 x 接近 0 时,想想 (1 + 1/x)^x。 【参考方案1】:

这在?'NaN'引用的帮助页面中引用

“IEC 60559 标准,也称为 ANSI/IEEE 754 浮点标准。

http://en.wikipedia.org/wiki/NaN。”

您可以在此处找到关于应该创建 NaN 的声明:

 "There are three kinds of operations that can return NaN:[5]
       Operations with a NaN as at least one operand.

它可能来自特定的 C 编译器,如您引用的注释所示。这就是 GNU C 文档所说的:

http://www.gnu.org/software/libc/manual/html_node/Infinity-and-NaN.html

“另一方面,NaN 会感染任何涉及它的计算。除非无论用什么实际值替换 NaN,计算都会产生相同的结果,否则结果就是 NaN。”

所以 GNU-C 人在编写代码时似乎有不同的标准。据报道,2008 年版的 ANSI/IEEE 754 浮点标准提出了这一建议:

http://en.wikipedia.org/wiki/NaN#Function_definition

发布的标准不是免费的。所以如果你有访问权限或有钱,你可以看这里:

http://ieeexplore.ieee.org/xpl/mostRecentIssue.jsp?punumber=4610933

【讨论】:

我从帮助页面添加了注释。 (我当然不打算涵盖“所有可能的编译器”。)我会说 GNU-C 编译器的当前行为不同意“注意”。 @BlueRaja-DannyPflughoeft 等效的 C 函数是 pow。 R 中的内置求幂函数^ 通过对传递给它的参数进行一些检查来调用powNaN^0 在 R 中等同于 `^`(NaN,0)。请参阅我在 OP 下面的评论,了解调用 before pow 执行的 R 源代码(用 C 编写)。我认为 DWin 对 R 非常熟悉。 @BlueRaja-DannyPflughoeft:我开始使用“NaN”的帮助页面搜索权威描述。它把我引向了 IEEE 标准。 R 是用 C 编写的,因此在实践中,像这样的边缘情况似乎有可能由 GNU-C 编译器中带有“^”的 NaN 的“通常”行为来确定。答案有多种形式,通常是历史性的,就像这里的情况一样。 它还说“在 R 中,基本上所有的数学函数(包括基本的‘算术’)都应该在‘+/- Inf’和‘NaN’作为输入或输出时正常工作。”所以我认为这是 R 中的一个错误 - 特别是 `NA ^ 0 == 1" 绝对是错误的。 @SimonO101 我不明白为什么元素的类是相关的:NA_real_ ^ 0 是 1,显然违反了通常的缺失值传播规则:NA_real_ * 0,是 NA,而不是 0 .【参考方案2】:

答案可以用“历史原因”来概括。

似乎 IEEE 754 引入了两个 different power functions - powpowr,后者在 OP 情况下保留了 NaN,并且还为 Inf^00^0 返回了 NaN1^Inf,但最终后者被删除为explained briefly here。

从概念上讲,我在 NaN 保留阵营,因为我是从限制的角度来解决这个问题的,但从方便的角度来看,我希望当前的约定更容易处理,即使它们不在某些情况下没有多大意义(例如,sqrt(-1)^0 等于 1 而所有操作都是实数,如果有的话,意义不大)。

【讨论】:

那个链接读起来很有趣。我本来希望 R 的 minmax 忽略 NaN,但 NaN^1 是 NaN。你不能总是得到你想要的。 我相信 IEEE754-2008 标准的最终版本实际上同时具有 powpowr,以及用于将任意浮点数提高到整数幂的 pownpow(qNaN, 0)pown(qNaN, 0)定义为1powr(qNaN, 0) 表示无效操作异常,因此在默认的 FP 异常处理下返回 qNaN 关于 IEEE 754 历史的非常有趣的读物。NaN 保留还有另一个优势(对于最小值/最大值或其他任何东西):NaN 可能出现在之前的计算中,在其他情况下会给出一个可用的 double 值,它可以被比较/使用/... NaN 然后被视为一个异常值,并且仅仅是一个错误(由于某种原因,作为溢出,计算变坏了)。保留 NaN 至少可以最终看到某处存在错误,并且不会默默地给出不正确的答案。发送信号 NaN 也是一种在错误发生时捕获错误的方法。 “NaN 保留”概念实际上与“NA 保留”相同。所以在数值计算中,NA 和 NaN 总是(?,你能找到一个例外吗?)同等/类似地对待。更多在下面的单独“回复”中。回复sqrt(-1)^0:这正是一个很好的例子,为什么NaN^0应该给出1:sqrt(-1 + 0i)^0确实给出1(+0i):sqrt(-1+0i)^0 == 1确实是TRUE @MartinMächler 你没有抓住重点。假设我定义了我自己的函数,该函数在集合 [0,Inf) 上定义,并且未在其他情况下定义:f = function(x) if (x >= 0) x else NaNf(-1)^0 绝不会等于 1,但 R 会告诉你它是。【参考方案3】:

是的,我来晚了,但作为参与此设计的 R Core 成员,让我回忆一下我上面的评论。 NaN 保留和 NA 保留在 R 中“等效”工作,因此如果您同意 NA^0 应该给出 1,则 NaN^0 |-> 1 是结果。

确实(正如其他人所说)您应该真正阅读 R 的帮助页面,而不是 C 或 IEEE 标准,回答这些问题, 和 SimonO101 正确引用了

1 ^ y 和 y ^ 0 始终为 1

而且我很确定我参与其中(如果不是作者的话)。 请注意,能够提供非 NaN 答案是,也不错,在其他编程语言做不同的情况下也是如此。 这种规则的结果是更多的事情自动正确地工作。 在另一种情况下,R 程序员会被敦促自己做更多特殊的套管。

或者换一种说法,上面的简单规则(在所有情况下都返回非 NaN)是一个很好的规则,因为它在数学意义上传播了连续性:lim_x f(x) = f(lim x)。 我们有一些情况,显然是有利的(即不需要特殊的大小写,我重复一遍..)遵守上述“= 1”规则,而不是传播 NaN。正如我进一步说的,sqrt(-1)^0 也是这样一个例子,因为 1 只要你扩展到复平面就是正确的结果。

【讨论】:

大声笑,如果有人认为 NaN^0 不应该给出 1,为什么有人会同意 NA^0 应该给出 1? NANaN 的超集。你弄错了 if-else 方向。 好吧,OP 确实是这么说的! :) 很公平 - 两个你们应该更清楚 以及为什么我的总结性评论来自一个知道“为什么”这个问题的答案的人。因为我已经共同实现了它,所以被否决投票。 ..天堂仁慈! -1 来自我,主要是因为你说这个选择是“好的”,没有任何论据来支持它【参考方案4】:

这是一个原因。来自Goldberg:

在 IEEE 754 中,NaN 通常表示为浮点数 指数 e_max + 1 和非零有效数。

所以NaN 是一个浮点数,尽管有特殊含义。将一个数的零次幂设置为零,因此它将不再是 NaN。

另请注意:

> 1^NaN
[1] 1

一是指数已经为零的数字。

【讨论】:

那么,您的说法是他们希望避免处理特殊情况?但是,浮点计算已经不得不处理由NaN(以及+/- Inf+/- 0和非规范化数字)引起的一些特殊情况,所以... 如果碰巧 NaN 被表示为例如2,根据您的逻辑,1+NaN 将等于 3。您无法根据您选择的表示方式对某些结果应该是得出什么结论。【参考方案5】:

从概念上讲,NaN^0 == 1 的唯一问题是零值至少有四种不同的方式,但 IEEE 格式对其中三种使用相同的表示。上面的公式相等适用于最常见的情况(这是三种情况之一),但不适用于其他情况。

顺便说一句,我认识的四种情况是:

文字零 无符号零:无法区分的两个数字之间的差异 正无穷小:两个匹配符号的乘积或商,太小而无法与零区分开来。 负无穷小:符号相反的两个数的乘积或商,太小而无法与零区分开来。

其中一些可以通过其他方式产生(例如,文字零可以作为两个文字零的总和产生;正无穷小通过一个非常小的数除以一个非常大的数等)。

如果浮点数识别出上述情况,它可以有效地将 NaN 提升到字面上的零作为产生 1,并将其提升到任何其他类型的零作为产生 NaN;这样的规则将允许在许多情况下假设一个常量结果,其中可能是 NaN 的东西将被提升为编译器可以识别为常量零的东西,而这种假设不会改变程序语义。否则,我认为问题在于,如果xNaN,大多数代码不会关心x^0 是否会NaN,并且让编译器为条件代码添加代码没有多大意义。 t去关心。请注意,问题不仅在于计算 x^0 的代码,还在于任何基于 x^0 不变的计算。

【讨论】:

NaN 通常用于例如表明结果不在真实域中,例如sqrt(-1)。在您的自定义函数中,它可能比复数更具异国情调,甚至不一定要为其定义 ^ 运算符,在这种情况下,如果您是零,则与“种类”无关看着。 @eddi:如果x^literalZero的语义定义为“忽略x并返回1”,那么sqrt(-1)^0的正确结果应该是1。可能有人会质疑这是不是最定义幂运算符的理想方法,但我认为语言应避免定义处理需要额外代码的极端情况。顺便说一句,您使用的语言是否区分右手运算符是整数和浮点数的情况?在某些语言中,(-2.0)^2 为 4.0,但 (-2.0)^(2.0) 无效。如果零是整数... ...那么我不认为 IEEE-754 NaN 处理是相关的(因为它没有提到整数取幂),我不赞成要求一种语言将零大小写编码为if (exponent==0) return (isNan(base) ? NaN : 1.0); 而不是简单的 if (exponent==0) return 1; 取一个函数f = function(x) if (x > 0) x else "boo"。然后f(-1)^0 会正确地给你一个错误。现在想象有人想在纯实数域中表示这个函数。他们这样做的方式是:f_real = function(x) if (x > 0) x else NaN。当他们尝试做f_real(-1)^0时,他们会继续给出错误的答案。 @eddi:你的意思是 f_real(-1)^0 还是 f_real^0.0?我会假设在数学上,f(x)^N 可以定义为 1 当 N=0 时,(f(x)^(N-1))*f(x) 当 N > 0 时,和 (f(x )^(N+1)) 当 N 只要人们只关心实际使用结果时会发生什么。请注意,我的分歧仅适用于指数为“整数”零的情况。顺便说一句,我对 IEEE 的看法是错误的,而不是......【参考方案6】:

如果你看NaN的类型,它仍然是一个数字,它只是不是一个特定的数字,可以用数字类型来表示。

编辑:

例如,如果您要取 0/0。结果是什么?如果你试图在纸上解这个方程,你会卡在第一个数字上,有多少个零适合另一个 0?你可以放 0,你可以放 1,你可以放 8,它们都适合 0*x=0 但不可能知道哪个是正确答案。然而,这并不意味着答案不再是一个数字,它只是一个无法表示的数字。

无论如何,任何数字,即使是你无法表示的数字,0 次方仍然是 1。如果你分解一些数学 x^8 * x^0 可以进一步简化为 x^(8+0) 等于 x^8x^0 去哪儿了?如果x^0 = 1 是有道理的,因为等式x^8 * 1 解释了为什么x^0 会从存在中消失。

【讨论】:

那么你基本上是在说“不是数字就是数字”吗? @H2CO3 我知道你知道。只是有一点天真的乐趣。 这个答案(尤其是编辑)完全是一派胡言,与数学无关 @eddi 我真的希望有人会写一个回答说“因为 R 遵循 X 标准,这就是标准所说的”,所以我们都可以投票并完成。 @joran:嗯,我不确定 R 对遵循任何标准有何​​保证,但该领域的压倒性主导标准是 IEEE 754,它说(在第 9.2.1 节中): “对于任何 x(即使是零、安静的 NaN 或无穷大),pow (x, ±0) 都是 1”。从标准的措辞来看,我并不是 100% 清楚这是建议还是要求。

以上是关于为啥 NaN^0 == 1的主要内容,如果未能解决你的问题,请参考以下文章

matlab中可以用NaN来去掉部分图像,但是怎么使用呢?

使用 Pandas 进行数据操作 [重复]

当 NaN [重复] 时用先前填充列值

用另一个 DataFrame 的值替换 DataFrame 的值

为啥 NaN^0 == 1

为啥无穷大 × 0 = NaN?