DEV Community

Identifying Negative Zero

EmNudge on January 25, 2020

As usual, I like to delve into some of the weird or complicated bits of JS. The other week I was thinking about a way to possibly identify a negat...
Collapse
 
savagepixie profile image
SavagePixie

You could also use Object.is(), which does make a difference between -0 and 0:

Object.is(0, -0) // -> false
Object.is(-0, -0) // -> true
Enter fullscreen mode Exit fullscreen mode
Collapse
 
emnudge profile image
EmNudge

Yes! I completely forgot to include that one!
Object.is() seems to be a "fixed" === since it also works when comparing NaN, unlike ===.

Collapse
 
theodesp profile image
Theofanis Despoudis

MDN gives a polyfill code:

if (!Object.is) {
  Object.is = function(x, y) {
    // SameValue algorithm
    if (x === y) { // Steps 1-5, 7-10
      // Steps 6.b-6.e: +0 != -0
      return x !== 0 || 1 / x === 1 / y;
    } else {
      // Step 6.a: NaN == NaN
      return x !== x && y !== y;
    }
  };
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
rubberduck profile image
Christopher McClellan

Javascript uses IEEE 754 floating point numbers where the most significant (left most) bit represents the sign of the number. Therefore, +0 is encoded something like 0000 while -0 is something like 1000.

I don’t know JS very well, so I’m not sure you can access this raw, underlying representation, but in theory, you can bitwise and the input with an actual negative zero to efficiently check for equality.

Collapse
 
emnudge profile image
EmNudge • Edited

I did some testing and unfortunately could not get them to produce different results with bitwise operators.

I have been looking at the spec for how it decides what to do and it seems that unless explicitly stated otherwise, -0 and 0 are treated the same.

Collapse
 
rubberduck profile image
Christopher McClellan

That’s unfortunate.

Collapse
 
egeriis profile image
Ronni Egeriis Persson

A while back I had an interesting use case for -0. I was looking for a way to map x,y coordinates into absolute positioning of an element in CSS. And I wanted that behavior to be different for positive and negative numbers, to create an easy interface for the consumer of that component. So negative x would position the element from the right edge, positive x would position from the left edge. Vice versa for the y axis.

I ended up writing a small function that would determine if the number provided is negative, including -0:

const isNeg = v => v < 0 || 1 / v === -Infinity;

And this function was used to position the element with some simple logic:

const x = `${isNeg(left) ? 'right' : 'left'} ${Math.abs(left)}rem`;
const y = `${isNeg(top) ? 'bottom' : 'top'} ${Math.abs(top)}rem`;
Collapse
 
lampe2020 profile image
Lampe2020

I maybe actually found a usecase for -0: Minecraft world coords. The coordinates 0 0 are on the corner between four blocks, meaning there are four columns of blocks at 0 0. So if you have a tool written in JS that works based on coords in Minecraft or a similar game, having a distinction between -0 and 0 can save you from some errors adjacent to the coordinate axes.
Although if you use floating point instead of integer coords, -0 and 0 sit in the exact same spot in the world.

Collapse
 
dlukashevich profile image
Denis Lukashevich

Be carefull with this one - return zero.toLocaleString()[0] === "-".
For some locales on certain OS minus character is going to be different (e.g. char code 8722 instead of 45), so this comparison will be false for -0. For example that's how it works for Swedish on Windows.

Collapse
 
kayahr profile image
Kayahr

You can create a very small sign function which works with -0 and 0:

sign = x => Math.sign(1 / x || x)
Enter fullscreen mode Exit fullscreen mode

For everything except Infinity Math.sign(1 / x) is sufficient. To support infinite values the || x is needed because 1 / Infinity is 0.

Collapse
 
kollinmurphy profile image
Kollin Murphy

Thanks for sharing! Found this article because I was converting decimal coordinates to degrees/minutes/seconds coordinates. Pulling the degree out as the integer number before the decimal was causing the negative sign to be lost when it was converted back into a string.

Collapse
 
ashraile profile image
Ashraile

In unusual and rare circumstances, a couple of Math methods (asinh) will output negative zero when given zero as an input. For bugfixes, the only way to check for it is by this method.