JavaScript converts integers with more than 21 digits to scientific notation when used in a string context. I’m printing an integer as part of a URL. How can I prevent the conversion from happening?
Advertisement
Answer
There’s Number.toFixed, but it uses scientific notation if the number is >= 1e21 and has a maximum precision of 20. Other than that, you can roll your own, but it will be messy.
function toFixed(x) { if (Math.abs(x) < 1.0) { var e = parseInt(x.toString().split('e-')[1]); if (e) { x *= Math.pow(10,e-1); x = '0.' + (new Array(e)).join('0') + x.toString().substring(2); } } else { var e = parseInt(x.toString().split('+')[1]); if (e > 20) { e -= 20; x /= Math.pow(10,e); x += (new Array(e+1)).join('0'); } } return x; }
Above uses cheap-‘n’-easy string repetition ((new Array(n+1)).join(str)
). You could define String.prototype.repeat
using Russian Peasant Multiplication and use that instead.
This answer should only be applied to the context of the question: displaying a large number without using scientific notation. For anything else, you should use a BigInt library, such as BigNumber, Leemon’s BigInt, or BigInteger. Going forward, the new native BigInt (note: not Leemon’s) should be available; Chromium and browsers based on it (Chrome, the new Edge [v79+], Brave) and Firefox all have support; Safari’s support is underway.
Here’s how you’d use BigInt for it: BigInt(n).toString()
Example:
const n = 13523563246234613317632; console.log("toFixed (wrong): " + n.toFixed()); console.log("BigInt (right): " + BigInt(n).toString());
Beware, though, that any integer you output as a JavaScript number (not a BigInt) that’s more than 15-16 digits (specifically, greater than Number.MAX_SAFE_INTEGER + 1
[9,007,199,254,740,992]) may be be rounded, because JavaScript’s number type (IEEE-754 double-precision floating point) can’t precisely hold all integers beyond that point. As of Number.MAX_SAFE_INTEGER + 1
it’s working in multiples of 2, so it can’t hold odd numbers anymore (and similiarly, at 18,014,398,509,481,984 it starts working in multiples of 4, then 8, then 16, …).
Consequently, if you can rely on BigInt
support, output your number as a string you pass to the BigInt
function:
const n = BigInt("YourNumberHere");
Example:
const n1 = BigInt(18014398509481985); // WRONG, will round to 18014398509481984 // before `BigInt` sees it console.log(n1.toString() + " <== WRONG"); const n2 = BigInt("18014398509481985"); // RIGHT, BigInt handles it console.log(n2.toString() + " <== Right");