Written on 8 May 2015, last revised on 26 May 2015, may be out of date, please refer to it carefully.

The original

Since ancient times js many wonderful work, there are many pits on the language level, into the pits much also used to. Let’s just have one more pit.

Javascript has two ways to determine if two values are equal == and ===. The difference between the two I will not say more, any JS book have, in general we have such a conclusion: == save trouble, but the result is chaotic, in many cases almost pseudoscience, not recommended to use, a lot of people are regard it as a flood beast, avoid (its pit too much, I can not finish writing, do not write); === is very strict and should be used in most cases. I agree with this conclusion and try to do so. But javascript, as a wayward language, can’t be fun without a slap in the face. So let’s have a good time.

To play the bad= = =I just need to use 0. That’s right, the number zero. In javascript, numbers are computed as floating-point numbers, and the encoding rules followIEEE_754Standard (Not equal to 0.3 blame it! . And that’s not the point, the point is that according to that standard, the number code will have one sign bit for positive and negative, so for any number, either positive or negative. So the question is, what about 0? The answer is 0 is also positive or negative. Normally, it means +0, but in javascript -0 exists. In the actual operation, the difference between +0 and -0 may occur in some scenarios. Similarly, when +0 and -0 are involved in the calculation, it may lead to different results. But intuitively, it’s obvious that +0 and -0 should be the same, so javascript wants to eliminate this difference at the language level, so:

Seems reasonable, if a little strange. But look at an operation like this:

It’s not scientific. It’s clearly determined to be exactly the same value, but after the same operation, the results will not be equal. For developers, we can’t trust === in every situation, and it can be unreliable.

Dealing with this “unscientific” situation is also simple:

function isEqual(a, b){
    if(a ! == b)return false;
    returna ! = =0 || 1 / a === 1 / b;
}
Copy the code

Added on 14 May 2015:

To highlight the point of this article, I never intended to dispute that Infinity is not equal to Infinity, but the point I would like to share is that in JS, +0 === -0, but they are not exactly equal.


Added on 26 May 2015:

First reply comments longer than the body… Let’s concentrate.

About IEEE_754 standard

This is a scheme that uses binary to represent floating point numbers and is widely used. It specifies one sign bit for plus and minus, and zero is no exception, and that’s where minus zero comes in. This is a common problem with floating-point representation schemes with signed bits, but of course, schemes without signed bits avoid this problem. This is not a serious problem, however. Often programming languages don’t want developers to know that negative 0 exists, and specify that positive 0 and negative 0 are equal at the language level, which is the essence of why +0 === -0.

I say negative zero is not a serious problem because it is used in fewer scenarios and has a low bug rate. In terms of not serious, there is a serious problem, which is the precision of floating-point numbers, which are precise and continuous; Numerical coding is discrete and often inaccurate. After all, there is a limit to how many floating points you can represent, 32-bit or 64-bit. From 0.1, 0.2 to 0.9, only 0.5 can really be accurately expressed. The other numbers are approximations. Try it out for yourself. Whether it’s js, Java, or c++, floating-point arithmetic is never reliable, for exampleIt’s not equal to 0.3. If you’ve had c++ or Java programming experience, you’ve probably come across some weird code to handle floating-point comparisons, such as defining an accuracy of 0.002f (assuming) ifAbs (floatA - floatB) < 0.002f, the two are considered equal. Very anti-human, but I can’t help it. What’s wrong with programming languages? No, but the reality is compromise.

About the negative zero

Negative zero doesn’t make any sense mathematically, zero is unsigned. But if a number goes to 0, then it’s signed and can be negative. But in this case, the IEEE_754 standard is not defined. So in a real development scenario, if a number approaches 0, it’s 0, and negative 0 makes sense, it might represent a negative number approaching 0. This is essentially a question of IEEE_754 accuracy, or range of expression. But when negative 0 has a concrete meaning, plus 0 === minus 0, I think it’s questionable.

Is negative zero common

First of all, I’m going to say negative zero is unusual, but it’s not what you think it’s usually not possible. In fact, there are some common, simple scenarios where -0 can occur. For example, math.ceil (-0.1), math.round (-0.1); There are also the less common math.atan2 (-1, Infinity), etc. There are more operations that produce different results from plus or minus 0, such as the reciprocal operation in the example in this article.

References:

  • Developer.mozilla.org/en-US/docs/…

Javascript operates with ===

Normally, in JS, === means to determine whether types and values are exactly equal. I mean, that’s the norm. There must be a counterexample. Many people familiar with JS know such a knowledge point, NaN! = = NaN. So we often see code like this:

function isNaN (num){
    returnnum ! == num; }Copy the code

This is what happens when a programming language manipulates operators for intuitive understanding. It’s the same thing with +0 and -0, they’re not coded differently, but they’re judged to be equal.

For these two points, EmacScript 6 adds the object. is method to handle them:

Object.defineProperty(Object.'is', {
    value: function(x, y) {
        if (x === y) {
        // 0 === -0, but they are not identical
        returnx ! = =0 || 1 / x === 1 / y;
        }

        // NaN ! == NaN, but they are identical.
        // NaNs are the only non-reflexive value, i.e., if x ! == x,
        // then x is a NaN.
        // isNaN is broken: it converts its argument to number, so
        // isNaN("foo") => true
        returnx ! == x && y ! == y; },configurable: true.enumerable: false.writable: true
});
Copy the code

References:

  • Wiki.ecmascript.org/doku.php?id…
  • Developer.mozilla.org/en-US/docs/…

For the problem of negative 0, EmacScript 5 also adds isNegative0 to handle negative 0.

References:

  • www.wirfs-brock.com/allen/posts…

Not only that, but some of the utility class libraries have added similar processing, such as the isEqual method for underscore.

So…

For most development scenarios, -0 doesn’t exist at all; But I share this point so that more people know that there is such a thing as -0, so that more people know that there is a possibility that the same seemingly identical input, through the same calculation, can produce completely different results, so that they don’t encounter strange bugs.