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


84

我们都知道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


3
@zzzzBov:在标准定义下,“ a <sup> b </ sup> = exp(b ln(a))”,未定义。尝试将其定义为“ limit <sub> x-> 0 </ sub> f(x)<sup> g(x)</ sup>”,其中“ f”和“ g”的极限均为零,因此不确定价值,因为它取决于您选择的功能。(为错误的注释表示歉意;我不知道如何在注释中获得上标)。
Mike Seymour 2013年

@MikeSeymour,是的,我知道给定该定义未定义0⁰(使用unicode字符),但是,如果您阅读我的评论,则应注意引号引用的是“数学世界”,而不是任何“标准定义”。我最初指的就是这种差异,并且该问题已得到更新以纠正这种细微差别。
zzzzBov

2
@AJMansfield Um ... a ^ 0 = 1表示非零a。
Beska

它允许依赖于概率乘积的函数提供合理的结果。计算机是符号数学处理器,这是一个错误的观念。C语言在现实世界中具有特定的实现方式,而您的数学世界可能过于理想而无法在硅上进行补充。
IRTFM

26
对于这个问题的数学解释,“为什么我们经常定义0 ^ 0 = 1?” — math.stackexchange有很多好的答案:math.stackexchange.com/questions/11150/…–
PLL

Answers:


78

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

尽管pow(0,0)产生结果1对于许多应用程序都是有用的,因为涵盖IEC 60559浮点算术支持的部分中指出了国际标准(编程语言)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价值errno0,所以它不是一个域误差为那些编译器。

更新Javascript

对于Javascriptpow(x,y)“数学对象”部分中的ECMAScript®语言规范指出:15.8 15.8.2.13

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


1
@leemes我认为页面是错误的,标准并没有说应该返回NaN。返回值是实现定义的。您声称不是可靠来源的cplusplus.com实际上在这里更准确。
interjay 2013年

@interjay我猜你的意思是删除的答案;我只引用了它的不可靠性,希望它可以解释下降投票(不是我本人)。嗯,这两个页面都是Wiki,因此其可靠性取决于其编辑人员的人性化和错误之处。;)
leemes 2013年


@ShafikYaghmour我链接了相同的问题(在删除的答案中)。
leemes

1
@Alek我很感谢您的反馈,我尝试写一些我想从别人那里读到的答案。我并不总是成功,但我会尝试。编写好的问题更加困难,我只尝试过一次,花了更长的时间,然后才回答。
Shafik Yaghmour 2013年

35

在JavaScriptMath.pow中定义如下

  • 如果y为NaN,则结果为NaN。
  • 如果y为+0,则即使x为NaN,结果也为1。
  • 如果y为−0,则即使x为NaN,结果也为1。
  • 如果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。

重点矿

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


C99和C11标准的附件F包含相同的规范。一个实现应该定义__STDC_IEC_559__为宣布它符合此规范。附件F描述了IEC 60559浮点算法。我认为C规范可以部分符合附件F(例如pow(0,0)== 1),而不是define __STDC_IEC_559__
2013年

@HowardHinnant hmmm,对于gccclang来说,信息可能并不完全有用,这令人沮丧。
Shafik Yaghmour

6
我不知道这个答案有帮助。当然,该功能应按照规范中的定义执行。但是问题就变成了“为什么在规范中这样定义?”
Beska

好事(可能)是在硬件中完成的,否则在所有这些特殊情况下都会降低性能:)
Thomas


14

根据维基百科:

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

0**0每种情况都有几种利弊方式(请参阅Wikipedia进行详细讨论)。

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

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

6

唐纳德·克努斯

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

在此处输入图片说明

并且在他的论文“记法上的两注”中进行了详细论述

基本上,尽管f(x)/g(x)并非所有函数f(x)and都没有1的限制g(x),但它仍然使组合函数的定义变得如此简单0^0=1,然后仅在需要考虑函数的少数地方做特殊情况,例如0^x,反正很奇怪 毕竟,x^0出现的频率更高。

我知道的关于该主题的一些最佳讨论(除了Knuth论文)是:


如果您还没有阅读一些内容,请阅读零至零功率的答案...?与问题相关联的是,您的一些答案也应该涵盖此方法。
Shafik Yaghmour 2013年


5

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


1
哎呀!真的很有趣!我编译使用我的cpp文件g++ (Ubuntu/Linaro 4.8.1-10ubuntu8) 4.8.
尼卡比曹

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的整数,因为“负乘法”是除法运算-我们除以4两次。

a ^(1/2)是root(a),因为将某物乘以a的根是乘以本身乘以一半的乘法工作-您必须做两次以将某物乘以4 = 4 ^ 1 = (4 ^(1/2))^ 2


0

为了理解这一点,您需要解决微积分:

在此处输入图片说明

x^x使用泰勒级数在零附近展开,我们得到:

在此处输入图片说明

因此,要了解x零时极限发生了什么,我们需要找出第二项发生了什么x log(x),因为其他项正比于x log(x)提高到某种功效。

我们需要使用转换:

在此处输入图片说明

现在,在此变换之后,我们可以使用L'Hôpital规则,该规则指出:

在此处输入图片说明

因此,使该转换与众不同:

在此处输入图片说明

因此,我们已经计算出,log(x)*x当x接近0时,该项接近0。很容易看到其他连续项也接近零,甚至比第二项还要快。

因此,在点上x=0,级数变为1 + 0 + 0 + 0 + ...并因此等于1。


尽管这个答案令人印象深刻,但值得注意的是,在数学上,f(x)的x-> a的极限不一定等于f(a),除非函数在x处连续。
jasonszhao
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.