Subtracting long numbers in javascript
-
20-09-2019 - |
Question
Why is q == 0 in the following script?
<script>
var start = 1234567890123456789;
var end = 1234567890123456799;
var q = end - start;
alert(q);
</script>
I would think the result should be 10. What is the correct way to subtract these two numbers?
Solution
Because numbers in JavaScript are floating-point. They have limited precision.
When JavaScript sees a very long number, it rounds it to the nearest number it can represent as a 64-bit float. In your script, start
and end
get rounded to the same value.
alert(1234567890123456789); // says: 1234567890123456800
alert(1234567890123456799); // says: 1234567890123456800
There's no built-in way to do precise arithmetic on large integers, but you can use a BigInteger library such as this one.
OTHER TIPS
Jason already posted the why. For a solution, you can get a Javascript BigInt library at http://www-cs-students.stanford.edu/~tjw/jsbn/
const subtract = (a, b) => [a, b].map(n => [...n].reverse()).reduce((a, b) => a.reduce((r, d, i) => {
let s = d - (b[i] || 0)
if (s < 0) {
s += 10
a[i + 1]--
}
return '' + s + r
}, '').replace(/^0+/, ''))
Better use big-integer library for these things so as to handle all different test cases.
This is just for the a general case you can use....
It is explained in the JavaScript documentation:
According to the ECMAScript standard, there is only one number type: the double-precision 64-bit binary format IEEE 754 value (numbers between
-(2
53
-1)
and2
53
-1
). There is no specific type for integers.
Wikipedia page about double precision floating point format explains:
Between
2
52
= 4,503,599,627,370,496
and2
53
= 9,007,199,254,740,992
the representable numbers are exactly the integers. For the next range, from2
53
to2
54
, everything is multiplied by2
, so the representable numbers are the even ones, etc.
(All integer numbers smaller than 2
52
are represented exactly.)
1234567890123456789
and 1234567890123456799
are larger than 2
60
= 1152921504606846976
. At this magnitude only about 1% of the integer numbers are stored exactly using the double-precision floating point format.
These two cannot be stored exactly. They both are rounded to 1234567890123456800
.
The JavaScript documentation also explains how to tell if a an integer number is stored exactly:
[...] and starting with ECMAScript 6, you are also able to check if a number is in the double-precision floating-point number range using
Number.isSafeInteger()
as well asNumber.MAX_SAFE_INTEGER
andNumber.MIN_SAFE_INTEGER
. Beyond this range, integers in JavaScript are not safe anymore and will be a double-precision floating point approximation of the value.