`BigInt`

primitive was added to the ECMAScript specification, what problem it solves, and how to get started with it here.
The post Why (and how) to use <code>BigInt</code> appeared first on LogRocket Blog.

]]>`Number`

primitive had a limit on the minimum and maximum values it could represent correctly.
Consequently, this led to many unstable workarounds, such as converting large values to strings, or outsourcing work to third-party vendors, which led to bugs and/or large build sizes.

But with the introduction of the `BigInt`

primitive to the ECMAScript specification, developers no longer need to rely on fragile workarounds or third-party libraries. Instead, `BigInt`

allows them to safely work with numbers beyond the limits of the `Number`

primitive.

In this article, we’ll learn what prompted the addition of the `BigInt`

primitive into the ECMAScript specification, how `BigInt`

solves the problem, and, lastly, we’ll learn how to get started with `BigInt`

.

`BigInt`

?Because there are many limitations using `Number`

and data types in JavaScript.

In JS, the `Number`

data type represents all numbers in JavaScript as double-precision-floating point number using the format defined by the IEEE 754, meaning that numbers in JavaScript are represented as double precision floats, or doubles for short.

Conventionally, because the `Number`

primitive represents all numbers as doubles, they are always allocated 64 bits of memory. With it, numbers ranging from -1.7*10^308 to 1.7*10^308 can be represented and stored in variables.

Unfortunately, we cannot reliably work with all the numbers within this range as most of them are *unsafe integers* — numerical representations that reference more than one real world number.

This occurs because even though a specific real world number cannot be exactly represented according to the IEEE 754 format, it will be rounded using one of the standard “rounding modes” in order to force the number to adhere to the format.

The result? The computer will round certain numbers in a way that makes them equal to other numbers that do not need to be rounded in order to ensure it follows the format.

Essentially, these unsafe integers do not have their own private representation; instead, they erroneously share the representation of other real world numbers that do not need to undergo rounding to conform to the format.

Here’s an example:

// JS defines the maximum safe interger as a constant Number.MAX_SAFE_INTEGR const safeInt = Number.MAX_SAFE_INTEGER // -> 9_007_199_254_740_991 // If we add one we get safeInt + 1 // -> 9_007_199_254_740_992 ✅ // If we add 2... safeInt + 2 // -> 9_007_199_254_740_992 🤦🏾♂ // Therefore 9_007_199_254_740_992 or (2^53) is deemed unsafe because two real world numbers 9_007_199_254_740_992 and 9_007_199_254_740_993 are represented through it. That is why safeInt + 1 === safeInt + 2 // -> true

So, what does this mean? Using numbers greater than or smaller than `Number.MAX_SAFE_INTEGR`

or `Number.MIN_SAFE_INTEGER`

is guaranteed to cause bugs.

Many of us may need not worry about this, as the range of numerical quantities we use is well within the limits of `Number.MAX_SAFE_INTEGR`

and `Number.MIN_SAFE_INTEGR`

.

Nevertheless, some developers have to work beyond these boundaries, such as those who work in finance or find themselves constantly performing calculations with incredibly large numbers.

Fortunately, there is a solution: `BigInt`

.

`BigInt`

?`BigInt`

is a relatively new numeric primitive/integer type in JavaScript. It was created to solve the limitations people ran into with the `Number`

primitive and safe integer restrictions.

`BigInt`

represents numbers with arbitrary precision, meaning it uses as much space as needed to store and represent large numbers instead of forcefully trying to represent them using a fixed amount of memory like the `Number`

integer type does.

You can think of `BigInt`

and `Number`

like static and dynamic arrays. `BigInt`

will use up more space if it needs to when representing a large number, like a dynamic array. But `Number`

will only make use of the fixed memory initially allotted to it to represent numbers, like a static array.

`BigInt`

gives us the ability to work with large numbers without having to worry about potentially losing precision (digits) or weird representation issues that hamper accuracy and create bugs.

`BigInt`

To create a `BigInt`

, simply add `n`

at the end of any integer literal. Notice that doing so with decimals/floats will throw a `RangeError`

:

// This is alright const bigInteger = 1000000000000000000000000n // This will throw a RangeError const bigInteger = 1.5n // -> RangeError // You can also create a BigInt with negative numbers const negativeBigIntInteger = -1111111n // -> -1111111n

Alternatively, you can also use the global `BigInt`

function passing an integer literal as an argument.

// This is also alright const bigIntefer = BigInt(1000000000000000000000000000000000) // This will still throw a RangeError const bigInteger = BigInt(1.5)

`BigInt`

literals can also be instantiated using strings, binary, hexadecimal, or octal notation.

// Strings BigInt("1111111111111111111111111111111111111") // -> 1111111111111111111111111111111111111n // Binary BigInt(0b100000000000000000000000000000000000000000000000000000000000000000000001111111) // -> 151115727451828646838272n // Hexadecimal BigInt(0xfffffffffffffffffffffffffffffffffff9fff9fffffffffffffffff) // -> 95780971304118053647396689196894323976171195136475136n // Octal BigInt(0o40000000000000000000000000000000000000000011112444) // -> 713623846352979940529142984724747568191373312n

You cannot compare a `BigInt`

and a regular `Number`

using strict equality (`===`

) because `BigInt`

is a primitive on its own.

Therefore, calling `typeof`

on a `BigInt`

literal will return `"bigint"`

instead of `"number"`

, causing strict comparisons between them to return false.

const a = 111111n const b = 111111 a === b // -> false

However, if you were to use abstract equality (`==`

), then comparing a `BigInt`

literal with a value of `11n`

and a `Number`

literal with a value of `11`

will return `true`

because both literals are of the same value.

const a = 11n const b = 11 a == b // -> true

All arithmetic operations (`+`

, `-`

, `/`

, `*`

) can be performed on `BigInt`

literals, with the exception of unary plus. For example, you can’t write `+11n`

like you would `+11`

.

On the other hand, you can increment `BigInt`

literals with `++`

and decrement them with `--`

.

Moreover, arithmetic with `BigInt`

literals must be between `BigInt`

literals. A `Number`

literal cannot be an operand in an arithmetic operation involving a `BigInt`

. Trying to do so will result in a `TypeError`

.

// We can do this 11n + 12n // -> 23n // But we can't do this 11n + 12 // -> TypeError

Additionally, because `BigInt`

arithmetic returns a `BigInt`

, the return value will always be an integer of type `"bigint"`

.

5n / 3n // -> 1n 19n / 2n // -> 9n

`BigInt`

literals greater than `0n`

are all coerced to `true`

. While `0n`

, is coerced to `false`

.

if (5n) { // Code block will run } if (0n) { // Code block will not run }

Also, `BigInt(true)`

will return `1n`

.

BigInt(true) === 1n // -> true

The `BigInt`

global function contains two static methods that will restrict a `BigInt`

representation to using a number of bits that is specified as the first parameter of both methods.

Once `BigInt`

is within the specified space limit, it will be returned as either a signed or unsigned integer, depending on the method used.

The first method, `BigInt.asIntN(bits, <bigInt-number>)`

, returns the `<bigInt-number>`

as a signed integer.

The second method, `BigInt.asUintN(bits, <bigInt-number>)`

returns the `<bigInt-number>`

as an unsigned integer.

These methods may be useful for explicit memory management. We know that, by default, `BigInt`

uses as many bits as necessary to represent a number, but, if you are strapped for memory and know the range for the numerical values for your application, then these methods will be useful.

// For representing BigInt numbers as signed integers BigInt.asIntN(bits, <BigInt>) // For representing BigInt numbers as unsigned integers BigInt.asUintN(bits, <BigInt>)

After reading this article, you hopefully have a deeper understanding of what `BigInt`

is, the problems it solves, and how to use it.

Thank you for reading!

The post Why (and how) to use <code>BigInt</code> appeared first on LogRocket Blog.

]]>