+0和-0是否相同?


171

通过阅读的ECMAScript 5.1规范+0-0被区分。

那为什么要+0 === -0评估true



6
请注意,在ES2015中,您可以Object.is用来区分+0和-0
Benjamin Gruenbaum 2015年

引用JS的David Flanagan的权威指南:当数字运算的结果比最小的可表示数字更接近零时,发生下溢。在这种情况下,JavaScript返回0。如果从负数发生下溢,则JavaScript返回一个特殊的值,称为“负零”。
RBT

Answers:


193

JavaScript使用IEEE 754标准表示数字。从维基百科

有符号的零为零,具有相关的符号。在普通算术中,−0 = +0 =0。但是,在计算中,某些数字表示形式允许存在两个零,通常用-0(负零)+0(正零)表示。这在某些带符号的整数表示形式以及大多数浮点数表示形式中都会发生。数字0通常被编码为+0,但是可以用+0或-0表示。

IEEE 754浮点算术标准(目前大多数支持浮点数的计算机和编程语言都在使用)要求+0和-0。零可被视为扩展实数线的变体,因此1 / −0 =-∞和1 / + 0 = +∞,仅对于±0 /±0和±∞/±∞未定义以零除。

本文包含有关不同表示形式的更多信息。

因此,这就是为什么在技术上必须区分两个零的原因。

但是,+0 === -0计算结果为true。这是为什么 (...) ?

此行为已在第11.9.6节严格平等比较算法”中明确定义(部分强调我的行为):

比较x === y,其中xy是值,产生truefalse。这样的比较执行如下:

(...)

  • 如果Type(x)是Number,则

    1. 如果x为NaN,则返回false。
    2. 如果y为NaN,则返回false。
    3. 如果x与y相同,则返回true。
    4. 如果x为+ 0,y为−0,则返回true。
    5. 如果x为−0,y为+0,则返回true。
    6. 返回false。

(...)

+0 == -0顺便说一句。)

从逻辑上看+0-0应平等对待。否则,我们将不得不在我们的代码中考虑到这一点,而我个人不想这样做;)


注意:

ES2015引入了一种新的比较方法Object.isObject.is明确区分-0+0

Object.is(-0, +0); // false

15
的确1/0 === Infinity; // true1/-0 === -Infinity; // true
user113716 2011年

48
所以我们有1 === 1and +0 === -0但是1/+0 !== 1/-0。真奇怪
2011年

8
@Random:我认为它肯定比+0 !== -0;)更好,这确实可能会造成问题。
Felix Kling

@FelixKling或0 !== +0/ 0 !== -0,这确实也会造成问题!
Yanick Rochon 2014年

5
实际上,此行为模型限制了数学计算。例如,函数1 / x的值无穷大为0,但是,如果我们要从负数的正数逼近0,则它将分隔开;在前者中,结果是+ inf,在后者中,结果是-inf。
Agoston Horvath 2014年

19

我将其添加为答案,因为我忽略了@ user113716的评论。

您可以通过执行以下操作测试-0:

function isMinusZero(value) {
  return 1/value === -Infinity;
}

isMinusZero(0); // false
isMinusZero(-0); // true

6
也应该检查== 0,上面的isMinusZero(-1e-323)返回true!
克里斯(Chris)

1
@Chris,双精度指数的极限是e±308,您的数字只能以非规范化形式表示,并且不同的实现对在何处支持它们完全不支持。关键是,在某些机器上,在某些浮点模式下,您的数字表示为,-0而在其他机器上则以非规范化的数字表示0.000000000000001e-308。这样的漂浮物,如此有趣
弱点

这可能也适用于其他语言(我已经通过C语言测试,并且可以工作)
Mukul Kumar,

11

我刚刚遇到了一个示例,其中+0和-0的行为确实有很大不同:

Math.atan2(0, 0);  //returns 0
Math.atan2(0, -0); //returns Pi

请注意:即使对-0.0001之类的负数使用Math.round时,它实际上也将为-0,并且可能会破坏如上所示的一些后续计算。

解决此问题的快速而肮脏的方法是做类似的事情:

if (x==0) x=0;

要不就:

x+=0;

如果是-0,则将数字转换为+0。


谢谢。因此,添加零将解决我遇到的问题很奇怪。“如果其他所有方法都失败,则加零。” 一生的教训。
Microsis

我刚刚在Math.atan(y / x)中也遇到了这个问题,(也许令人惊讶)可以处理正负的无限“ y / x”,只是在x为-0的情况下给出了错误的答案。将“ x”替换为“((x + 0)”)可修复此问题。
雅各布·C(Jacob C.)说应

5

在用于表示JavaScript中Number类型的IEEE 754标准中,符号用一位表示(a 1表示负数)。

结果,每个可表示的数字(包括)同时存在一个负值和一个正值0

这就是为什么两者-0同时+0存在。


3
二进制补码还对符号使用一点,但只有一个零(正)。
菲利克斯·克林

1
是的,但是在二进制补码中,负数位也是该值的一部分,因此一旦设置了负数位,它就不再是零。
Arnaud Le Blanc

3

回答原始标题Are +0 and -0 the same?

brainslugs83(在的答复中Spudley)指出了JS中的+0和-0不相同的重要情况-实现为函数:

var sign = function(x) {
    return 1 / x === 1 / Math.abs(x);
}

除标准外,这将Math.sign返回正确的符号+0和-0。


2

0有两个可能的值(位表示)。这不是唯一的。特别是在浮点数中,可能会发生这种情况。那是因为浮点数实际上是作为一种公式存储的。

整数也可以单独存储。您可以使用带有附加符号位的数字值,因此在16位空间中,可以存储15位整数值和符号位。在此表示形式中,值1000(十六进制)和0000均为0,但其中一个值为+0,另一个为-0。

可以通过从整数值中减去1来避免这种情况,因此它的范围是-1至-2 ^ 16,但这很不方便。

一种更常见的方法是将整数存储在“两个补码”中,但是显然ECMAscript选择不这样做。在此方法中,数字范围从0000到7FFF正。负数从FFFF(-1)到8000开始。

当然,相同的规则也适用于较大的整数,但是我不希望我的F耗尽。;)


4
但是您难道不觉得这+0 === -0有点奇怪。因为现在我们有了1 === 1+0 === -0但是1/+0 !== 1/-0……
Randomblue

2
当然+0是-0。都没事 但是+ infinity和-infinity之间有巨大的区别,在吗?这些无穷大甚至可能是ECMA支持+0和-1的原因。
GolezTrol

+0 === -0尽管两个位表示形式不同,您也无法解释为什么。
2011年

1
+0是-0是0,什么都没有,nada,niente。它们是相同的,这是有道理的。为什么天空是蓝色的?4 + 3也与1 + 6相同,尽管表示形式有所不同。它们具有不同的表示形式(因此具有不同的位值),但是当进行比较时,它们将被视为相同的零。
GolezTrol

1
他们一样。有关显示此内容的示例,请参见stackoverflow.com/questions/7223717/differentiating-0-and-0
2011年

2

我们可以Object.is用来区分+0和-0,还有另一件事NaN==NaN

Object.is(+0,-0) //false

Object.is(NaN,NaN) //true

1

我将其归咎于严格平等比较方法('===')。看第4D节 在此处输入图片说明

7.2.13全等比较规范


0

维基百科上有一篇很好的文章来解释这种现象:http : //en.wikipedia.org/wiki/Signed_zero

简而言之,它的+0和-0都在IEEE浮点规范中定义。从技术上讲,它们在没有符号的情况下都与0区别,整数是零,但实际上它们都为零,因此,出于所有实际目的,该区别可以忽略。


2
并非完全正确-例如,1 / -0 == 1/0在javascript中的计算结果为false。它们不会“评估”为一个神奇的无符号零,因为在IEEE 754中没有诸如“无符号整数零”之类的概念
。– BrainSlugs83 2013年
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.