Problem
At one point or another, while using JS, you should have encounter the limitation of number encoding. The most infamous example is:
0.1 + 0.2 === 0.3 // => false
Javascript encode numbers using 64bits of memory (64 binary digits). Since we want to deal with floating numbers (non-finite set), modern languages have to rely on weird maths.
I'm not going to explain it here, because I don't understand it fully myself. But you should know that storing infinite precision numbers over finite memory is not possible.
Math.PI // => 3.141592653589793 "only" 16 digits long.
As it can lack precision for small number, it's also true for large numbers. As soon as you go higher than Number.MAX_SAFE_INTEGER
or 2^53 - 1
, you're subject to error.
Number.MAX_SAFE_INTEGER // => 9007199254740991
Number.MAX_SAFE_INTEGER + 2 // => 9007199254740992 (1 + 2 = 2 ?)
It can get even worse if your integer goes beyond Number.MAX_VALUE
or 2^1024 - 1
, because JS will treat it as Infinity
.
Number.MAX_VALUE // => 1.7976931348623157e+308
Number.MAX_VALUE * 2 // => Infinity
1.8e308 // => Infinity
Solution
Recently, Javascript has a new number representation: BigInt. It's now supported by FireFox (v68), Chrome (v67) and Edge (v76). This allow you to write number as large as your computer memory can handle.
It's extremely easy to use, just add a n
character in the end of your numbers.
99 ** 999 // => Infinity
99n ** 999n // => 436073206168265161501341703386462012231079860756206...
If you can't add the n
, like when you consume the result of a function, you can wrap it in a constructor.
BigInt(getNumberViewers()) * BigInt(getAverageWatchDuration())
There's a few thing to remember while using BigInts.
First, BigInts are not compatible with regular numbers. So, you need to transform all operand to one or the other when doing maths.
const bigInt = 99n ** 999n;
bigInt * 10 // => TypeError: Cannot mix BigInt and other types
Secondly, BigInts are not compatible with Math
. Only basic maths operation are allowed.
Math.max(10n, 20n) // => TypeError: Cannot convert a BigInt value to a number
10n < 20n // => true
Thirdly, while division are supported, they automatically round to the closest to 0 integer.
19n / 10n // => 1n
-19n / 10n // => -1n
Finally, you'll have to consider that BigInt are a bit more ressource consuming than native numbers. So you should be using them only when manipulating ever growing numbers, like timestamps, users actions ...
I hope you enjoy this little article. Look for more articles from me on the right panel and consider following me on Github or Twitter.
Until next time, peace ✌️
Top comments (0)