为啥 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,包括 -Inf
和 Inf
。然而NaN
应该代表not-a-number,那么为什么会这样呢?当?NaN
的帮助页面指出:
在 R 中,基本上所有的数学函数(包括基本的
Arithmetic
),应该与+/- Inf
和NaN
一起正常工作 输入或输出。基本规则应该是与
Inf
s的调用和关系确实是 具有适当数学极限的语句。涉及
NaN
的计算将返回NaN
或NA
: 这两个不能保证,可能取决于 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 中的内置求幂函数^
通过对传递给它的参数进行一些检查来调用pow
。 NaN^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 - pow
和 powr
,后者在 OP 情况下保留了 NaN
,并且还为 Inf^0
、0^0
返回了 NaN
, 1^Inf
,但最终后者被删除为explained briefly here。
从概念上讲,我在 NaN
保留阵营,因为我是从限制的角度来解决这个问题的,但从方便的角度来看,我希望当前的约定更容易处理,即使它们不在某些情况下没有多大意义(例如,sqrt(-1)^0
等于 1 而所有操作都是实数,如果有的话,意义不大)。
【讨论】:
那个链接读起来很有趣。我本来希望 R 的min
和 max
忽略 NaN,但 NaN^1 是 NaN。你不能总是得到你想要的。
我相信 IEEE754-2008 标准的最终版本实际上同时具有 pow
和 powr
,以及用于将任意浮点数提高到整数幂的 pown
。 pow(qNaN, 0)
和pown(qNaN, 0)
定义为1
; powr(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 NaN
。 f(-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? NA
是 NaN
的超集。你弄错了 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 的东西将被提升为编译器可以识别为常量零的东西,而这种假设不会改变程序语义。否则,我认为问题在于,如果x
是NaN
,大多数代码不会关心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^8
,x^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的主要内容,如果未能解决你的问题,请参考以下文章