Are +0 and -0 the same?
Asked Answered
G

11

225

Reading through the ECMAScript 5.1 specification, +0 and -0 are distinguished.

Why then does +0 === -0 evaluate to true?

Guide answered 28/8, 2011 at 19:31 Comment(4)
possible duplicate of Differentiating +0 and -0Irrespirable
Note that in ES2015 you can use Object.is to distinguish +0 and -0Corenecoreopsis
Quoting David Flanagan from JS the definitive guide: Underflow occurs when the result of a numeric operation is closer to zero than the smallest representable number. In this case, JavaScript returns 0. If underflow occurs from a negative number, JavaScript returns a special value known as “negative zero.”Emission
Related posts - Why is negative zero important? & Uses for negative zero floating point value?Emission
S
240

JavaScript uses IEEE 754 standard to represent numbers. From Wikipedia:

Signed zero is zero with an associated sign. In ordinary arithmetic, −0 = +0 = 0. However, in computing, some number representations allow for the existence of two zeros, often denoted by −0 (negative zero) and +0 (positive zero). This occurs in some signed number representations for integers, and in most floating point number representations. The number 0 is usually encoded as +0, but can be represented by either +0 or −0.

The IEEE 754 standard for floating point arithmetic (presently used by most computers and programming languages that support floating point numbers) requires both +0 and −0. The zeroes can be considered as a variant of the extended real number line such that 1/−0 = −∞ and 1/+0 = +∞, division by zero is only undefined for ±0/±0 and ±∞/±∞.

The article contains further information about the different representations.

So this is the reason why, technically, both zeros have to be distinguished.

However, +0 === -0 evaluates to true. Why is that (...) ?

This behaviour is explicitly defined in section 11.9.6, the Strict Equality Comparison Algorithm (emphasis partly mine):

The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed as follows:

(...)

  • If Type(x) is Number, then

    1. If x is NaN, return false.
    2. If y is NaN, return false.
    3. If x is the same Number value as y, return true.
    4. If x is +0 and y is −0, return true.
    5. If x is −0 and y is +0, return true.
    6. Return false.

(...)

(The same holds for +0 == -0 btw.)

It seems logically to treat +0 and -0 as equal. Otherwise we would have to take this into account in our code and I, personally, don't want to do that ;)


Note:

ES2015 introduces a new comparison method, Object.is. Object.is explicitly distinguishes between -0 and +0:

Object.is(-0, +0); // false
Seismic answered 28/8, 2011 at 19:37 Comment(9)
Indeed 1/0 === Infinity; // true and 1/-0 === -Infinity; // true.Theological
So we have 1 === 1 and +0 === -0 but 1/+0 !== 1/-0. How weird!Guide
@Random: I think it's certainly better than +0 !== -0 ;) That could really create problems.Seismic
@FelixKling, or 0 !== +0 / 0 !== -0, which would indeed create problems too!Luckily
Different behaviour for Object.is()Picrate
@killeoy: you are right, I should update my post with the new ES6 stuff. Thanks!Seismic
Actually, this behavior models limit calculation in math. For example function 1/x has a value infinity in 0, however, it is separated if we are approaching 0 from the positive of negative side; in the former, the result is +inf, in the latter, -inf.Scrophulariaceous
@Randomblue: that's exactly why you don't divide by zero in equations.Iams
@Iams I agree. Why do we need to divide anything by zero? It does not make infinity and what can we use it for? Fun?Hastie
F
28

I'll add this as an answer because I overlooked @user113716's comment.

You can test for -0 by doing this:

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

isMinusZero(0); // false
isMinusZero(-0); // true
Fauch answered 1/9, 2016 at 20:37 Comment(3)
Should probably check for == 0 as well, the above isMinusZero(-1e-323) returns true!Tryparsamide
@Chris, limit of double precision exponent is e±308, your number can be represented only in denormalized form and different implementations have different opinions about where to support them at all or not. The point is, on some machines in some floating point modes your number is represented as -0 and on others as denormalized number 0.000000000000001e-308. Such floats, so funPerilymph
This may work for other languages as well (I tested for C and this works)Angelaangele
R
27

I just came across an example where +0 and -0 behave very differently indeed:

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

Be careful: even when using Math.round on a negative number like -0.0001, it will actually be -0 and can screw up some subsequent calculations as shown above.

Quick and dirty way to fix this is to do smth like:

if (x==0) x=0;

or just:

x+=0;

This converts the number to +0 in case it was -0.

Ranita answered 3/11, 2018 at 21:3 Comment(2)
Thanks. So weird how adding zero would fix the problem I ran into. "If all else fails, add zero." A lesson for life.Woden
I just encountered this in Math.atan(y/x) as well, which (perhaps surprisingly) can handle positively or negatively infinite "y/x", except it gives the wrong answer in the case where x is -0. Replacing "x" with "(x+0)" fixes it.Rozamond
S
9

2021's answer

Are +0 and -0 the same?

Short answer: Depending on what comparison operator you use.

Long answer:

Basically, We've had 4 comparison types until now:

  1. ‘loose’ equality
console.log(+0 == -0); // true
  1. ‘strict’ equality
console.log(+0 === -0); // true
  1. ‘Same-value’ equality (ES2015's Object.is)
console.log(Object.is(+0, -0)); // false
  1. ‘Same-value-zero’ equality (ES2016)
console.log([+0].includes(-0)); // true

As a result, just Object.is(+0, -0) makes difference with the other ones.

const x = +0, y = -0; // true                -> using ‘loose’ equality
console.log(x === y); // true                -> using ‘strict’ equality
console.log([x].indexOf(y)); // 0 (true)     -> using ‘strict’ equality
console.log(Object.is(x, y)); // false       -> using ‘Same-value’ equality
console.log([x].includes(y)); // true        -> using ‘Same-value-zero’ equality

enter image description here

Socket answered 29/3, 2021 at 2:58 Comment(0)
T
8

In the IEEE 754 standard used to represent the Number type in JavaScript, the sign is represented by a bit (a 1 indicates a negative number).

As a result, there exists both a negative and a positive value for each representable number, including 0.

This is why both -0 and +0 exist.

Terminus answered 28/8, 2011 at 19:39 Comment(2)
Two's complement also uses a bit for the sign, but only has one zero (positive).Seismic
Yes but in Two's complement the negative-bit is also part of the value, so once you set the negative-bit, it's not zero anymore.Terminus
L
4

Answering the original title Are +0 and -0 the same?:

brainslugs83 (in comments of answer by Spudley) pointed out an important case in which +0 and -0 in JS are not the same - implemented as function:

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

This will, other than the standard Math.sign return the correct sign of +0 and -0.

Lignify answered 20/8, 2015 at 15:1 Comment(1)
Your function returns true or false, but not -1 and 1Gurule
C
4

I'd blame it on the Strict Equality Comparison method ( '===' ). Look at section 4d enter image description here

see 7.2.13 Strict Equality Comparison on the specification

Clothe answered 26/1, 2018 at 14:28 Comment(0)
S
3

We can use Object.is to distinguish +0 and -0, and one more thing, NaN==NaN.

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

Object.is(NaN,NaN) //true
Staffordshire answered 26/9, 2016 at 8:12 Comment(0)
G
3

If you need sign function that supports -0 and +0:

var sign = x => 1/x > 0 ? +1 : -1;

It acts as Math.sign, except that sign(0) returns 1 and sign(-0) returns -1.

Gurule answered 1/4, 2021 at 19:50 Comment(1)
sign(Infinity) gives -1Irenics
I
2

There are two possible values (bit representations) for 0. This is not unique. Especially in floating point numbers this can occur. That is because floating point numbers are actually stored as a kind of formula.

Integers can be stored in separate ways too. You can have a numeric value with an additional sign-bit, so in a 16 bit space, you can store a 15 bit integer value and a sign-bit. In this representation, the value 1000 (hex) and 0000 both are 0, but one of them is +0 and the other is -0.

This could be avoided by subtracting 1 from the integer value so it ranged from -1 to -2^16, but this would be inconvenient.

A more common approach is to store integers in 'two complements', but apparently ECMAscript has chosen not to. In this method numbers range from 0000 to 7FFF positive. Negative numbers start at FFFF (-1) to 8000.

Of course, the same rules apply to larger integers too, but I don't want my F to wear out. ;)

Irrespirable answered 28/8, 2011 at 19:45 Comment(7)
But don't you find that +0 === -0 a little weird. Because now we have 1 === 1 and +0 === -0 but 1/+0 !== 1/-0...Guide
Of course +0 is -0. It's both nothing. But there's a huge difference between +infinity and -infinity, is there? Those inifinity-numbers may even be the reason why ECMA supports both +0 and -1.Irrespirable
You don't explain why +0 === -0 despite the two bit representations being different.Guide
+0 is -0 is 0, nothing, nada, niente. It makes sense that they are the same. Why is the sky blue? 4+3 is also the same as 1+6, although the representations are different. They have different representations (and thus a different bit value), but when compared they are handled as the same zero, which they are.Irrespirable
They are not the same. See https://mcmap.net/q/24514/-differentiating-0-and-0 for examples showing that.Guide
No, they are not, but they are evaluated to be equal when compared to each other, because they are logically the same value.Irrespirable
It's just a hack they put in so JavaScript programmers wouldn't get confused if they encountered it. -0 is even printed and converted to strings as "0" -- super lame to just throw away the sign of a number. -- as for the "you don't explain why 0 and -0 aren't equal comments" -- he doesn't have to, it's defined as being different in IEEE 754. It's a international computer engineering standard.Illaudable
B
1

Wikipedia has a good article to explain this phenomenon: http://en.wikipedia.org/wiki/Signed_zero

In brief, it both +0 and -0 are defined in the IEEE floating point specifications. Both of them are technically distinct from 0 without a sign, which is an integer, but in practice they all evaluate to zero, so the distinction can be ignored for all practical purposes.

Bolshevism answered 28/8, 2011 at 19:42 Comment(1)
That's not entirely correct -- 1/-0 == 1/0 evaluates to false in javascript for example. They do not "evaluate" to a magical unsigned zero, as there is no such concept such as "an unsigned integer zero" in IEEE 754.Illaudable

© 2022 - 2024 — McMap. All rights reserved.