Content from: Chapter 2 (Values) of Types and Grammars in You-dont-know-JS
decimal value
The most famous (and notorious) side effects of using binary floating point are (remember, this is true for all languages that use IEEE 754 - not a problem that many people think/pretend to exist only in JavaScript):
0.1 + 0.2 === 0.3; // false
Mathematically, we know that this statement should be true
. Why is it false
?
Simply put, the0.1
binary representation of and is inexact, so when they are added, the result is not exact . It's a very close value: , but if your comparison fails, "closer" is irrelevant.0.2
0.3
0.30000000000000004
Note: Should JavaScript switch to a different number
implementation ? Some people think it should. Many options have come up over the years. But none have been adopted, and probably never will. It looks as simple as waving your hand and saying, "That bug has been fixed!", but it's not at all. If it were that simple, it must have been changed a long time ago.
Now the question is, if some number
can't be trusted to be exact, doesn't that mean we can't use it at number
all? Of course not .
In some applications you need to be careful, especially when dealing with decimals. There are many (maybe most?) applications that only deal with integers, and, at most, only a few million to a few trillion. These applications are, and always will be, very safe to use numeric manipulation in JS .
What if we really needed to compare two number
, like 0.1 + 0.2
AND 0.3
, and knew that this simple equality test would fail?
The most common acceptable practice is to use a small "misrounding" value as the tolerance . This small value is often referred to as the "machine epsilon" , which number
is usually 2^-52(2.220446049250313e-16)
.
In ES6, using this tolerance value is predefined Number.EPSILON
, so you'll want to use it, and you can safely fill this definition in pre-ES6 as well:
if (!Number.EPSILON) {
Number.EPSILON = Math.pow(2,-52);
}
We can use this Number.EPSILON
to compare number
the "equivalence" of two (with tolerance for incorrect rounding):
function numbersCloseEnoughToEqual(n1,n2) {
return Math.abs( n1 - n2 ) < Number.EPSILON;
}
var a = 0.1 + 0.2;
var b = 0.3;
numbersCloseEnoughToEqual( a, b ); // true
numbersCloseEnoughToEqual( 0.0000001, 0.0000002 ); // false
The largest floating point value that can be represented is roughly 1.798e+308
(it's really, really, really big!), which is predefined for you as Number.MAX_VALUE
. On the extremely small end, Number.MIN_VALUE
presumably 5e-324
, it's not negative but very close to 0
!