区分+0和-0

42
事实证明,尽管+0和-0是不同的实体,+0 === -0的结果为true。那么,你如何区分+0和-0?
这里有一个技巧:
if (1 / myZero > 0) {
   // myZero is +0
} else {
   // myZero is -0
}

我能做得更好吗?


17
为什么你需要了解这个?(不是居高临下... 我真的很好奇!) - Jason Gennaro
2
你的解决方案似乎是合理的。在语言中(+0 === -0)为true似乎是个疏忽,所以我不知道你会如何解决它。我不指望它会经常出现。 - evan
12
@evan,这不是疏忽,这是IEEE 754要求的。 - John Flatness
2
你不需要一个函数,只需进行以下检查:if (1 / x > 0) { ... - Šime Vidas
5
@Jason:我只是在摆弄规格,并考虑了一堆思维实验。这些奇怪的事情可能会导致难以发现的错误。请参见我在这里的一个担忧:https://dev59.com/hGw05IYBdhLWcg3weBru。 - Randomblue
@JasonGennaro - 我现在正在用JavaScript编写自己的printf%+f指示符必须区分+0-0 - csharpfolk
9个回答

27
在ECMAScript 6中,Object.is的行为类似于===,但它区分正零和负零,并且Object.is(NaN, NaN)的结果是true。 (有关详细信息,请参见此处。)
Chrome 24支持Object.is

如果您需要为旧浏览器使用,此文档末尾还有一个ECMAScript 5的替代版本。 - Gerard Brull

14

这仍然是某种形式的技巧,但是规范提示了以下内容:

Math.atan2(0, -0) === Math.PI // true
Math.atan2(0,  0) === 0       // true

你指的是哪些规范?ECMAScript吗?(我并不怀疑,只是想知道……) - Jared Farrish
@Jared Farrish:是的,atan2 的那一部分。 - pimvdb
你有链接吗? - Jared Farrish
好的,谢谢大家。 :) 这是为了我自己的学习。 (请注意,pimvdb的参考资料可以在http://bclary.com/2004/11/07/#a-15.8.2.5找到) - Jared Farrish
1
它可以运行,但是在我的Chrome浏览器上比“1/zero”测试慢10倍。 - csharpfolk
这并不适用于每个数字:Math.atan2(0, -5e-324) === Math.PI 是正确的,但 -5e-324 === -0 是错误的。 - Timothy Gu

9
根据David Flanagan的书,第34页,将1除以0会产生相应的无穷大,然后可以在等式检查中使用。
1 / 0
> Infinity
1 / -0
> -Infinity

以下是无穷大的相等比较的行为:

Infinity === -Infinity
> false
Infinity === Infinity
> true
-Infinity === Infinity
> false
-Infinity === -Infinity
> true

1
这并不适用于每个数字:1 / -5e-324 的结果为 -Infinity,但 -5e-324 === -0 是错误的。 - Timothy Gu
@TimothyGu 你的观点是什么?这个问题特别问及+0和-0,而不是“每个数字”。 - Matt Fenwick
确实如此。我犯了错误,忘记了最初的问题。 - Timothy Gu

4

想要检查负零,这里有一个简单的解决方案。

function isNegativeZero(n) {
    n = Number( n );
    return (n === 0) && (1 / n === -Infinity);
}

3
这将返回 +0:
-0 + 0

这并不能区分-0和+0,但它有助于确保某个值不是-0。

1 / -0       => -Infinity  
1 / (-0 + 0) => Infinity

4
你可以使用Math.abs(-0) - evan
5
这对我非常有用,因为我需要确保正零而不影响其他有符号数字。 - Semicolon

3

由于人们似乎对这个的实际需求感到困惑,这里是我的用例...

我需要一个解决方案来按它们的索引对表格的列进行排序。单击<th>并使用[ordinal]调用排序器以进行升序和-[ordinal]进行降序。第一列将给出-0表示降序或0表示升序。

因此,我需要区分+0-0,最终找到了这里。对我有效的解决方案在@Šime Vidas的评论中,但有点隐藏。

// This comparison works for all negatives including -0
if ( 1 / x > 0 ) { }

1 / -0 > 0  // false
1 / 0 > 0  // true
1 / -99 > 0 // false
1 / 99 > 0 // true

// WRONG: this naive comparison might give unexpected results
if ( x > 0 ) { }

-0 > 0 // true
// Gotcha

1
非常好的使用案例。我还有一个小问题不太明白:您提供的表达式也说明-0> 0会得出true的结果。当我读到它时,我感到震惊,当然,我立即在浏览器的开发工具中尝试了一下。看起来它返回的是false(正如我所预期的)。我可能在这里误解了什么吗? - Bart Hofland
我真的不记得写过这个,而且我看到你的观察是正确的。请原谅我的糊涂,我会添加一个注释来标识它。 - Roy Prins

1

Node.js中一种直接的选项是使用缓冲区(Buffer)

var negZero = Buffer('8000000000000000', 'hex')

var buf = Buffer(8);
buf.writeDoubleBE(myZero);

if (buf.equals(negZero)) {
    // myZero is -0
} else {
    // myZero is +0
}

此外,你可以通过 缓冲区模块 轻松地将它们 browserify 化。

1
使用TypedArray实现相同的想法:isPosZero = x => !(new Uint8Array(new Float64Array([x]).buffer).some(Boolean)) - tsh

0

正如Matt Fenwick所示,您可以这样做(使用变量zero):

if(1/zero===Infinity) {
  // zero is +0
} else {
  // zero is -0
}

0
使用 Math.sign()

console.log(Math.sign( 1 / +0 ));
console.log(Math.sign( 1 / -0 ));


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接