To represent integers larger than 2**53 – 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. 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:
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:
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:
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
:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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.