我们都知道 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
.
我们都知道 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
.
在 C++中 pow(0, 0)的结果基本上是实现定义的行为,因为在数学上我们有一个矛盾的情况N^0
应该总是1
但0^N
应该总是0
for 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标准和两个C99和C11中部分7.12.7.4
的POW功能段2说(强调我的):
[...]如果 x 为零且 y 为零,则可能发生域错误。[...]
据我所知,这意味着这种行为是未指定的行为,回退一点部分7.12.1
错误条件的处理说:
[...]如果输入参数在定义数学函数的域之外,则会发生域错误。[...] 在域错误时,函数返回一个实现定义的值;如果整数表达式 math_errhandling & MATH_ERRNO 非零,则整数表达式 errno 获取值 EDOM;[...]
因此,如果存在域错误,那么这将是实现定义的行为,但在最新版本的gcc
和clang
的值中,对于这些编译器errno
来说0
,这不是域错误。
更新 JavaScript
对于Javascript,在pow (x, y)下的数学对象部分中的ECMAScript® 语言规范说明了其他条件:15.8
15.8.2.13
如果 y 为 +0,则结果为 1,即使 x 为 NaN。
- 如果 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。
强调我的
作为一般规则,任何语言的本机函数都应该按照语言规范中的描述工作。有时这包括明确的“未定义行为”,由实现者决定结果应该是什么,但这不是未定义行为的情况。
它是将其定义为只是约定1
,0
或者离开它undefined
。由于以下定义,该定义被广泛传播:
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 ]
根据维基百科:
在大多数不涉及指数连续性的设置中,将 0 0解释为 1 可以简化公式并消除对定理中特殊情况的需要。
有几种可能的方法来处理0**0
每种方法的利弊(请参阅维基百科的扩展讨论)。
在IEEE 754-2008浮点标准推荐三种不同的功能:
pow
对待0**0
的1
。这是最早定义的版本。如果幂是一个精确整数,则结果与 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 论文)是: