我们都知道 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)
结果 in1
对于许多应用程序很有用,因为国际标准的基本原理 - 编程语言 - C在涵盖IEC 60559 浮点算术支持的部分中声明:
通常,C99 避免使用数值有用的 NaN 结果。[...] pow(∞,0) 和 pow(0,0) 的结果都是 1,因为有些应用程序可以利用这个定义。例如,如果 x(p) 和 y(p) 是在 p = a 处变为零的任何解析函数,则等于 exp(y*log(x)) 的 pow(x,y) 在 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
和isclang
的值中,对于那些编译器来说,这不是域错误。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
每种方法的优缺点(有关详细讨论,请参见Wikipedia)。
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 论文)是:
C 语言定义说 (7.12.7.4/2):
如果 x 为零且 y 为零,则可能发生域错误。
它还说(7.12.1/2):
在域错误时,该函数返回一个实现定义的值;如果整数表达式 math_errhandling & MATH_ERRNO 非零,则整数表达式 errno 获取值 EDOM;如果整数表达式 math_errhandling & MATH_ERREXCEPT 不为零,则引发“无效”浮点异常。
默认情况下, 的值为math_errhandling
,MATH_ERRNO
因此请检查errno
该值EDOM
。
当您想知道f(a)
当f
不能直接计算时应该赋予什么值时a
,您可以计算f
何时x
趋于的极限a
。
在这种情况下x^y
,通常的限制倾向于1
何时x
和y
倾向于0
,尤其是x^x
倾向于1
何时x
倾向于0
。
我不同意之前的一些答案的断言,即将 0^0 定义为 1 而不是 0 是约定或方便的问题(涵盖各种定理的一些特殊情况等)。
指数实际上与我们的其他数学符号不太吻合,所以我们都学习的定义留下了混淆的空间。一种稍微不同的方法是说 a^b(或 exp(a, b),如果你愿意)返回乘法的值,相当于将其他东西乘以a,重复 b 次。
当我们将 5 乘以 4 2 次时,我们得到 80。我们将 5 乘以 16。所以 4^2 = 16。
当您将 14 乘以 0 时,0 次,我们剩下 14。我们将它乘以 1。因此,0^0 = 1。
这种思路也可能有助于澄清负指数和分数指数。4^(-2) 是第 16 位,因为“负乘法”是除法——我们除以四两次。
a^(1/2) 是 root(a),因为将某物乘以 a 的根是乘以 a 本身的乘法工作的一半——你必须做两次才能将某物乘以 4 = 4^1 = (4^(1/2))^2
要理解这一点,您需要解决微积分:
x^x
使用泰勒级数在零附近展开,我们得到:
因此,要了解 limitx
变为零时发生了什么,我们需要找出 second term 发生了什么x log(x)
,因为其他项与x log(x)
提高到某个幂成正比。
我们需要使用转换:
现在经过这个转换,我们可以使用L'Hôpital 规则,它指出:
所以区分我们得到的转换:
所以我们计算出log(x)*x
当 x 接近 0 时,项接近 0。很容易看出,其他连续项也接近 0,甚至比第二项更快。
所以在 点x=0
,系列变为1 + 0 + 0 + 0 + ...
并因此等于 1。