Using JavaScript BigInt to Represent Large Numbers
Tags: javascript, webdev, beginners, tutorial
Published: 2020-01-07 03:38:32

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

**Follow me on Twitter at https://twitter.com/AuMayeung**

To represent integers larger than 2<sup>53</sup> -  1 in JavaScript, we can use the `BigInt` object to represent the values.

It can be manipulated via normal operations like arithmetic operators — addition, subtraction, multiplication, division, remainder, and exponentiation.

It can be constructed from numbers and hexadecimal or binary strings. Also, it supports bitwise operations like AND, OR, NOT, and XOR. The only bitwise operation that doesn’t work is the zero-fill right-shift operator (`>>>` ) because `BigInts` are all signed.

Also, the unary `+` operator isn’t supported to not break [asm.js](http://asmjs.org/). These operations are only done when all the operands are `BigInts`. We can’t have some operands being `BigInts` and some being numbers.

In JavaScript, a `BigInt` is not the same as a normal number. It’s distinguished from a normal number by having an `n` at the end of the number. We can define a `BigInt` with the `BigInt` factory function.

It takes one argument that can be an integer number or a string representing a decimal integer, hexadecimal string, or binary string. `BigInt` cannot be used with the built-in `Math` object.

Also, when converting between number and `BigInt` and vice versa, we have to be careful because the precision of `BigInt` might be lost when a `BigInt` is converted into a number.

* * *

Usage
=====

To define a `BigInt`, we can write the following if we want to pass in a whole number:

```javascript
const bigInt = BigInt(1);  
console.log(bigInt);
```

It would log `1n` when we run the `console.log` statement. If we want to pass a string into the factory function instead, we can write:

```javascript
const bigInt = BigInt('2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222');  
console.log(bigInt);
```

We can also pass an hexadecimal number string with a string that starts with `0x` into the factory function:

```javascript
const bigHex = BigInt("0x1fffffffffffff111111111");  
console.log(bigHex);
```

The code above would log `618970019642690073311383825n` when we run `console.log` on `bigHex`.

Likewise, we can pass in a binary string with a string that starts with `0b` and binary string in the remainder of the string to get a `BigInt`:

```javascript
const bigBin = BigInt("0b111111111111111000000000011111111111111111111111");  
console.log(bigBin);
```

The code above would get us `281466395164671n` when we run `console.log` on it. Passing in strings would be handy if the `BigInt` that we want to create is outside of the range that can be accepted by the number type.

We can also define a `BigInt` with a `BigInt` literal, we can just attach an `n` character to the whole number. For example, we can write:

```javascript
const bigInt = 22222222222222222222222222222222n;  
console.log(bigInt);
```

Then, we get `22222222222222222222222222222222n` as the value of `bigInt` when we log the value.

`BigInt` has its own data type in JavaScript. When you run the `typeof` operator on a `BigInt` variable, constant or value, we would get `bigint`. For example, when we run:

```javascript
typeof 2n === 'bigint';  
typeof BigInt(2) === 'bigint';
```

Both lines of code would evaluate to `true`. However, if we wrap it with the `Object` factory function, we get that the type is an object:

```javascript
typeof Object(2n) === 'object';
```

The code above would evaluate to `true`.

We can apply number operations to `BigInts`.

This includes the arithmetic operators — addition, subtraction, multiplication, division, remainder, and exponentiation. Also, it supports bitwise operations like AND, OR, NOT, and XOR.

The only bitwise operation that doesn’t work is the zero-fill right-shift operator (`>>>` ) because `BigInts` are all signed. Also, the unary `+` operator isn’t supported to not break asm.js.

These operations are only done when all the operands are `BigInts`. We can’t have some operands being `BigInts` and some being numbers. For example, if we have:

```javascript
const bigInt = BigInt(Number.MAX_SAFE_INTEGER);  
console.log(bigInt);
const biggerInt = bigInt + BigInt(1);  
console.log(biggerInt);
const evenBiggerInt = bigInt + BigInt(2);  
console.log(evenBiggerInt);
const multi = bigInt * BigInt(2);  
console.log(multi);
const subtr = bigInt - BigInt(10);  
console.log(subtr);
const remainder = bigInt % BigInt(1);  
console.log(remainder);
const bigN = bigInt ** BigInt(54);  
console.log(bigN);
const veryNegativeNum = bigN * -BigInt(1)  
console.log(veryNegativeNum);
```

We get 9007199254740991n for `bigInt`, 9007199254740992n for `biggerInt`, 9007199254740993n for `evenBiggerInt`, 18014398509481982n for `multi`, 9007199254740981n for `subtr`, 0n for `remainder`, 3530592467533273200243077170885155617107348521747142286627863260349958518655132050034081285541183004983189865471543609006121689601641796259277395721973496380268998810860889580999688899063966604079229944616948651888866122410855207004436640389001057851295873774080462273415460559916461808220601907673652198075821210257903676343961872269549414664419834643799298966710366275919846143068708381391506113181640387818197335712192797007703730122048543818655729529755334964590919971124632271934272078761071878238334159341746985273963326734748343552398522547662400805644304911487571159654254814460707275228515191584712593238883953404971043549757327554636466197405269908317698331974392008288867249576664013677011521696874812515379689360830743272800013459321098384864332719963035293422648481458040217707301509007592199565531403472471705983351384755965631442881685949576642561n for `bigN`, and -3530592467533273200243077170885155617107348521747142286627863260349958518655132050034081285541183004983189865471543609006121689601641796259277395721973496380268998810860889580999688899063966604079229944616948651888866122410855207004436640389001057851295873774080462273415460559916461808220601907673652198075821210257903676343961872269549414664419834643799298966710366275919846143068708381391506113181640387818197335712192797007703730122048543818655729529755334964590919971124632271934272078761071878238334159341746985273963326734748343552398522547662400805644304911487571159654254814460707275228515191584712593238883953404971043549757327554636466197405269908317698331974392008288867249576664013677011521696874812515379689360830743272800013459321098384864332719963035293422648481458040217707301509007592199565531403472471705983351384755965631442881685949576642561n for `veryNegativeNum`.

Note that when we get fractional results, the fractional parts will be truncated when result has it. `BigInt` is a big integer and it’s not for storing decimals. For example, in the examples below:

```javascript
const expected = 8n / 2n;  
console.log(expected)const rounded = 9n / 2n;  
console.log(rounded)
```

We get 4n for `expected` and `rounded`. This is because the fractional part is removed from the `BigInt`.

Comparison operators can be applied to BigInts. The operands can be either `BigInt` or numbers. We can use the bigger than, bigger than or equal to, less than, less than or equal to, double equals, and triple equals operators with BigInts.

For example, we can compare 1n to 1:

```javascript
1n === 1
```

The code above would evaluate to `false` because `BigInt` and numbers aren’t the same types. But when we replace triple equals with double equals, like in the code below:

```javascript
1n == 1
```

The statement above evaluates to `true` because only the value is compared.

Note that in both examples, we mixed `BigInt` operands with number operands. This is allowed for comparison operators.

BigInts and numbers can be compared together with other operators as well, like in the following examples:

```javascript
1n < 9  
// true9n > 1  
// true9 > 9n  
// false  
  
9n > 9  
// false  
  
9n >= 9  
// true
```

Also, they can be mixed together in one array and sorted together. For example, if we have the following code:

```javascript
const mixedNums = [5n, 6, -120n, 12, 24, 0, 0n];  
mixedNums.sort();  
console.log(mixedNums)
```

We get `[-120n, 0, 0n, 12, 24, 5n, 6]`. We also sort it in descending order with the following code:

```javascript
const mixedNums = [5n, 6, -120n, 12, 24, 0, 0n];  
mixedNums.sort((a, b) => {  
  if (a > b) {  
    return -1  
  } else if (a < b) {  
    return 1  
  }  
  return 0  
});  
console.log(mixedNums)
```

In the code above, we used the comparison operators to compare the value of the numbers and return -1 if the first number is bigger than the second number, return 1 if the first number is less than the second number, and return 0 otherwise.

If we wrap BigInts with `Object`, then they’re compared as objects, so two objects are only considered the same if the same instance is referenced. For example, if we have:

```javascript
0n === Object(0n);  
Object(0n) === Object(0n);  
const o = Object(0n);  
o === o;
```

Then the first three lines in the code above would evaluate to `false` while the last line would evaluate to `true`.

When BigInts are coerced into booleans, they act the same as if they're numbers. For example, `Boolean(0n)` would return `false`, and anything else would return `true`.

For example, we can coerce them into booleans like in the following code:

```javascript
0n || 11n  
// 11n  
  
0n && 11n  
// 0n  
  
Boolean(0n)  
// false  
  
Boolean(11n)  
// true  
  
!11n  
// false  
  
!0n  
// true
```

* * *

BigInt Methods
==============

The `BigInt` object has several methods. There are the static `asIntN()`  and `asUintN()`  methods, and the `toLocaleString()`, `toString()`, and `valueOf()` instance methods.

The `asIntN` method wraps a `BigInt` value between -2 to the width minus 1 and 2 to the width minus 1. For example, if we have:

```javascript
const bigNum = 2n ** (62n - 1n) - 1n;  
console.log(BigInt.asIntN(62, bigNum));
```

Then we get the literal of the actual value of `bigNum` modulo 62 returned, which is 2305843009213693951n. However, if we have:

```javascript
const bigNum = 2n ** (63n - 1n) - 1n;  
console.log(BigInt.asIntN(62, bigNum));
```

We get -1n since the `2n ** (63n — 1n)` modulo `2n ** 63n` is returned.

The `asUintN()` method wraps a `BigInt` value between 0 and 2 to the width minus 1. For example, if we have:

```javascript
const bigNum = 2n ** 11n - 1n;  
console.log(BigInt.asUintN(11, bigNum));
```

Then we get the literal of the actual value of `bigNum` returned, which is 2305843009213693951n. However, if we have:

```javascript
const bigNum = 2n ** 11n - 1n;  
console.log(BigInt.asUintN(11, bigNum));
```

We get 2047n since the `2n ** 11n — 1n` modulo `2n ** 11n` is returned.

`BigInt` has a `toLocaleString()` method to return the value of the string for the `BigInt` depending on the locale we pass in. For example, if we want to get the French representation of a `BigInt`, we can write:

```javascript
const bigNum = 2n ** 60n - 1n;  
console.log(bigNum.toLocaleString('fr'));
```

The code above will log `1 152 921 504 606 846 975`.

The `toString()` method will convert a `BigInt` to a string. For example, we can write:

```javascript
const bigNum = 2n ** 60n - 1n;  
console.log(bigNum.toString());
```

The code above will log `1152921504606846975`.

The `valueOf` method will get the value of the `BigInt` object. For example, if we run:

```javascript
const bigNum = 2n ** 60n - 1n;  
console.log(bigNum.valueOf());
```

Then we get `1152921504606846975n` logged.

BigInts aren’t supported by JSON, so a `TypeError` would be raised if we try to convert it to JSON with `JSON.stringify()`.

However, we can convert it to something supported like a string, then it can be stored as JSON. We can override the `toJSON` method of a `BigInt` by writing:

```javascript
BigInt.prototype.toJSON = function() {  
  return this.toString();  
}

const bigIntString = JSON.stringify(88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888n)  
console.log(bigIntString);
```

Then, we get: `“88888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888”`.

BigInts are useful for representing integers larger than 2 to the 53rd power minus 1 in JavaScript, we can use the `BigInt` object to represent the values.

It can be manipulated via normal operations like arithmetic operators — addition, subtraction, multiplication, division, remainder, and exponentiation.

BigInts support most bitwise operations like AND, OR, NOT, and XOR.

They can also be converted from hexadecimal or binary numbers.

These operations are only done when all the operands are BigInts. We can’t have some operands being BigInts and some being numbers.

In JavaScript, a `BigInt` is not the same as a normal number. It’s distinguished from a normal number by having an `n` at the end of the number. We can define a `BigInt` with the `BigInt` factory function.

It takes one argument that can be an integer number or a string representing a decimal integer, hexadecimal string, or binary string. `BigInt` cannot be used with the built-in `Math` object.