BigInt
is a new numeric primitive data type in JavaScript that allows you to work with arbitrary precision numbers. With BigInt
you can safely store and process large integers even beyond the maximum safe integer value Number
. In this article, we will look at some examples of using BigInt
and the new features of Chrome 67, comparing BigInt
and Number
in JavaScript.
Arbitrary precision integers open up many new uses for JavaScript.
BigInt allows you to prevent overflow errors during mathematical operations. This fact in itself makes countless possibilities available, for example, mathematical operations on large numbers are commonly used in financial technologies.
Large numeric identifiers and high-precision time stamps cannot be safely represented by the Number
data type in JavaScript. This often leads to errors and forces developers to store them as strings. With BigInt
this data can be represented as numeric values.
BigInt
can be used in a possible implementation of the BigDecimal
data type. This will allow storing monetary values ββas decimal fractions without loss of accuracy when performing operations (for example, without a 0.10 + 0.20 !== 0.30
problem 0.10 + 0.20 !== 0.30
).
Previously, in JavaScript, in any of these cases, you had to use libraries that emulate the BigInt
functionality. When BigInt
becomes widely available, it will be possible to abandon these dependencies in favor of natively supported BigInt
. This will help reduce download time, parsing and compilation, as well as increase runtime performance.
Native BigInt
runs faster than popular custom libraries
For the BigInt BigInt
, a library is required that implements the necessary functions, as well as a transfiguration step, to translate the new syntax into a library API call. Babel currently supports BigInt
parsing literals, but cannot convert them. Therefore, we do not hope that BigInt
will be used in production on sites that require compatibility with a wide range of browsers. However, now that this functionality is starting to appear in browsers, you can start experimenting with BigInt, expecting with time more and more support for BigInt.
The primitive Number
data type in JavaScript is represented by double-precision floating-point numbers. The constant Number.MAX_SAFE_INTEGER
contains the largest possible integer that can be safely incremented by one. Its value is 2 ** 53-1
.
const max = Number.MAX_SAFE_INTEGER; // β 9_007_199_254_740_991
Note: for readability, I group numbers using underscores as delimiters. The corresponding sentence will allow the use of such an entry for regular numeric JavaScript literals.
Increasing it by one gives the expected result:
max + 1; // β 9_007_199_254_740_992
But if we increase it by one more, Number
will not be able to accurately save the result:
max + 2; // β 9_007_199_254_740_992
Note that the result of the expression max + 1
will be equal to the result of the expression max + 2
. Therefore, whenever we get this particular value in javascript, one cannot say whether it is accurate or not. Any calculations with integers outside the safe integer range (that is, from Number.MIN_SAFE_INTEGER
to Number.MAX_SAFE_INTEGER
) are potentially not accurate. For this reason, we can only rely on integer values ββin the safe range.
BigInt
is a new numeric primitive data type in JavaScript that allows you to work with arbitrary precision numbers. With BigInt
you can safely store and process large integers even beyond the maximum safe integer value Number
.
To create BigInt
suffices to add the suffix n
to the literal notation of an integer. For example, 123
will become 123n
. The global function BigInt(number)
can be used to cast a number to BigInt
. In other words, BigInt(123) === 123n
. Let's use this to solve the problems we talked about above:
BigInt(Number.MAX_SAFE_INTEGER) + 2n; // β 9_007_199_254_740_993n
Here is another example, with the multiplication of two numbers of type Number
:
1234567890123456789 * 123; // β 151851850485185200000
If we look at the low-order digits, 9
and 3
, it can be argued that the result of the multiplication must end with 7
(because 9 * 3 === 27
). But the result ends with a set of zeros. Something went wrong. Let's try again with BigInt
:
1234567890123456789n * 123n; // β 151851850485185185047n
This time the result is correct.
The limits for safe operation with integers do not apply to BigInt
, so with BigInt
we can use long arithmetic without worrying about loss of precision.
BigInt
is a new primitive data type in the JavaScript language, so it gets its own type, which can return a typeof
operator:
typeof 123; // β 'number' typeof 123n; // β 'bigint'
Since BigInt
is an independent data type, a number of type BigInt
never be strictly equal to a number of type (for example, 42n !== 42
). To compare a number of type BigInt
and a number of type Number
, convert one of them to the type of the other before making a comparison, or use a comparison with type conversion ( ==
):
42n === BigInt(42); // β true 42n == 42; // β true
When casting to a boolean value (for example, in if
, using &&
or ||
, or as the result of a Boolean(int)
expression, and so on), numbers of type BigInt
behave exactly like numbers of type.
if (0n) { console.log('if'); } else { console.log('else'); } // β logs 'else', because `0n` is falsy.
BigInt
supports most operators. Binary +
, -
, *
and **
work as usual. /
and %
also work, rounding the result to a whole if necessary. Bitwise Operators |
, &
, <<
, >>
and ^
work with BigInt
numbers in the same way as Number
numbers, when negative numbers are represented in binary form as an additional code.
(7 + 6 - 5) * 4 ** 3 / 2 % 3; // β 1 (7n + 6n - 5n) * 4n ** 3n / 2n % 3n; // β 1n
Unary -
can be used to indicate a negative BigInt
value, for example, -42n
. Unary +
not supported because it violates the asm.js code, which expects that +x
will always return either a Number
or an exception.
The important point is that you should not mix BigInt
and Number
in operations. This is good because any implicit conversion can lead to loss of information. Consider an example:
BigInt(Number.MAX_SAFE_INTEGER) + 2.5; // β ??
What should be equal to the result? There is no right answer. BigInt
cannot contain fractional numbers, and Number
cannot accurately contain large numbers greater than the safe integer limit. Therefore, operations with BigInt
and Number
result in a TypeError
exception.
The only exception to this rule is comparison operators, such as ===
(discussed earlier), <
and >=
, since they return logical values ββthat do not carry the risk of losing accuracy.
1 + 1n; // β TypeError 123 < 124n; // β true
Note: since BigInt
and Number
usually do not mix, it is not necessary to overwrite the already existing code from Number
to BigInt
. Decide which of these two types you need and use it. For new APIs that work with potentially large integers, BigInt
is the best choice. However, Number
can still be used for values ββthat are guaranteed to be in the safe range of integers.
It is also worth noting that the >>>
operator, which performs an unsigned right shift, does not make sense for BigInt
numbers, since they always contain a sign. Therefore, >>>
does not work for BigInt
numbers.
Several new API methods for BigInt
become available.
The BigInt
global constructor BigInt
similar to the Number
constructor: it converts its argument to BigInt
(as mentioned earlier). If the conversion fails, a SyntaxError
or RangeError
exception will be thrown.
BigInt(123); // β 123n BigInt(1.5); // β RangeError BigInt('1.5'); // β SyntaxError
There are two functions that allow you to limit BigInt
values BigInt
specified number of significant bits, treating the number as either signed or unsigned. BigInt.asIntN(width, value)
limit the number value
type BigInt
to the number of bits specified in width
taking into account the sign, and BigInt.asUintN(width, value)
will do the same, considering the value as unsigned. For example, if you need operations on 64-bit numbers, you can use these APIs to stay in the appropriate range:
// `BigInt`, // 64- . const max = 2n ** (64n - 1n) - 1n; BigInt.asIntN(64, max); // β 9223372036854775807n BigInt.asIntN(64, max + 1n); // β -9223372036854775808n // ^ ,
Notice that the overflow occurs as soon as we pass a BigInt
that exceeds the 64-bit integer range (i.e. 63 bits for the value itself and 1 bit for the character).
BigInt
allows BigInt
to accurately represent 64-bit signed and unsigned integers that are commonly used in other programming languages. Two new typed arrays, BigInt64Array
and BigUint64Array
, simplify working with these values:
const view = new BigInt64Array(4); // β [0n, 0n, 0n, 0n] view.length; // β 4 view[0]; // β 0n view[0] = 42n; view[0]; // β 42n
BigInt64Array
guarantees that its values ββwill be within the limits of possible 64-bit signed values.
// `BigInt`, // 64- . const max = 2n ** (64n - 1n) - 1n; view[0] = max; view[0]; // β 9_223_372_036_854_775_807n view[0] = max + 1n; view[0]; // β -9_223_372_036_854_775_808n // ^ ,
BigUint64Array
works similarly for unsigned 64-bit values.
BigInt
fun with BigInt
!
Source: https://habr.com/ru/post/354930/
All Articles