BigInt: ограничения и поведение

Представление произвольной точности и фундаментальные ограничения

Тип BigInt предназначен для работы с целыми числами произвольной точности. В отличие от Number, который основан на IEEE-754 double precision и ограничен диапазоном безопасных целых чисел -(2^53 - 1) до 2^53 - 1, BigInt позволяет хранить значения, выходящие далеко за эти пределы.

Однако «произвольная точность» не означает отсутствие ограничений. Ограничения BigInt определяются не диапазоном значений, а ресурсами среды выполнения:

  • памятью процесса;
  • временем выполнения операций;
  • внутренними ограничениями реализации движка (V8, SpiderMonkey, JavaScriptCore).

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

Синтаксические особенности и строгая типизация

BigInt создаётся двумя основными способами:

  • литералом с суффиксом n:

    const a = 123456789012345678901234567890n;
  • вызовом конструктора:

    const b = BigInt("123456789012345678901234567890");

Ключевое ограничение связано с типовой системой языка: BigInt не является подтипом Number. Между ними отсутствует автоматическое приведение.

Любая попытка смешивания типов в арифметике приводит к исключению:

10n + 5 // TypeError

Это поведение является осознанным решением языка, исключающим скрытые потери точности.

Арифметическое поведение BigInt

BigInt поддерживает базовые операции:

  • сложение
  • вычитание
  • умножение
  • целочисленное деление
  • остаток
  • возведение в степень
const a = 10n;
const b = 3n;

a + b; // 13n
a - b; // 7n
a * b; // 30n
a / b; // 3n (усечение дробной части)
a % b; // 1n
a ** b; // 1000n

Ключевое ограничение деления — отсутствие дробной части. Результат всегда округляется вниз по направлению к нулю. Это делает BigInt непригодным для вычислений, требующих вещественной точности.

Отрицательные значения также следуют правилам усечения:

-10n / 3n // -3n

Побитовые операции и внутреннее представление

BigInt поддерживает побитовые операции, но их поведение отличается от Number:

  • операции выполняются над бесконечной «логической» разрядной сеткой;
  • отсутствует фиксированная длина слова (32/64 бита);
  • знак учитывается в дополнительном коде произвольной длины.

Пример:

5n & 3n  // 1n
5n | 3n  // 7n
5n ^ 3n  // 6n
~5n      // -6n

Оператор сдвига работает с произвольной точностью:

1n << 100n

При этом отрицательные сдвиги не допускаются и приводят к ошибке.

Ограничения взаимодействия с Number

Одно из ключевых ограничений BigInt — отсутствие автоматического приведения между типами.

Нельзя:

  • складывать Number и BigInt;
  • сравнивать их без явного преобразования в арифметических операциях.

Допустимы только сравнения:

1n < 2      // true
1n == 1     // true (нестрогое сравнение)
1n === 1    // false

При этом нестрогое сравнение использует приведение типов, но оно не применяется в арифметике.

Для совместимости требуется явное преобразование:

BigInt(10) + BigInt(5)
Number(10n) + 5

Ограничение связано с риском потери точности при обратном приведении BigInt → Number.

BigInt и JSON-сериализация

BigInt не поддерживается форматом JSON.

JSON.stringify(10n)
// TypeError: Do not know how to serialize a BigInt

Это фундаментальное ограничение стандарта JSON, где допустимы только:

  • string
  • number
  • boolean
  • null
  • object
  • array

Для обхода требуется ручная трансформация:

JSON.stringify(obj, (_, value) =>
  typeof value === "bigint" ? value.toString() : value
);

Обратное восстановление требует дополнительного парсинга.

Операции сравнения и поведение в условиях

BigInt корректно участвует в сравнительных операциях:

10n > 5n   // true
10n <= 10n // true

При использовании в логических контекстах BigInt подчиняется стандартным правилам truthy/falsy. Единственное falsy значение — 0n:

if (0n) {
  // не выполняется
}

Приведение типов и явные преобразования

Основные функции преобразования:

  • BigInt(value) — приведение к BigInt
  • Number(value) — обратное преобразование (с риском переполнения)
  • String(value) — безопасное представление

Ограничение Number заключается в невозможности корректного хранения больших значений:

Number(2n ** 200n) // Infinity

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

BigInt и строгая экосистема SWC

В контексте трансформации кода SWC ведёт себя как высокопроизводительный компилятор, ориентированный на сохранение семантики ECMAScript.

SWC не транспилирует BigInt в Number автоматически. Это связано с несколькими факторами:

  • невозможность безопасной эмуляции произвольной точности;
  • различие поведения побитовых операций;
  • риск изменения результатов вычислений;
  • отсутствие универсального runtime для эмуляции.

В проектах с настройками трансформации SWC BigInt сохраняется как есть:

// вход
const x = 10n + 20n;

// выход после SWC (упрощённо)
const x = 10n + 20n;

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

Ограничения минификации и оптимизации

SWC как компилятор и минификатор должен учитывать BigInt как неделимую сущность. Это приводит к ряду ограничений:

  • невозможность свёртки выражений с BigInt в Number;
  • запрет агрессивного constant folding при смешанных типах;
  • осторожная обработка экспоненциальных выражений.

Пример, который не может быть упрощён без потери семантики:

const a = 2n ** 100n;
const b = a + 1n;

Любая попытка преобразования в Number нарушает корректность вычислений.

BigInt в оптимизированных рантаймах

В движках уровня V8 BigInt представлен как специализированная структура произвольной длины, обычно реализованная через массив 30- или 64-битных «лимбов».

Ограничения производительности:

  • сложение: O(n)
  • умножение: от O(n²) до O(n log n)
  • деление: зависит от алгоритма (long division или Burnikel–Ziegler)

На практике это означает, что операции над числами с тысячами бит становятся существенно дороже стандартных Number операций.

Побочные эффекты и ловушки использования

Ключевые проблемные зоны:

  • смешение типов в выражениях;
  • неявные преобразования через API;
  • сериализация/десериализация;
  • использование в структурах данных, ожидающих Number;
  • производительность в горячих циклах.

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

Совместимость с API и браузерной экосистемой

Многие веб-API исторически ориентированы на Number:

  • Canvas API координаты;
  • WebGL uniform значения;
  • DOM размеры и вычисления;
  • таймеры и timestamp.

BigInt требует явного приведения, иначе API либо отклоняет значение, либо приводит к неявному преобразованию с потерей точности.