DEV Community

Cover image for Counting Stars with JavaScript: Using the BigInt Type
Michael Mathews
Michael Mathews

Posted on • Edited on

Counting Stars with JavaScript: Using the BigInt Type

JavaScript's native Number type is a 64-bit floating-point value (IEEE 754 double-precision). While this gives you a massive range, JavaScript integer Numbers are still limited. In JavaScript, integer values are only precise up to 2⁵³ - 1.

The number 2⁵³ represents the result you get when you multiply the number 2 by itself, 53 times in a row. So the maximum safe integer number is 2**53 - 1 or 9,007,199,254,740,991, about nine quadrillion, give or take a few trillion.

But don't bother trying to remembering that number; JavaScript has helpfully given it an easy-to-recall name: Number.MAX_SAFE_INTEGER.

console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991 
Enter fullscreen mode Exit fullscreen mode

As the name implies, once you start working with integer Numbers larger than Number.MAX_SAFE_INTEGER, you can't safely assume the accuracy of any result.

There is also a corresponding Number.MIN_SAFE_INTEGER value. It represents JavaScript's smallest safe integer value, or -(2⁵³ - 1).

console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991 
Enter fullscreen mode Exit fullscreen mode

By "safe," we mean:

  • Accurately represented: A safe integer won't get rounded to a different value due to insufficient precision.
  • Correctly compared: Comparisons between safe integers will yield mathematically correct results.

To illustrate, let's try something with a couple of unsafe values and see how it can go mathematically wrong:

const x = Number.MAX_SAFE_INTEGER; console.log(x + 1 === x + 2); // true! (but not correct) 
Enter fullscreen mode Exit fullscreen mode

What's the point?

You might think, I'll just stick to numbers smaller than nine quadrillion -- it's a plenty big-enough number after all. That's true. In fact, if you ever tried to count up to 9 quadrillion, even at one number per second and without any breaks, it would take you about 285 million years!

While working with such massive numbers is not typical, it wouldn't be inconceivable. Here are a few examples of real integer values where Number.MAX_SAFE_INTEGER isn't big enough.

Genes in the human body

The estimated number of gene copies in an adult human body (spread across our 30 to 40 trillion cells) is about 2 × 10¹⁸ (2 quintillion). MAX_SAFE_INTEGER is 222 times too small to represent the number of gene copies in the human body.

Milliseconds since the Big Bang

The universe's age is about 13.8 billion years, or about 4.4 × 10²⁰ milliseconds (440 quintillion ms). MAX_SAFE_INTEGER is about 50,000 times too small to represent the number of milliseconds since the dawn of time.

Stars in the observable universe

The estimated number of stars in the observable universe is between 10²² and 10²⁴ (1 septillion). MAX_SAFE_INTEGER is about 100 million times too small to represent the number of stars in the observable universe.

So while Number.MAX_SAFE_INTEGER is big, it's not big enough for some values in astronomy, geography, genetics, cryptography, or large financial systems. That's when we reach for the BigInt primitive type. BigInt can handle values way beyond Numbers's 64-bit limit.

Meet BigInt

BigInt is a primitive type introduced in ES2020 that can represent integers with arbitrary precision. That means you can work with much larger integer values. There is no upper maximum specified for BigInt; the implementation of the JavaScript engine you use and the available memory on your machine are the only practical limits.

A BigInt value is created by appending the letter n to the end of an integer literal or calling the BigInt() function and giving it an integer or string value.

Here's how it works:

const x = BigInt(Number.MAX_SAFE_INTEGER); console.log(x + 1n === x + 2n); // false, now works correctly 
Enter fullscreen mode Exit fullscreen mode

Key characteristics

  1. Literal syntax: Append n to create a BigInt literal (123n).
  2. Distinct Type: It's one of the built-in primitive types in JavaScript (typeof 1n returns "bigint").
  3. No decimals: BigInt can only represent whole numbers (integers) (BigInt(1.1) throws a RangeError).

Considerations

There are several limitations you must keep in mind when working with BigInt values.

JSON serialization

BigInt values aren't supported in JSON.

JSON.stringify({ value: 123n }); // TypeError: Do not know how to serialize a BigInt 
Enter fullscreen mode Exit fullscreen mode

Integers only

As the "Int" in the name implies, BigInt is for integers (whole numbers) only. If you forget about this limitation you might be surprised.

console.log(10n / 1n); // 10n console.log(10n / 3n); // 3n (but not correct) 
Enter fullscreen mode Exit fullscreen mode

Don't mix

BigInt values cannot be combined with regular Number values (1n + 1 is a TypeError, but 1n + 1n is okay).

Watch your speed

Expect code that uses BigInt values to be at least slightly slower than the same code using ordinary Numbers. This is because floating-point arithmetic (used by Number) is implemented directly in the computer hardware, while arbitrary-precision arithmetic, used by BigInt, is implemented in software. Your computer hardware is far faster than any software!

What about TypeScript?

The bigint type is fully supported in TypeScript, just like any other primitive type. However, you must set the "target" property inside the "compilerOptions" object in your tsconfig.json file, to "ES2020" or later.

let x: bigint; x = 1234567890123456789012345678901234567890n; // OK x = BigInt("1234567890123456789012345678901234567890"); // OK x = 12345; // ERROR Type 'number' is not assignable to type 'bigint'. 
Enter fullscreen mode Exit fullscreen mode

Fun fact

Reading long numerical values can be confusing for humans, if not for computers. By convention, we tend to add digit grouping characters to make them more readable. For example, a comma separates the thousands in long numbers in English-speaking countries, like "1,000,000". Other countries use different symbols; you might see that written as "1’000’000" in Switzerland and Liechtenstein, "1.000.000" in other European countries, or even "1 000 000" in some scientific settings.

JavaScript supports using an underscore character to group digits. So while your computer has no problem understanding 1000000, you can write 1_000_000 instead if it's easier to read.

Top comments (0)