为什么 Math.pow(0, 0) === 1?

IT技术 javascript c++ language-agnostic pow
2021-03-01 21:24:58

我们都知道 0 0是不确定的。

但是javascript说:

Math.pow(0, 0) === 1 // true

C++说同样的话:

pow(0, 0) == 1 // true

为什么?

我知道:

>Math.pow(0.001, 0.001)
0.9931160484209338

但是为什么不Math.pow(0, 0)抛出错误呢?或者也许 aNaN会比1.

6个回答

在 C++中 pow(0, 0)的结果基本上是实现定义的行为,因为在数学上我们有一个矛盾的情况N^0应该总是10^N应该总是0for N > 0,所以你也不应该对这个结果有数学上的期望。这个Wolfram Alpha论坛帖子有更多细节。

尽管pow(0,0)涵盖IEC 60559 浮点算术支持的部分中,1作为国际标准的基本原理—编程语言—C状态结果对于许多应用程序很有用

通常,C99 避免使用数值有用的 NaN 结果。[...] pow(∞,0) 和 pow(0,0) 的结果都是 1,因为有些应用程序可以利用这个定义。例如,如果 x(p) 和 y(p) 是任何在 p = a 处变为零的解析函数,那么 pow(x,y),等于 exp(y*log(x)),随着 p 的接近而接近 1一个。

更新 C++

正如leemes正确地指出我最初链接为基准复杂的版本POW不复杂的版本权利要求它是域误差草案C ++标准回落到草案C标准和两个C99C11中部分7.12.7.4 的POW功能2说(强调我的):

[...]如果 x 为零且 y 为零,则可能发生域错误。[...]

据我所知,这意味着这种行为是未指定的行为,回退一点部分7.12.1 错误条件的处理说:

[...]如果输入参数在定义数学函数的域之外,则会发生域错误。[...] 在域错误时,函数返回一个实现定义的值;如果整数表达式 math_errhandling & MATH_ERRNO 非零,则整数表达式 errno 获取值 EDOM;[...]

因此,如果存在域错误,那么这将是实现定义的行为,但在最新版本的gccclang的值中,对于这些编译器errno来说0,这不是域错误

更新 JavaScript

对于Javascriptpow (x, y)的数学对象部分中ECMAScript® 语言规范说明了其他条件:15.8 15.8.2.13

如果 y 为 +0,则结果为 1,即使 x 为 NaN。

@interjay 我猜你的意思是删除的答案;我只引用了它的不可靠性,希望它能解释反对票(这不是我做的)。嗯,这两个页面都是 wiki,所以它们的可靠性取决于它们的编辑,这些编辑是人类并且会犯错误。;)
2021-04-20 21:24:58
@leemes SO 上的 C++ 社区绝对不喜欢 cplusplus.com
2021-04-21 21:24:58
@leemes 我相信那个页面是错误的,标准没有说应该返回 NaN。返回值是实现定义的。您声称不是可靠来源的 cplusplus.com 实际上在这里更准确。
2021-04-22 21:24:58
@ShafikYaghmour 我链接了同样的问题(在已删除的答案中)。
2021-04-26 21:24:58
@Alek 我感谢反馈,我尝试写下我想从其他人那里读到的答案。我并不总是成功,但我会尝试。写出好的问题更难,我只尝试过一次,而且我花在它上面的时间比我的答案要长得多。
2021-05-04 21:24:58

在 JavaScriptMath.pow中定义如下

  • 如果 y 为 NaN,则结果为 NaN。
  • 如果 y 为 +0,则结果为 1,即使 x 为 NaN。
  • 如果 y 为 -0,则结果为 1,即使 x 为 NaN。
  • 如果 x 为 NaN 且 y 非零,则结果为 NaN。
  • 如果 abs(x)>1 且 y 为 +∞,则结果为 +∞。
  • 如果 abs(x)>1 且 y 为 −∞,则结果为 +0。
  • 如果 abs(x)==1 且 y 为 +∞,则结果为 NaN。
  • 如果 abs(x)==1 且 y 为 −∞,则结果为 NaN。
  • 如果 abs(x)<1 且 y 为 +∞,则结果为 +0。
  • 如果 abs(x)<1 且 y 为 −∞,则结果为 +∞。
  • 如果 x 为 +∞ 且 y>0,则结果为 +∞。
  • 如果 x 为 +∞ 且 y<0,则结果为 +0。
  • 如果 x 为 −∞ 且 y>0 且 y 为奇数,则结果为 −∞。
  • 如果 x 为 −∞ 且 y>0 且 y 不是奇数,则结果为 +∞。
  • 如果 x 为 -∞ 且 y<0 且 y 为奇数,则结果为 -0。
  • 如果 x 为 −∞ 且 y<0 且 y 不是奇数,则结果为 +0。
  • 如果 x 为 +0 且 y>0,则结果为 +0。
  • 如果 x 为 +0 且 y<0,则结果为 +∞。
  • 如果 x 为 -0 且 y>0 且 y 为奇数,则结果为 -0。
  • 如果 x 为 -0 且 y>0 且 y 不是奇数,则结果为 +0。
  • 如果 x 为 -0 且 y<0 且 y 为奇数,则结果为 -∞。
  • 如果 x 为 -0 且 y<0 且 y 不是奇数,则结果为 +∞。
  • 如果 x<0 且 x 是有限的且 y 是有限的且 y 不是整数,则结果为 NaN。

强调我的

作为一般规则,任何语言的本机函数都应该按照语言规范中的描述工作。有时这包括明确的“未定义行为”,由实现者决定结果应该是什么,但这不是未定义行为的情况。

好消息是(可能)在硬件中完成,否则它会在所有这些特殊情况下影响性能:)
2021-04-23 21:24:58
@HowardHinnant 嗯,似乎在gccclang的情况下,这条信息可能并不完全有用,这令人沮丧。
2021-04-27 21:24:58
我不知道这个答案有帮助。当然,该功能应该按照规范中的定义执行。但随后问题就变成了“为什么在规范中以这种方式定义?”
2021-05-11 21:24:58
C99 和 C11 标准中的附录 F 包含相同的规范。一个实现应该定义__STDC_IEC_559__来宣布它符合这个规范。附录 F 描述了 IEC 60559 浮点运算。我相信 C 规范允许部分符合附件 F(例如 pow(0, 0) == 1)而不是定义__STDC_IEC_559__.
2021-05-19 21:24:58

它是将其定义为只是约定10或者离开它undefined战俘(0,0)由于以下定义,该定义被广泛传播:

数学幂定义


ECMA-Script 文档说明了以下内容pow(x,y)

  • 如果 y 为 +0,则结果为 1,即使 x 为 NaN。
  • 如果 y 为 -0,则结果为 1,即使 x 为 NaN。

[ http://www.ecma-international.org/ecma-262/5.1/#sec-15.8.2.13 ]

math.stackexchange 对 0^0=1 的定义有很多很好的讨论和解释:math.stackexchange.com/questions/11150/...
2021-05-12 21:24:58

根据维基百科:

在大多数不涉及指数连续性的设置中,将 0 0解释为 1 可以简化公式并消除对定理中特殊情况的需要。

有几种可能的方法来处理0**0每种方法的利弊(请参阅维基百科的扩展讨论)。

IEEE 754-2008浮点标准推荐三种不同的功能:

  • pow对待0**01这是最早定义的版本。如果幂是一个精确整数,则结果与 for 相同pown,否则结果与 forpowr相同(某些特殊情况除外)。
  • pown将 0**0 视为 1。幂必须是一个精确的整数。该值是为负基数定义的;例如,pown(−3,5)−243
  • powr将 0**0 视为 NaN(非数字 - 未定义)。对于powr(−3,2)基数小于零的情况该值也是 NaN 该值由 exp(power'×log(base)) 定义。

唐纳德·克努斯

1992 年通过以下方式解决了这场辩论:

在此处输入图片说明

并在他的论文《关于符号的两个注释》中更详细地介绍了细节

基本上,虽然我们没有将 1 作为f(x)/g(x)所有函数f(x)的极限g(x),但它仍然使组合数学的定义变得如此简单0^0=1,然后只需在需要考虑函数的少数地方进行特殊情况,例如0^x,反正很奇怪。毕竟x^0出现的频率要高得多。

我所知道的关于这个话题的一些最好的讨论(除了 Knuth 论文)是:

如果您还没有阅读一些阅读零到零功率中的答案......?这与您应该某些答案也涵盖这种方法的问题相关联。
2021-05-18 21:24:58