Bigint js что это
Перейти к содержимому

Bigint js что это

  • автор:

Большое целое

В математике числа бесконечны, а в программировании — нет. Если число не влезает в стандартный number , то есть его старший брат.

Время чтения: меньше 5 мин

Это незавершённая статья. Вы можете помочь её закончить! Почитайте о том, как контрибьютить в Доку.

Открыть/закрыть навигацию по статье

Обновлено 19 июля 2022

Кратко

Скопировать ссылку «Кратко» Скопировано

Тип большого целого Big Int — примитивный тип, который представляет целые числа больше 2 53 -1. Эти числа уже не помещаются в стандартный примитив «число».

Этот тип может использоваться для работы с произвольно большими целыми числами.

Как пишется

Скопировать ссылку «Как пишется» Скопировано

Создать Big Int можно двумя способами.

1️⃣ Добавить суффикс n в конец записи числа:

 const biggy = 9997000254740991n const biggy = 9997000254740991n      

2️⃣ Вызвать конструктор Big Int :

 const alsoBig = BigInt(9997000254999999) const alsoBig = BigInt(9997000254999999)      

Для Big Int определены операции сложения + , вычитания — , умножения * , взятия остатка от деления % , возведение в степень ** .

Операция деления / также работает, но дробная часть будет отброшена:

 const seven = 7nconst five = 5n console.log(seven / five)// 1 const seven = 7n const five = 5n console.log(seven / five) // 1      

Big Int не сериализуется в JSON. Это усложняет использование этого типа данных в задачах взаимодействия с сервером.

BigInt – полное руководство по новому типу данных JavaScript

BigInt позволяет JavaScript- программистам использовать целочисленные значения, превышающие диапазон, поддерживаемый типом данных Number. Благодаря использованию BigInt целочисленное переполнение больше не будет проблемой.

Также с помощью нового типа данным можно безопасно работать с метками времени, большими целочисленными идентификаторами, не прибегая к обходным путям. После добавления в спецификацию BigInt станет вторым числовым типом данных в JavaScript

В этой статье мы рассмотрим тип данных BigInt и узнаем, как он может помочь преодолеть ограничения типа данных Number в JavaScript.

Обновлено: 2023-06-14 19:09:24 Сергей Бензенко автор материала

Проблема

Многие языки программирования поддерживают несколько числовых типов данных: float, double, integer и bignum. Но в JavaScript все числа представлены в 64-битном формате с плавающей запятой двойной точности, как определено стандартом IEEE 754-2008.

Согласно нему, большие целые числа, которые не могут быть точно представлены, автоматически округляются. Поэтому тип данных Number в JavaScript может безопасно представлять только целые числа от -9007199254740991 (-(2 53 -1)) до 9007199254740991 (2 53 -1). Любое целочисленное значение, выпадающее из этого диапазона, будет округлено.

Это можно легко проверить, выполнив следующий код:

console.log(9999999999999999); // → 10000000000000000

Это целое число больше максимального значения, которое JavaScript может представить с помощью типа данных Number. Поэтому оно округлено. Это может поставить под угрозу надежность и безопасность приложения.

Вот еще один пример:

// обратите внимание на последние цифры 9007199254740992 === 9007199254740993; // → true

JavaScript предоставляет константу Number.MAX_SAFE_INTEGER, которая позволяет быстро получить максимально безопасное целое число. Точно так же вы можете получить минимальное безопасное целое число, используя константу Number.MIN_SAFE_INTEGER:

const minInt = Number.MIN_SAFE_INTEGER; console.log(minInt); // → -9007199254740991 console.log(minInt - 5); // → -9007199254740996 // заметьте, что отображается то же число, что и выше console.log(minInt - 4); // → -9007199254740996

Решение

Для обхода этих ограничений JavaScript- разработчики представляют большие целые числа, используя тип данных String. Например, API Twitter добавляет строковую версию идентификаторов к объектам в ответах, пересылаемых в формате JSON. Также разработан целый ряд библиотек, таких как bignumber.js, чтобы упростить работу с большими целыми числами.

Благодаря типу данных BigInt приложениям больше не требуется обходной путь для безопасного представления целых чисел за пределами Number.MAX_SAFE_INTEGER и Number.MIN_SAFE_INTEGER. Арифметические операции над большими целыми числами теперь могут выполняться в JavaScript без риска потери точности.

Дополнительным преимуществом использования BigInt вместо сторонней библиотеки является лучшая производительность кода во время выполнения.

Чтобы создать BigInt, добавьте n в конец целого числа. Для сравнения:

console.log(9007199254740995n); // → 9007199254740995n console.log(9007199254740995); // → 9007199254740996

Также можно вызвать конструктор BigInt():

BigInt("9007199254740995"); // → 9007199254740995n

Значения BigInt также могут быть записаны в двоичной, восьмеричной или шестнадцатеричной системе исчисления:

// двоичная console.log(0b100000000000000000000000000000000000000000000000000011n); // → 9007199254740995n // шестнадцатеричная console.log(0x20000000000003n); // → 9007199254740995n // восьмеричная console.log(0o400000000000000003n); // → 9007199254740995n // заметьте, что старая форма восьмеричной записи не поддерживается console.log(0400000000000000003n); // → синтаксическая ошибка

Но вы не сможете использовать оператор строгого равенства для сравнения BigInt с обычным числом, потому что они разного типа данных:

console.log(10n === 10); // → false console.log(typeof 10n); // → bigint console.log(typeof 10); // → number

Вместо этого можно использовать оператор равенства, который выполняет неявное преобразование типов данных перед компиляцией:

console.log(10n == 10); // → true

В BigInt могут использоваться все арифметические операторы, кроме унарного оператора плюс (+):

10n + 20n; // → 30n 10n - 20n; // → -10n +10n; // → Ошибка: нельзя преобразовать значение BigInt value в number -10n; // → -10n 10n * 20n; // → 200n 20n / 10n; // → 2n 23n % 10n; // → 3n 10n ** 3n; // → 1000n const x = 10n; ++x; // → 11n --x; // → 9n

Некоторые программы могут полагаться на инвариант, в котором оператор + всегда создаёт Number или выдает исключение. Изменение поведения оператора + также приведет к нарушению кода asm.js.

При использовании BigInt ожидается, что арифметические операторы будут возвращать значение BigInt. Поэтому результат работы оператора деления (/) автоматически округляется до ближайшего целого числа. Например:

25 / 10; // → 2.5 25n / 10n; // → 2n

Неявное преобразование типа

При неявном преобразовании типов данных может потеряться информация, поэтому операции между BigInt и Number не допускаются. При операциях с большими целыми числами и чисел с плавающей запятой результирующее значение может быть представлено как BigInt или Number. Рассмотрим следующий пример:

(9007199254740992n + 1n) + 0.5

Результат этого выражения находится вне диапазона BigInt и Number. Число с дробной частью не может быть точно преобразовано в BigInt. И BigInt больше 2 53 не может быть точно преобразовано в Number.

Из-за этого невозможно выполнять арифметические операции между Number и BigInt. Попытка сделать это вызовет ошибку TypeError:

10 + 10n; // → TypeError Math.Max(2n, 4n, 6n); // → TypeError

Number и BigInt

С момента своего создания в 1995 году, в JavaScript был только один числовой тип данных — Number, который имеет ограничения в пределах 64-битового формата IEEE-754. Это означает, что безопасно доступны целые числа в диапазоне от-(2^53 — 1) до (2^53 — 1) из-за ограничений на хранение позиции точки. Поэтому числа, выходящие за эти границы, будут преобразованы в Infinity или -Infinity. Однако с выходом ES2020 появился новый тип данных — BigInt, который позволяет работать с целыми числами любой длинны. Для создания значения с таким типом достаточно добавить n в конце числа при вводе вручную или передать нужное значение в функцию BigInt.

console.log(10 ** 1000); //Infinity console.log(10n ** 1000n); //выведет все значение огромным числом

BigInt во многих ситуациях ведет себя как Number, например с большинством математических операторов, а так же при преобразовании в Boolean , использовании логических операторов || , && , ! и при проверке условий. Но не может его полностью заменить т.к. имеет ряд ограничений:

  • Оператор деления округляет результат в меньшую сторону до целого потому что BigInt представляет только целые числа.
  • BigInt нельзя смешивать в одних выражениях с Number, для подобных операций следует приводить значения к одному типу данных, но не стоит забывать, что при приведении Number к BigInt потеряется вся дробная часть, а при приведении BigInt к Number — точность и обход ограничения максимального значения.
  • Унарный плюс не подойдет для приведения BigInt к Number поэтому следует использовать глобальный объект Number .
  • Строгое сравнение “одинаковых” значений этих двух типов данных вернет false ( 1n === 1 //false ), при этом другие операторы сравнения будут работать как обычно вне зависимости от того, какими типами данных представлены числа, как и метод .sort массивов, элементы которых являются любым из числовых типов.
  • Для использования объекта Math BigInt так же придется приводить к Number.
  • Если вы попытаетесь использовать функцию JSON.stringify() на значении типа BigInt, то столкнетесь с ошибкой TypeError. Это происходит потому что по умолчанию значения BigInt не могут быть правильно преобразованы в формат JSON.
console.log(3n / 2n); //1n //результат округлен с 1,5 до целого 1 console.log(3n / 2); //TypeError: Cannot mix BigInt and other types console.log(BigInt(1.5)); //RangeError: The number 1.5 cannot be converted to a BigInt because it is not an integer console.log(BigInt(Math.round(1.5))); //2n //для преобразования Number в BigInt придется округлять значение console.log(+2n); //TypeError: Cannot convert a BigInt value to a number console.log(Number(2n)); //2 //Для конвертации BigInt в Number нужно использовать глобальный объект Number console.log(JSON.stringify(2n)); //TypeError: Do not know how to serialize a BigInt

Неточности при вычислениях в JavaScript

BigInt призван не только снять ограничение по размеру положительных и отрицательных числе в JavaScript, но и решить проблему неточности при работе с большими числами. Как мы уже знаем, JavaScript хранит Number в 64-битном формате IEEE-754. Из этих 64 бит один хранит знак числа, 11 — позицию десятичной дроби и оставшиеся 52 — само число и если число занимает больше 52 бит — часть информации будет утрачена. BigInt предотвращает такую потерю.

console.log(9999999999999999); //выведет 10000000000000000 console.log(9999999999999999n); //выведет 9999999999999999n

Однако BigInt подходит только для целых чисел. При работе дробями так же могут возникать неточности вычислений из-за переполнения памяти, отведенной под знаки после запятой. На самом деле такие неточности возникают чаще, чем кажется, но формат IEEE-754 незаметно для нас округляет дробь до ближайшего возможного числа. Видим же мы последствия переполнения 11 бит, в основном при математических операциях с дробями. Тут уже нам самим нужно при написании кода позаботиться о корректности вывода результатов операций с дробями, например округлив этот результат до допустимого знака после запятой с помощью метода .toFixed() .

console.log((0.1).toFixed(18)); //0.100000000000000006 //можно увидеть 'отрезаную' стандартом неточность дроби const sum = 0.1 + 0.2; console.log(sum); //0.30000000000000004 //христоматийный пример неточности вычислений с плавающей запятой console.log(sum.toFixed(1));//0.3 //а так легко его можно исправить, если нам важен только один знак после запятой

Способы записи чисел в JavaScript

В JavaScript существует несколько способов записать число с большим количеством знаков так, что бы его было удобно прочесть. Так знак нижнего подчеркивания ( _ ) внутри записи числа не повлияет на его значение, но упростит прочтение, а для очень больших или очень маленьких чисел, с большим количеством знаков знаков после запятой, можно добавить букву “e” и указать после нее количество нулей (положительное для записи целого числа и отрицательное для дроби). Так миллиард можно записать как 1e9, а одну миллиардную долю как 1e-9. Важно помнить что запись через “e” не доступна в BigInt и не защищает от неточности вычислений.

console.log(1_000_000); //1000000 console.log(1_000_000n); //1000000n console.log(1e23n);//SyntaxError: Invalid or unexpected token console.log(0.00000000000000000000001);//1e-23 const myNum = 1e23; const myBigInt = 99999999999999991611392n; console.log(myBigInt == myNum); //true

Довольно часто встречаются записи значений в виде строки с единицей измерения, например 100px или 20$. Что бы извлечь из такой записи числовое значение можно воспользоваться функциями parseInt() для целых чисел или parseFloat() для дробей. Однако стоит помнить, что обе эти функции “ищут” числовые значения с начала строки и вернут NaN при парсинге строки типа “у Саши было 2 яблока”, проигнорировав цифру 2. Для поиска по подобным строкам лучше использовать регулярные выражения.

console.log(parseInt("100px")); //100 console.log(parseFloat("192.168.0.1")); //192.168 //поиск останавливается после первого нечислового знака console.log(parseInt("I am 23 years old")); //NaN console.log("I am 23 years old".match(/-?\d+(\.\d+)?/g)); //[ '23' ]

Заключение

JavaScript, как и большинство языков программирования, имеет неточности при работе с числами поэтому понимание причин таких неточностей и знание способов обхода ограничений при работе с числовыми типами данных крайне важно для профессионального роста разработчика. Надеюсь что данная статья была полезна для понимания столь важной темы.

BigInt — новый тип данных в JS

На днях, я обновил chrome до 67-й версии, и оказалось в нем теперь есть поддержка примитивного типа — BigInt. Технология находится в третьей стадии / черновик. Давайте вместе посмотрим что это такое и где это может пригодиться.

Проблема

До текущего момента, все числа, и целые и дробные были представлены одним типом Number, так же имеющим название “double-precision floats”. Если не вникать в подробности, то это означает, что этот тип имеет ограниченную точность. Константа Number.MAX_SAFE_INTEGER хранит максимально возможное целое число, которое можно безопасно увеличивать. Его значение равно двум в пятдесят третьей степени, минус один (2**53–1).

Попробуем сложить максимальное число и единицу. Результат верный — число больше на единицу.

Но при сложении с двойкой, JS выдает ошибочный результат, в нашем случае такой же как и предыдущий.

Проблема, думаю, видна. Все расчеты, вне диапазона от Number.MIN_SAFE_INTEGER до Number.MAX_SAFE_INTEGER, могут быть неточными.

BigInt

BigInt — новый числовой примитив, который позволяет использовать большие числа с высокой точностью.

Чтобы создать BigInt, добавьте суффикс n в любой целочисленный литерал. Например, 123 становится 123n. Глобальную функцию BigInt можно использовать для преобразования обычного числа в BigInt. Другими словами, BigInt (123) === 123n. Теперь решим нашу проблему используя BigInt.

Вот еще один пример, где мы умножаем два числа с типом Number:

Мы знаем, что результат умножения должен заканчиваться на 7 (так как последние цыфры в числах 9 и 3, 9 * 3 === 27 ). Однако результат заканчивается набором нулей. Повторим то жесамое с BigInts:

И снова, с BigInt, ответ верный.

Безопасные пределы (Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER) не применяются к BigInts. Мы можем спокойно выполнять целочисленную арифметику , не беспокоясь о потере точности.

Новый примитив

BigInt — новый примитив в языке JavaScript. Тип BigInt может быть определен с помощью оператора typeof:

BigInt — это отдельный тип, и по этому при строгом сравнении (===) с Number мы увидим false. Прежде чем выполнять строгое сравнение (без приведения типов) BigInt с Number, нужно преобразовать один из них в тип другого.

При принуждении к логическому (что происходит при использовании if, &&, || или Boolean (int), например), BigInts следуют той же логике, что и Numbers.

Если необходимо привести BigInt к логическому типу (что происходит при использовании if, &&, ||, Boolean(int) ), то новый тип ведет себя подобно типу Number:

asm.js

Прежде чем мы пойдем дальше нужно немного затронуть asm.js (хоть и сам столкнулся впервые), ведь новый тип чисел тесно связан с этой реализацией языка.

asm.js это оптимизированное низкоуровневое подмножество JavaScript. И если попытаться еще проще — это некий низкоуровневый синтаксис, с доступом к памяти, подобный c или c++, в основном предназначенный для работы с арифметикой. После компиляции мы получаем очень оптимизированный js код.

Разработчики новых реализаций JS заимствуют решения из asm.js и пытаются поддерживать совместимость. Asm.js это огромная тема и довольно сложная, но может когда то и осилю и ее.

Операторы

BigInt поддерживает наиболее распространенные операторы. Двоичные +, -, * и ** работают как и ожидается. / и % работают и округляют до нуля по мере необходимости. Побитовые операции |, &, > и ^ выполняют поразрядную арифметику, при условии представления two’s complement representation для отрицательных значений, как и для Number.

Унарный минус (-) может использоваться для обозначения отрицательного значения BigInt, например -42n. Унарный плюс (+)не поддерживается, потому что он нарушит код asm.js , который ожидает, что конструкция вида +x всегда будет возвращать либо Number, либо выбрасывать исключение.

Так же, нельзя смешивать операции между BigInts и Numbers. Это хорошо, потому что любое неявное преобразование может потерять часть информации. Рассмотрим пример:

Что увидим в результате? Здесь нет и не может быть правильного ответа. Если предположить, что движок попытается привести типы, то все равно, BigInt не может содержать дробные числа, а Number не может отобразить точное число выше безопасного. Поэтому такие операции приведут к выбросу исключения TypeError.

Есть только одно исключение — это операторы сравнения, такие как ===, и >=, так как они возвращают одно из двух логических значений, и не рискуют точностью.

Доступно несколько новых API методов BigInt.

Конструктор BigInt похож на конструктор Number: он преобразует свой аргумент в тип BigInt. Если преобразование невозможно, будет выброшено исключение SyntaxError или RangeError.

Функции утилиты

BigInt.parseInt(string, radix?) — Работает аналогично Number.parseInt (), но выдает SyntaxError вместо возврата NaN в случае невозможности вычислить значение.

Так же есть возможность ограничивать число по битам, BigInt.asUint и NBigInt.asInt. Их я описывать не буду, это связано с побитовыми операциями. Если интересно — вот спека.

Отзывы

Уже есть замечания по производительности. В любом случае — BigInt еще черновик.

Вывод

Я думаю этот тип данных будет довольно редок в использовании. Очень редкий кейс, считать такие астрономические значения, но и удивляться не стоит встретив в коде значение, например, 120n — это просто BigInt.

Я надеюсь, вам понравился пост. Если да, похлопайте ��, чтобы помочь другим найти эту информацию. И не стесняйтесь оставлять комментарии — буду рад любым замечаниям!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *