Повний посібник з типу BigInt у JavaScript, що розкриває його можливості та застосування. Навчіться обробляти великі цілі числа та виконувати точні обчислення.
JavaScript BigInt: Освоєння арифметики великих цілих чисел
JavaScript, хоч і є універсальною мовою, має обмеження при роботі з дуже великими цілими числами. Стандартний тип `Number` може точно представляти цілі числа лише до певного ліміту, відомого як `Number.MAX_SAFE_INTEGER`. За межами цього ліміту обчислення стають неточними, що призводить до неочікуваних результатів. Саме тут на допомогу приходить BigInt
. Представлений в ECMAScript 2020, BigInt
— це вбудований об'єкт, який надає спосіб представлення та маніпулювання цілими числами довільного розміру, перевищуючи обмеження стандартного типу `Number`.
Розуміння потреби в BigInt
До появи BigInt
розробникам JavaScript доводилося покладатися на бібліотеки або власні реалізації для обробки обчислень з великими цілими числами. Ці рішення часто супроводжувалися зниженням продуктивності та підвищеною складністю. Впровадження BigInt
надало нативний та ефективний спосіб роботи з великими цілими числами, відкриваючи можливості для застосувань у різних сферах, зокрема:
- Криптографія: Безпечна обробка великих простих чисел є ключовою для криптографічних алгоритмів.
- Фінансові розрахунки: Точне представлення великих грошових сум без втрати точності.
- Наукові обчислення: Виконання складних розрахунків, що включають надзвичайно великі або малі числа.
- Високоточні часові мітки: Представлення часових міток з наносекундною точністю.
- Генерація ID: Створення унікальних і дуже великих ідентифікаторів.
Створення значень BigInt
Існує два основних способи створення значень BigInt
у JavaScript:
- Використання конструктора `BigInt()`: Цей конструктор може перетворити число, рядок або логічне значення на
BigInt
. - Використання суфікса `n`: Додавання `n` до цілочисельного літералу створює
BigInt
.
Приклади:
Використання конструктора `BigInt()`:
const bigIntFromNumber = BigInt(12345678901234567890);
const bigIntFromString = BigInt("98765432109876543210");
const bigIntFromBoolean = BigInt(true); // Результат: 1n
const bigIntFromFalseBoolean = BigInt(false); // Результат: 0n
console.log(bigIntFromNumber); // Вивід: 12345678901234567890n
console.log(bigIntFromString); // Вивід: 98765432109876543210n
console.log(bigIntFromBoolean); // Вивід: 1n
console.log(bigIntFromFalseBoolean); // Вивід: 0n
Використання суфікса `n`:
const bigIntLiteral = 12345678901234567890n;
console.log(bigIntLiteral); // Вивід: 12345678901234567890n
Важливе зауваження: Ви не можете безпосередньо змішувати значення BigInt
та Number
в арифметичних операціях. Вам потрібно явно перетворити їх до одного типу перед виконанням обчислень. Спроба змішати їх напряму призведе до `TypeError`.
Арифметичні операції з BigInt
BigInt
підтримує більшість стандартних арифметичних операторів, зокрема:
- Додавання (`+`)
- Віднімання (`-`)
- Множення (`*`)
- Ділення (`/`)
- Залишок від ділення (`%`)
- Піднесення до степеня (`**`)
Приклади:
const a = 12345678901234567890n;
const b = 98765432109876543210n;
const sum = a + b;
const difference = a - b;
const product = a * b;
const quotient = a / 2n; // Примітка: Ділення округлює в бік нуля
const remainder = a % 7n;
const power = a ** 3n; // Піднесення до степеня працює очікувано
console.log("Сума:", sum); // Вивід: Сума: 111111111011111111100n
console.log("Різниця:", difference); // Вивід: Різниця: -86419753208641975320n
console.log("Добуток:", product); // Вивід: Добуток: 1219326311370217957951669538098765432100n
console.log("Частка:", quotient); // Вивід: Частка: 6172839450617283945n
console.log("Залишок:", remainder); // Вивід: Залишок: 5n
console.log("Степінь:", power); // Вивід: Степінь: 187641281029182300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n
Важливі аспекти:
- Ділення: Ділення значень
BigInt
округлює в бік нуля. Це означає, що дробова частина результату відкидається. Якщо вам потрібне більш точне ділення, розгляньте можливість використання бібліотек, що підтримують арифметику довільної точності. - Унарний оператор плюс (+): Унарний оператор плюс (+) не можна використовувати зі значеннями
BigInt
, оскільки це конфліктувало б зі старим кодом asm.js. Використовуйте функцію перетворення `Number()` для конвертації BigInt у Number, якщо вам потрібне числове представлення (з розумінням, що ви можете втратити точність). - Побітові оператори:
BigInt
також підтримує побітові оператори, такі як `&`, `|`, `^`, `~`, `<<` та `>>`. Ці оператори працюють очікувано з бінарним представленням значеньBigInt
.
Оператори порівняння
Ви можете використовувати стандартні оператори порівняння (`==`, `!=`, `<`, `>`, `<=`, `>=`) для порівняння значень BigInt
з іншими значеннями BigInt
або навіть зі значеннями Number
. Однак будьте уважні щодо потенційного приведення типів.
Приклади:
const a = 10n;
const b = 20n;
const c = 10;
console.log(a == b); // Вивід: false
console.log(a != b); // Вивід: true
console.log(a < b); // Вивід: true
console.log(a > b); // Вивід: false
console.log(a <= b); // Вивід: true
console.log(a >= b); // Вивід: false
console.log(a == c); // Вивід: true (приведення типів)
console.log(a === c); // Вивід: false (без приведення типів)
Найкраща практика: Використовуйте сувору рівність (`===`) та сувору нерівність (`!==`), щоб уникнути неочікуваного приведення типів при порівнянні значень BigInt
та Number
.
Перетворення між BigInt та Number
Хоча прямі арифметичні операції між BigInt
та Number
заборонені, ви можете конвертувати значення між цими двома типами. Однак пам'ятайте про потенційну втрату точності при перетворенні BigInt
на Number
, якщо значення BigInt
перевищує `Number.MAX_SAFE_INTEGER`.
Приклади:
const bigIntValue = 9007199254740991n; // Number.MAX_SAFE_INTEGER
const numberValue = Number(bigIntValue); // Перетворення BigInt на Number
console.log(numberValue); // Вивід: 9007199254740991
const largerBigIntValue = 9007199254740992n; // Перевищує Number.MAX_SAFE_INTEGER
const largerNumberValue = Number(largerBigIntValue);
console.log(largerNumberValue); // Вивід: 9007199254740992 (може бути неточним)
const numberToBigInt = BigInt(12345); // Перетворення Number на BigInt
console.log(numberToBigInt); // Вивід: 12345n
Сценарії використання та приклади
Криптографія
Криптографічні алгоритми часто покладаються на дуже великі прості числа для забезпечення безпеки. BigInt
надає спосіб ефективно представляти ці числа та маніпулювати ними.
// Приклад: Генерація простої (небезпечної) пари ключів
function generateKeyPair() {
const p = 281n; // Просте число
const q = 283n; // Інше просте число
const n = p * q; // Модуль
const totient = (p - 1n) * (q - 1n); // Функція Ейлера
// Вибираємо e (відкриту експоненту) так, що 1 < e < totient і НСД(e, totient) = 1
const e = 17n;
// Обчислюємо d (секретну експоненту) так, що (d * e) % totient = 1
let d = 0n;
for (let i = 1n; i < totient; i++) {
if ((i * e) % totient === 1n) {
d = i;
break;
}
}
return {
publicKey: { n, e },
privateKey: { n, d },
};
}
const keyPair = generateKeyPair();
console.log("Відкритий ключ:", keyPair.publicKey);
console.log("Секретний ключ:", keyPair.privateKey);
Примітка: Це спрощений приклад лише для демонстраційних цілей. Реальна криптографія використовує набагато більші прості числа та складніші алгоритми.
Фінансові розрахунки
При роботі з великими сумами грошей, особливо в міжнародних транзакціях, точність є критично важливою. BigInt
може запобігти помилкам округлення та забезпечити точні обчислення.
// Приклад: Розрахунок складних відсотків
function calculateCompoundInterest(principal, rate, time) {
const principalBigInt = BigInt(principal * 100); // Переводимо в центи
const rateBigInt = BigInt(rate * 10000); // Переводимо в десятитисячні відсотка
const timeBigInt = BigInt(time);
let amount = principalBigInt;
for (let i = 0n; i < timeBigInt; i++) {
amount = amount * (10000n + rateBigInt) / 10000n;
}
const amountInDollars = Number(amount) / 100;
return amountInDollars;
}
const principal = 1000000; // $1,000,000
const rate = 0.05; // 5% відсоткова ставка
const time = 10; // 10 років
const finalAmount = calculateCompoundInterest(principal, rate, time);
console.log("Кінцева сума:", finalAmount); // Вивід: Кінцева сума: 1628894.6267774413 (приблизно)
У цьому прикладі ми перетворюємо основну суму та ставку на значення BigInt
, щоб уникнути помилок округлення під час обчислення. Потім результат конвертується назад у Number
для відображення.
Робота з великими ID
У розподілених системах генерація унікальних ID на кількох серверах може бути складною. Використання BigInt
дозволяє створювати дуже великі ID, ймовірність колізії яких є низькою.
// Приклад: Генерація унікального ID на основі часової мітки та ID сервера
function generateUniqueId(serverId) {
const timestamp = BigInt(Date.now());
const serverIdBigInt = BigInt(serverId);
const random = BigInt(Math.floor(Math.random() * 1000)); // Додаємо трохи випадковості
// Комбінуємо значення для створення унікального ID
const uniqueId = (timestamp << 20n) + (serverIdBigInt << 10n) + random;
return uniqueId.toString(); // Повертаємо у вигляді рядка для зручності обробки
}
const serverId = 123; // Приклад ID сервера
const id1 = generateUniqueId(serverId);
const id2 = generateUniqueId(serverId);
console.log("Унікальний ID 1:", id1);
console.log("Унікальний ID 2:", id2);
BigInt та JSON
Значення BigInt
не підтримуються в JSON нативно. Спроба серіалізувати об'єкт JavaScript, що містить BigInt
, за допомогою `JSON.stringify()` призведе до `TypeError`. Для обробки значень BigInt
при роботі з JSON у вас є кілька варіантів:
- Перетворення на рядок: Перетворіть
BigInt
на рядок перед серіалізацією. Це найпоширеніший і найпростіший підхід. - Власна серіалізація/десеріалізація: Використовуйте власну функцію серіалізації/десеріалізації для обробки значень
BigInt
.
Приклади:
Перетворення на рядок:
const data = {
id: 12345678901234567890n,
name: "Example Data",
};
// Перетворюємо BigInt на рядок перед серіалізацією
data.id = data.id.toString();
const jsonData = JSON.stringify(data);
console.log(jsonData); // Вивід: {"id":"12345678901234567890","name":"Example Data"}
// При десеріалізації вам потрібно буде перетворити рядок назад на BigInt
const parsedData = JSON.parse(jsonData, (key, value) => {
if (key === "id") {
return BigInt(value);
}
return value;
});
console.log(parsedData.id); // Вивід: 12345678901234567890n
Власна серіалізація/десеріалізація (з використанням `replacer` та `reviver`):
const data = {
id: 12345678901234567890n,
name: "Example Data",
};
// Власна серіалізація
const jsonData = JSON.stringify(data, (key, value) => {
if (typeof value === 'bigint') {
return value.toString();
} else {
return value;
}
});
console.log(jsonData);
// Власна десеріалізація
const parsedData = JSON.parse(jsonData, (key, value) => {
if (typeof value === 'string' && /^[0-9]+$/.test(value)) { // перевіряємо, чи це рядок, що складається з цифр
try {
return BigInt(value);
} catch(e) {
return value;
}
}
return value;
});
console.log(parsedData.id);
Сумісність з браузерами
BigInt
широко підтримується в сучасних браузерах. Однак важливо перевіряти сумісність для старих браузерів або середовищ. Ви можете використовувати інструмент, такий як Can I use, для перевірки підтримки браузерами. Якщо вам потрібно підтримувати старі браузери, ви можете розглянути використання поліфіла, але пам'ятайте, що поліфіли можуть впливати на продуктивність.
Аспекти продуктивності
Хоча BigInt
надає потужний інструмент для роботи з великими цілими числами, важливо пам'ятати про можливі наслідки для продуктивності.
- Операції з
BigInt
можуть бути повільнішими за стандартні операції зNumber
. - Перетворення між
BigInt
таNumber
також може створювати додаткові накладні витрати.
Тому використовуйте BigInt
лише за необхідності та оптимізуйте свій код для підвищення продуктивності, якщо ви виконуєте велику кількість операцій з BigInt
.
Висновок
BigInt
— це цінне доповнення до JavaScript, що дозволяє розробникам обробляти арифметику великих цілих чисел з високою точністю. Розуміючи його можливості, обмеження та сценарії використання, ви можете застосовувати BigInt
для створення надійних і точних додатків у різних сферах, включаючи криптографію, фінансові розрахунки та наукові обчислення. Не забувайте враховувати сумісність з браузерами та аспекти продуктивності при використанні BigInt
у своїх проектах.
Подальше вивчення
- Mozilla Developer Network (MDN) - BigInt
- Блог V8 - BigInt: Цілі числа довільної точності в JavaScript
Цей посібник надає всебічний огляд BigInt
у JavaScript. Досліджуйте пов'язані ресурси для отримання більш детальної інформації та вивчення передових технік.