Skip to main content

JavaScript BigInt

In this lesson, we'll explore JavaScript's BigInt - a built-in object introduced in ES2020 (ES11) that allows you to work with integers of arbitrary precision. Before BigInt, JavaScript could only safely represent numbers between -(2^53 - 1) and (2^53 - 1). But now, we can work with much larger numbers!

Introduction to BigInt

JavaScript traditionally has a single numeric type called Number which can represent integers and floating-point values. However, the Number type has limitations when dealing with very large integers.

Let's look at the maximum safe integer in JavaScript:

console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991

This number (9007199254740991 or 2^53 - 1) represents the largest integer JavaScript can reliably represent with the Number primitive. Beyond this limit, precision becomes a problem.

For example:

console.log(9007199254740991); // 9007199254740991 (correct)
console.log(9007199254740991 + 1); // 9007199254740992 (correct)
console.log(9007199254740991 + 2); // 9007199254740992 (incorrect! should be 9007199254740993)

This is where BigInt comes to the rescue.

Creating BigInt Values

There are two ways to create a BigInt:

  1. Append the letter n to the end of an integer literal:
const bigInt = 9007199254740991n;
console.log(bigInt); // 9007199254740991n
  1. Call the BigInt() constructor:
const bigInt1 = BigInt(9007199254740991);
const bigInt2 = BigInt("9007199254740991");
console.log(bigInt1); // 9007199254740991n
console.log(bigInt2); // 9007199254740991n

Working with BigInt

Let's explore the basic operations and characteristics of BigInt:

Type Checking

BigInt is a separate primitive type:

const regularNum = 42;
const bigIntNum = 42n;

console.log(typeof regularNum); // "number"
console.log(typeof bigIntNum); // "bigint"

Arithmetic Operations

You can perform basic arithmetic operations with BigInt:

const a = 1234567890123456789n;
const b = 987654321987654321n;

console.log(a + b); // 2222222212111111110n
console.log(a - b); // 246913568135802468n
console.log(a * b); // 1219326312466898976304909138238409969n
console.log(a / b); // 1n (division truncates towards zero)
console.log(a % b); // 246913568135802468n
console.log(a ** 2n); // 1524157875323883675049535156256668161n

Comparison Operations

BigInt values can be compared using the usual comparison operators:

console.log(1n < 2n); // true
console.log(2n > 1n); // true
console.log(2n >= 2n); // true
console.log(2n <= 2n); // true
console.log(2n === 2n); // true

Mixing BigInt with Number

Mixing BigInt and regular Number in operations is not allowed and will throw a TypeError:

// This will throw a TypeError
try {
const result = 1n + 2;
console.log(result);
} catch (error) {
console.log(error.message); // "Cannot mix BigInt and other types"
}

You need to explicitly convert between types:

const bigIntValue = 5n;
const numberValue = 10;

// Convert Number to BigInt
console.log(bigIntValue + BigInt(numberValue)); // 15n

// Convert BigInt to Number (potential precision loss)
console.log(Number(bigIntValue) + numberValue); // 15

Equality Comparisons

When comparing BigInt with Number using loose equality (==), the comparison works as expected:

console.log(1n == 1); // true (loose equality)
console.log(1n === 1); // false (strict equality - different types)

Limitations

There are a few limitations when working with BigInt:

  1. No support for Math object methods:
// This will throw a TypeError
try {
console.log(Math.sqrt(4n));
} catch (error) {
console.log(error.message); // "Cannot convert a BigInt value to a number"
}
  1. Cannot mix with regular numbers in operations

  2. No decimal point operations - BigInt is for integers only:

// This will throw a RangeError
try {
console.log(5n / 2n); // Result is 2n, not 2.5n
console.log(BigInt(3.14)); // Error
} catch (error) {
console.log("Error: Cannot convert floating-point to BigInt");
}

Real-World Applications

Financial Calculations

BigInt is useful for precise financial calculations where large integers are needed:

// Calculate compound interest with large values
function calculateCompoundInterest(principal, ratePercent, years, compoundPerYear) {
const rate = BigInt(ratePercent);
const periods = BigInt(years) * BigInt(compoundPerYear);
const ratePerPeriod = rate * BigInt(10000) / BigInt(compoundPerYear) / BigInt(1000000);

// Calculate (1 + ratePerPeriod)^periods
// Using a simplified approach for demonstration
let base = BigInt(10000000) + ratePerPeriod;
let result = BigInt(10000000); // Represents 1.0 with 7 decimal precision

for (let i = 0; i < periods; i++) {
// Multiply and maintain precision
result = (result * base) / BigInt(10000000);
}

return (principal * result) / BigInt(10000000);
}

const principal = BigInt(10000000000); // $10 billion
const result = calculateCompoundInterest(principal, 5, 30, 12);
console.log(`After 30 years: $${result}`);

Cryptography

BigInt is essential for cryptographic operations that require large integers:

// Simple example of RSA-like calculation (not actual encryption)
function modPow(base, exponent, modulus) {
if (modulus === 1n) return 0n;

let result = 1n;
base = base % modulus;

while (exponent > 0n) {
if (exponent % 2n === 1n) {
result = (result * base) % modulus;
}
exponent = exponent / 2n;
base = (base * base) % modulus;
}

return result;
}

const message = 123456789n;
const publicKey = 65537n;
const modulus = 2349082340928409238409283409820948209480928409283409283409823098n;

const encrypted = modPow(message, publicKey, modulus);
console.log("Encrypted:", encrypted);

Managing Database IDs

When working with large database IDs that exceed JavaScript's safe integer limit:

// Twitter's snowflake-like ID generation
function generateId(timestamp, workerId, sequence) {
// Convert all inputs to BigInt if they aren't already
const timestampBits = BigInt(timestamp);
const workerIdBits = BigInt(workerId);
const sequenceBits = BigInt(sequence);

// Bit shifting operations (using BigInt)
return (timestampBits << 22n) |
(workerIdBits << 12n) |
sequenceBits;
}

const id = generateId(Date.now(), 5, 12);
console.log("Generated ID:", id.toString());

Performance Considerations

BigInt operations are generally slower than regular Number operations, so use them only when necessary:

// Performance comparison example
function measureTime(fn, name) {
const start = performance.now();
fn();
const end = performance.now();
console.log(`${name} took ${end - start} ms`);
}

// Regular number calculation
measureTime(() => {
let result = 1;
for (let i = 0; i < 1000000; i++) {
result = (result * 123) % 10007;
}
}, "Regular Number");

// BigInt calculation
measureTime(() => {
let result = 1n;
for (let i = 0; i < 1000000; i++) {
result = (result * 123n) % 10007n;
}
}, "BigInt");

Browser and Environment Support

BigInt is supported in all modern browsers and Node.js environments but may not be available in older browsers. Always check compatibility before using it in production.

// Feature detection
function supportsBigInt() {
return typeof BigInt === 'function';
}

if (supportsBigInt()) {
console.log("BigInt is supported!");
const reallyBigNumber = 9007199254740991n * 9007199254740991n;
console.log(reallyBigNumber);
} else {
console.log("BigInt is not supported in this environment");
}

Summary

JavaScript's BigInt provides a way to represent integers of arbitrary precision, which is crucial for situations where you need to work with numbers larger than Number.MAX_SAFE_INTEGER. Key points to remember:

  • Create BigInt values by appending n to integer literals or using the BigInt() constructor
  • BigInt is a distinct primitive type with its own operators and restrictions
  • You cannot mix BigInt and Number in operations without explicit conversion
  • BigInt can't represent fractions or decimals
  • Use it for financial calculations, cryptography, and other applications requiring precise integer arithmetic with large numbers
  • Be aware of performance implications when using BigInt for intensive calculations

Additional Resources

Exercises

  1. Calculate 2 raised to the power of 100 using BigInt and compare it with the result using regular Number.
  2. Write a function to determine if a BigInt is prime.
  3. Implement a factorial function that handles very large numbers using BigInt.
  4. Convert between binary, hexadecimal, and decimal representations using BigInt.
  5. Create a function to compute Fibonacci numbers with large indices using BigInt.

Happy coding with JavaScript's BigInt!



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)