JS
() =>
JavaScript · Typen · Arithmetik · Kryptographie
BigInt in JavaScript
Wenn Number nicht groß genug ist

JavaScript-Numbers sind 64-Bit-Floats – und verlieren bei Ganzzahlen über 9 Billiarden (2^53) lautlos Präzision. BigInt löst das Problem: beliebig große Ganzzahlen ohne Rundungsfehler, für IDs, Kryptographie, Timestamps und Finanzberechnungen.

10 Min. Lesezeit BigInt · Number.MAX_SAFE_INTEGER · JSON · Kryptographie ES2020 · Alle modernen Browser · Node.js 10.3+

1. Das Problem: Number verliert Präzision

JavaScript hat nur einen numerischen Typ für Zahlen: Number. Er entspricht dem IEEE 754 Double-Precision-Format mit 64 Bit – davon 52 Bit für die Mantisse. Das bedeutet: Ganzzahlen können exakt dargestellt werden, solange sie kleiner als 2^53 (9.007.199.254.740.992) sind. Diese Grenze ist als Number.MAX_SAFE_INTEGER in der Sprache verankert. Jenseits dieser Grenze beginnt Rundung: Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 ergibt true, weil beide Werte zum nächsten darstellbaren Float gerundet werden.

In der Praxis tritt dieses Problem bei Datenbank-IDs aus Twitter, Snowflake oder anderen verteilten Systemen auf – diese IDs sind häufig 64-Bit-Ganzzahlen und überschreiten Number.MAX_SAFE_INTEGER. Eine Twitter-ID wie 1591874983876853760 wird in JavaScript als Number gerundet und kann die falsche Ressource adressieren. Auch Timestamps in Nanosekunden, Kryptographie-Schlüssel, Blockchain-Werte und bestimmte Hash-Werte überschreiten die sichere Grenze. BigInt wurde in ES2020 als Antwort auf genau dieses Problem eingeführt.

2. Was ist BigInt und wie erstellt man ihn?

BigInt ist ein primitiver Typ in JavaScript, eingeführt in ES2020, der beliebig große Ganzzahlen mit exakter Präzision darstellt – begrenzt nur durch den verfügbaren Arbeitsspeicher. Es gibt zwei Wege, einen BigInt zu erstellen: durch das Literal-Suffix n oder durch die Funktion BigInt(). Das Literal 9007199254740993n ist ein BigInt, während 9007199254740993 ein Number ist, der gerundet wird. BigInt("9007199254740993") konvertiert einen String zu einem BigInt – das ist der sichere Weg, wenn die Zahl aus einer API kommt.

BigInt ist ein eigener primitiver Typ, erkennbar an typeof 1n === "bigint". Er verhält sich wie eine Ganzzahl – es gibt keine Dezimalstellen, kein Infinity, kein NaN. Division bei BigInt ist ganzzahlige Division: 5n / 2n === 2n (Rest wird abgeschnitten). Negative BigInts funktionieren wie erwartet: -5n / 2n === -2n. Es gibt BigInt.asIntN(width, value) und BigInt.asUintN(width, value), die den BigInt auf eine feste Bitbreite beschneiden – nützlich für die Simulation von 32-Bit- oder 64-Bit-Ganzzahlen.


// BigInt creation: literal suffix 'n' or BigInt() constructor
const fromLiteral = 9007199254740993n; // exact — no rounding
const fromNumber = BigInt(9007199254740992); // safe conversion from Number
const fromString = BigInt("9007199254740993456789"); // from API response

// typeof distinguishes BigInt from Number
console.log(typeof 42n);  // "bigint"
console.log(typeof 42);   // "number"

// Demonstrate the Number precision problem
console.log(9007199254740993 === 9007199254740994); // true — Number is wrong!
console.log(9007199254740993n === 9007199254740994n); // false — BigInt is correct

// BigInt division is integer division (truncates fractional part)
console.log(17n / 5n); // 3n — not 3.4
console.log(-17n / 5n); // -3n — truncates toward zero

// Clamping to fixed bit width (useful for simulation)
const u32max = BigInt.asUintN(32, 0xFFFFFFFFn + 1n);
console.log(u32max); // 0n — wraps around like uint32 overflow

3. Arithmetische Operatoren mit BigInt

Alle arithmetischen Grundoperatoren funktionieren mit BigInt: Addition (+), Subtraktion (-), Multiplikation (*), ganzzahlige Division (/), Modulo (%) und Potenzierung (**). Die Vergleichsoperatoren (<, >, ===, !==) funktionieren ebenfalls. Wichtig: Der einstellige +-Operator (unary plus) funktioniert mit BigInt nicht – das ist eine bewusste Designentscheidung, die versehentliche Konvertierungen zu Number verhindert.

Bitweise Operatoren (&, |, ^, ~, <<, >>) funktionieren alle mit BigInt. Der unsigned right shift (>>>) existiert für BigInt nicht, da BigInt kein festes Bitformat hat und der Begriff "unsigned" sinnlos wäre. Logische Operatoren (&&, ||) und der ternäre Operator funktionieren mit BigInt. 0n ist falsy, alle anderen BigInts sind truthy – konsistent mit den anderen JavaScript-Typen. Loser Vergleich mit == funktioniert zwischen BigInt und Number, strikter Vergleich mit === nicht, da die Typen verschieden sind.

4. Typenkonvertierung: BigInt und Number mischen

Das größte Stolperstein bei BigInt ist, dass JavaScript keine implizite Konvertierung zwischen BigInt und Number erlaubt. 1n + 1 wirft einen TypeError: Cannot mix BigInt and other types. Das ist eine bewusste Designentscheidung: Implizite Konvertierungen würden leise Präzisionsverluste verursachen und den Zweck von BigInt untergraben. Explizite Konvertierung ist immer erforderlich: Number(1n) oder BigInt(1).

Die Konvertierung von BigInt zu Number verliert Präzision, wenn der Wert Number.MAX_SAFE_INTEGER überschreitet – das ist der gleiche Fehler, den man zu vermeiden versucht. Daher sollte man immer prüfen, ob die Konvertierung sicher ist. BigInt(x) von einem Number funktioniert nur für ganzzahlige Werte: BigInt(1.5) wirft einen RangeError. Für den Vergleich mit Number kann man losen Vergleich verwenden: 1n == 1 ist true, weil JavaScript für == eine Konvertierungsregel hat, die BigInt und Number vergleichbar macht.


// Explicit conversion required — no implicit mixing
const big = 9007199254740993n;

// Safe: check before converting BigInt → Number
function bigIntToNumber(n) {
  if (n > BigInt(Number.MAX_SAFE_INTEGER) || n < BigInt(Number.MIN_SAFE_INTEGER)) {
    throw new RangeError(`BigInt ${n} exceeds safe integer range`);
  }
  return Number(n);
}

// Safe conversion from API string to BigInt
function parseId(idString) {
  const parsed = BigInt(idString);
  return parsed;
}

// Loose vs strict equality
console.log(1n == 1);   // true — loose equality allows type coercion
console.log(1n === 1);  // false — strict equality checks type
console.log(1n < 2);    // true — comparison operators work across types

// Formatting large BigInt values
const trillion = 1_000_000_000_000n; // numeric separators work with BigInt
console.log(trillion.toString());    // "1000000000000"
console.log(trillion.toString(16));  // "e8d4a51000" — hex representation
console.log(trillion.toString(2));   // binary representation

5. BigInt und JSON: Serialisierungsprobleme lösen

BigInt kann nicht direkt mit JSON.stringify() serialisiert werden – es wirft einen TypeError: Do not know how to serialize a BigInt. Das ist eine bewusste Entscheidung, da JSON keinen nativen BigInt-Typ hat und eine stille Konvertierung zu Number wieder Präzision kosten würde. Die Lösung ist ein benutzerdefinierter Replacer in JSON.stringify() und ein benutzerdefinierter Reviver in JSON.parse().

Ein weit verbreitetes Muster: BigInt-Werte werden im JSON als Strings übertragen (mit einem Suffix wie "n" oder in einem Wrapper-Objekt). Beim Parsen werden diese Strings erkannt und zurück zu BigInt konvertiert. Alternativ gibt es die Bibliothek json-bigint, die das korrekte Parsen von großen Zahlen in JSON übernimmt – besonders nützlich wenn eine externe API große IDs als Zahlen (nicht als Strings) in JSON überträgt, was per JSON-Spezifikation erlaubt ist, in JavaScript aber Präzision kostet.

6. Bitoperationen mit BigInt

Einer der überraschenden Anwendungsfälle von BigInt sind Bitoperationen auf Werten, die 32 Bit überschreiten. JavaScript-Numbers führen bitweise Operationen auf 32-Bit-Ganzzahlen durch – Werte werden intern zu einem 32-Bit-Integer konvertiert, die Operation wird durchgeführt, und das Ergebnis wird wieder zu Number konvertiert. Das bedeutet: bitweise Operationen auf großen Zahlen mit Number verlieren Information jenseits der 32-Bit-Grenze.

Mit BigInt arbeiten bitweise Operationen auf beliebig breiten Werten, begrenzt nur durch den Speicher. Das ist relevant für Flags und Bitmasks, die mehr als 32 Bit benötigen, für 64-Bit-Flags aus systemnahen APIs, für Implementierungen von Hash-Funktionen, die mit 64-Bit-Werten arbeiten, und für Protokoll-Implementierungen, die mit großen Bitfeldern operieren. BigInt.asUintN(64, value) simuliert dabei eine 64-Bit-Ganzzahl-Arithmetik mit definiertem Overflow-Verhalten.


// Bitwise operations on large values — BigInt handles >32 bits correctly
const flags64 = 0b1000000000000000000000000000000000000000000000000000000000000001n;

// Set, check, clear bits
const BIT_ADMIN   = 1n << 0n;
const BIT_WRITE   = 1n << 1n;
const BIT_EXECUTE = 1n << 63n; // 64th bit — impossible with Number

let permissions = 0n;
permissions |= BIT_ADMIN;   // set admin flag
permissions |= BIT_EXECUTE; // set execute flag

const isAdmin   = (permissions & BIT_ADMIN)   !== 0n; // true
const isExecute = (permissions & BIT_EXECUTE) !== 0n; // true
const isWrite   = (permissions & BIT_WRITE)   !== 0n; // false

// Simulate 64-bit unsigned arithmetic with defined overflow
function uint64Add(a, b) {
  return BigInt.asUintN(64, a + b);
}

console.log(uint64Add(0xFFFFFFFFFFFFFFFFn, 1n)); // 0n — wraps to 0 like uint64

// FNV-1a hash (64-bit variant) implemented in BigInt
function fnv1a64(str) {
  const PRIME  = 1099511628211n;
  const OFFSET = 14695981039346656037n;
  let hash = OFFSET;
  for (const char of str) {
    hash ^= BigInt(char.charCodeAt(0));
    hash = BigInt.asUintN(64, hash * PRIME);
  }
  return hash;
}

7. BigInt in der Kryptographie

Kryptographische Algorithmen wie RSA, Diffie-Hellman und elliptische Kurven arbeiten mit sehr großen Ganzzahlen – typischerweise 2048 bis 4096 Bit groß. Bevor BigInt in JavaScript verfügbar war, mussten Kryptobibliotheken eigene BigInteger-Implementierungen mitbringen (z.B. jsbn oder forge). Mit nativem BigInt sind diese Operationen direkt in JavaScript implementierbar, ohne externe Abhängigkeiten für die Grundarithmetik.

Für produktiven Einsatz in der Kryptographie sollte man jedoch die SubtleCrypto-API des Browsers bevorzugen, die native, seitenkanalresistente Implementierungen bietet. BigInt eignet sich für das Verstehen und Prototypen kryptographischer Algorithmen sowie für Anwendungsfälle, wo SubtleCrypto nicht ausreicht – etwa die Implementierung von Shamir's Secret Sharing, Pedersen-Commitments oder bestimmte Protokolle, die spezifische Primzahloperationen erfordern. Modular-Exponentiation – der Kern von RSA – ist mit BigInt und dem **-Operator und % direkt implementierbar.

8. Performance: BigInt vs. Number

BigInt-Arithmetik ist langsamer als Number-Arithmetik – das ist unvermeidbar, weil Number direkt auf IEEE 754 Hardware-Operationen abbildet, während BigInt beliebige Größen verwalten und Software-Multipräzisions-Arithmetik implementieren muss. In V8-Benchmarks (Chrome/Node.js) ist eine einfache BigInt-Addition etwa 5–50x langsamer als die gleiche Number-Operation, abhängig von der Größe der Operanden und ob der JIT-Compiler den Code optimieren konnte.

Das bedeutet: BigInt ist nicht für Anwendungen gedacht, die intensive numerische Berechnungen mit vielen Iterationen durchführen. Für Physik-Simulationen, Spiele-Engines und Signalverarbeitung bleibt Number (oder TypedArray) die richtige Wahl. BigInt ist für Präzision, nicht für Geschwindigkeit. In Szenarien, wo man korrekte Ergebnisse für große Ganzzahlen braucht und die Anzahl der Operationen überschaubar ist – ID-Verarbeitung, Protokoll-Implementierung, gelegentliche Hash-Berechnungen – ist der Performanceunterschied irrelevant.

9. BigInt vs. Number: Vergleich der Grenzen

Die Wahl zwischen BigInt und Number ist keine persönliche Präferenz, sondern eine sachliche Entscheidung basierend auf den Anforderungen. Wenn die zu verarbeitenden Ganzzahlen garantiert unter 2^53 bleiben, ist Number korrekt und deutlich performanter. Wenn nicht – oder wenn man nicht sicher sein kann – ist BigInt die sichere Wahl.

Eigenschaft Number BigInt Empfehlung
Maximale sichere Ganzzahl 2^53 − 1 Unbegrenzt BigInt für IDs >2^53
Dezimalstellen Ja (Float) Nein (nur Ganzzahl) Number für Fließkomma
JSON-Serialisierung Direkt Manuell (Replacer) BigInt als String übertragen
Performance Sehr schnell (Hardware) 5–50x langsamer Number bei Massenoperationen
Bitoperationen >32 Bit Verlieren Bits Exakt BigInt für 64-Bit-Flags

BigInt und Number ergänzen sich: Number für Fließkomma-Mathematik, Performance-kritische Berechnungen und die überwältigende Mehrheit numerischer Operationen. BigInt für korrekte Darstellung großer Ganzzahlen, 64-Bit-Flags, Kryptographie-Prototypen und Szenarien, wo ein einziger Rundungsfehler fatale Konsequenzen hätte. Die beiden Typen können nicht gemischt werden – was anfangs frustrierend wirkt, aber explizite Konvertierungen erzwingt und so versehentliche Präzisionsverluste verhindert.

Mironsoft

JavaScript-Entwicklung, Datenintegrität und sichere ID-Verarbeitung

Präzisionsprobleme mit großen Zahlen in Ihrer Anwendung beheben?

Wir analysieren bestehende Systeme auf versteckte Präzisionsverluste bei ID-Verarbeitung, Timestamps und numerischen Berechnungen – und migrieren auf BigInt wo nötig.

Precision-Audit

Analyse auf versteckte Number-Präzisionsverluste bei IDs, Timestamps und Finanzdaten

BigInt-Migration

Schrittweise Migration von Number zu BigInt inkl. JSON-Serialisierung und API-Adapter

Code-Review

Review auf implizite BigInt/Number-Mischungen und fehlerhafte Konvertierungslogik

10. Zusammenfassung

BigInt ist die Antwort von JavaScript auf das seit ES1 bestehende Problem, dass Number keine beliebig großen Ganzzahlen exakt darstellen kann. Mit dem Suffix n oder der Funktion BigInt() erstellt man BigInt-Werte, die alle arithmetischen Operatoren und bitweisen Operatoren unterstützen. Implizite Konvertierungen zwischen BigInt und Number sind verboten – explizite Konvertierungen sind immer erforderlich. Für JSON-Serialisierung sind benutzerdefinierte Replacer und Reviver notwendig. Performance ist schlechter als Number, aber das ist der bewusste Kompromiss für exakte Präzision.

Die typischen Einsatzgebiete sind klar: BigInt für Twitter-/Snowflake-IDs und andere 64-Bit-IDs aus externen Systemen, für Timestamps in Nanosekunden, für 64-Bit-Flags und Bitmasks, für kryptographische Berechnungen und für alle Szenarien, wo Rundungsfehler bei großen Ganzzahlen inakzeptabel sind. Number bleibt die richtige Wahl für Fließkomma-Berechnungen, Performance-kritische Schleifen und die große Mehrheit aller numerischen Operationen in JavaScript-Anwendungen.

BigInt in JavaScript — Das Wichtigste auf einen Blick

Wann BigInt

Ganzzahlen über 2^53, 64-Bit-IDs aus externen Systemen, Kryptographie, 64-Bit-Flags. Nicht für Fließkomma oder Performance-kritische Massenoperationen.

Syntax

Literal: 9007199254740993n — Suffix n. Aus String: BigInt("123456789012345678"). Aus Number nur für ganzzahlige, sichere Werte.

Konvertierung

Keine implizite Mischung mit Number — TypeError. Explizit: Number(bigint) prüft Sicherheitsgrenze. BigInt(number) nur für ganzzahlige Numbers.

JSON

JSON.stringify wirft TypeError für BigInt. Lösung: Replacer der BigInt als String serialisiert, Reviver der zurückkonvertiert.

11. FAQ: BigInt in JavaScript

1Was ist BigInt in JavaScript?
Primitiver Typ für beliebig große Ganzzahlen ohne Präzisionsverlust. Number kann nur bis 2^53 exakt darstellen. BigInt ist nur durch RAM begrenzt. Eingeführt in ES2020.
2Warum verliert Number Präzision?
IEEE 754 Double Precision hat 52 Bit Mantisse. Ganzzahlen über 2^53 werden gerundet. Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 ist true.
3Wie erstellt man BigInt?
Literal: 9007199254740993n (n-Suffix). Aus String: BigInt("123456789012345678"). Aus Number nur für ganzzahlige Werte die sicher unter MAX_SAFE_INTEGER liegen.
4BigInt und Number mischen?
Nicht implizit — TypeError. Explizit: Number(bigint) oder BigInt(number). Loser Vergleich == funktioniert, strikter === nicht.
5BigInt in JSON serialisieren?
JSON.stringify wirft TypeError. Replacer verwenden: (key, val) => typeof val === 'bigint' ? val.toString() : val. Beim Parsen Reviver mit BigInt(string).
6Performance von BigInt?
5–50x langsamer als Number. BigInt nutzt Software-Arithmetik, Number mapped auf CPU-Hardware. Für Massenoperationen Number bevorzugen.
7Bitoperatoren mit BigInt?
&, |, ^, ~, <<, >> funktionieren auf beliebig breiten Werten. Kein >>>. BigInt.asUintN(64, value) simuliert 64-Bit-Overflow.
8Wann BigInt für IDs verwenden?
Immer bei 64-Bit-IDs aus Twitter, Snowflake oder anderen verteilten Systemen. Diese überschreiten MAX_SAFE_INTEGER und werden als Number gerundet.
9BigInt in Node.js?
Seit Node.js 10.4 stabil. fs.stat() gibt Timestamps als BigInt zurück wenn bigint: true gesetzt. Alle LTS-Versionen ab Node.js 12 vollständig unterstützt.
10BigInt für Kryptographie?
Für Prototypen ja. Für Produktion immer SubtleCrypto nutzen — native, seitenkanalresistente Implementierungen. BigInt ist kein Krypto-Library-Ersatz.