Why BigInt is a big deal

I'm gonna be honest: it's not easy keeping up-to-date with when exactly changes to the Javascript language will be made. Wanna grasp it all? Go dig into meeting notes, drafts, specification documents, browser versions ... You get the gist.

The fact is that on a yearly basis, we're treated to new stuff in Javascript. And when I heard on a podcast that BigInt would finally make the official release (even though it has already been implemented for a while by most browsers), my mind began to wander off. It brought me back to early 2019, when I had encountered the need for BigInt in frantic fashion.

Why don't these numbers add up?

In 2019, I was working for a financial company and we displayed financial information (revenues, cost, forecasts ...) of clients to potential investors. Most of that information came from small businesses, but apparently not small enough

I remember getting a call from one of my colleagues: "Hi Karel, I'm getting some info from a client that the numbers he has uploaded to our site don't seem to be displayed correctly. Could you have a look?"

So I dove in and indeed, the numbers that were uploaded by the client didn't add up. There were numbers for several years that were uploaded, and the numbers for those latest years didn't match the data that was uploaded. We reproduced the problem on our test environments and figured there was a problem when column sizes exceeded a specific number.

But numerous tests later, we realized the problem lay with the numbers itself. They seemed to be cut off to 21.474. The developer knew it now: the problem was in the data type. And sure, we found that the max value for INT in MySQL is 2147483647.

Since we always included 2 decimal points, the maximum value we could store was 21.474.836,47. And when divided by 1.000 and displaying it without decimal points, that came down to 21.474. Mystery solved!

But what about Javascript?

Well, in Javascript things were similarly problematic. Although, because the Javascript number is stored as a 64-bit floating point number instead of a 32-bit number, the safe value is significantly larger than INT in MySQL or int in Java.

And just like in Java, you can easily access that maximum or minimum value:

// 9007199254740991

// -9007199254740991

Now, it seems difficult to spot problems with a value this high. But I was forced to think again.

Arithmetic for bank accounts

When building my IBAN generator/validator, I wrote some tests in Jest and after running them a couple of times, I decided things were good to go. But when I returned to the application, strange things were happening.

That's because validating or generating an IBAN number requires mathematical operations with large numbers. Looking at the example on Wikipedia, we need to perform a modulus operation on 3214282912345698765432161182, which is larger than the maximum value for a number in Javascript.

3214282912345698765432161182 > Number.MAX_SAFE_INTEGER
// true

The question is now: how can we safely proceed? Well, you can coerce a Number to a BigInt by adding "n" to the end of a number or by calling the BigInt constructor with a string that contains the integer value. Which leads to the following operations for our example number.

3214282912345698765432161182n % 97n
// 1n

BigInt("3214282912345698765432161182") % BigInt(97)
// 1n

Notice how you also can't perform these mathematical operations if both numbers aren't coerced to the same type (BigInt or Number).

BigInt("3214282912345698765432161182") % 97
// Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions

The main problem ofcourse is that you don't see the issues coming for (too) large numbers. Because when you perform this modulus operation without coercing to BigInt, you'll get a result that doesn't spell disaster.

Instead, it puts us on the wrong foot:

3214282912345698765432161182 % 97
// 65

It took me a while to figure it out so I got burned twice by the same flame. But that doesn't matter, I learned from it and next time, I'll see it coming even faster.

⇤ Return to blog overview