Reputation: 897
Consider condition
(-1 - Number.EPSILON < -1) === (-2 - Number.EPSILON < -2)
This example is executed in Chrome console on my machine to false
(?!), but I can't get why (left part is true, when right part is false). The whole condition also executes to false
in Edge and Firefox, but to true
in Internet Explorer (??!?).
Upvotes: 2
Views: 811
Reputation: 85827
Floating-point numbers are centered around zero. That is, they're densest around 0; the bigger your numbers get in magnitude, the fewer floating-point numbers exist in that region of the number line.
Bad ASCII approximation:
---------------------------------------(-1)-----(0)-----(1)------------------------------------------
. . . . . . . . . . .................. . . . . . . . . . .
The upper line represents the real numbers; the dots below mark possible floating-point values. There are many possible floating-point values between -1 and 1, allowing for very fine-grained distinction. The further away you get from 0, the sparser the possible floating-point values become, which means bigger numbers are stored with less precision.
Number.EPSILON
is the distance between 1 and the next higher floating-point number. That means 1 + Number.EPSILON
exists as a floating-point value and can be represented exactly. The same applies to -1 - Number.EPSILON
, which is the same value, but with a negative sign.
However, 2 + Number.EPSILON
does not exist. Because 1 is closer to 0 than 2 is, floating-point numbers are more dense around 1 than around 2. In particular, the difference between 2 and the next higher floating-point value is bigger than Number.EPSILON
(in fact, I wouldn't be surprised if it turned out to be 2 * Number.EPSILON
). Because 2 + Number.EPSILON
cannot be represented exactly, it is rounded to the nearest floating-point number, which turns out to be 2 itself:
console.log(2 + Number.EPSILON === 2); // true
As for Internet Explorer: It does not support Number.EPSILON
, so
-1 - Number.EPSILON < -1
is evaluated as
-1 - undefined < -1
which is Number.NaN < -1
, which (like all comparisons involving NaN
) evaluates to false
.
Upvotes: 4
Reputation: 2751
JavaScript number is double precision floating number (64 bit). Where bits 0-51 represents fraction and rest bits are for exponent.
If you try to convert Number.EPSILON
to binary - You'll see that it is:
> Number.EPSILON.toString(2)
'0.0000000000000000000000000000000000000000000000000001'
The first bit is 0
, so if you add 1 - it becomes 1, and it still fits into fraction bits:
> (1 + Number.EPSILON).toString(2)
'1.0000000000000000000000000000000000000000000000000001'
//---- So -----
(1+Number.EPSILON) !== 1
But when you add 2
(binary 10
) it catches additional bit on the left - so the right (less significant) bit is cut - to fit into fraction bits.
2 + Number.EPSILON
10.000000000000000000000000000000000000000000000000000|1 <- right bit dropped
^
51 bit
//---- So -----
(2+Number.EPSILON) === 2
Upvotes: 2