BigInt – Arbeiten mit großen Zahlen
In der Welt der Programmierung sind Zahlen ein grundlegendes Element. In JavaScript gibt es seit langem den Datentyp Number
, der jedoch aufgrund seiner Implementierung als 64-Bit-Gleitkommazahl (nach dem IEEE 754 Standard) Grenzen hat. Insbesondere können ganzzahlige Werte nur bis zu einer bestimmten Größe exakt dargestellt werden. Mit der Einführung von BigInt in ES2020 hat JavaScript nun die Möglichkeit, mit ganzen Zahlen beliebiger Größe sicher zu arbeiten.
Warum BigInt?
Der Datentyp Number
kann nur ganze Zahlen zwischen -(2^53 - 1)
und 2^53 - 1
(das entspricht etwa ±9.007.199.254.740.991) exakt darstellen. Werte außerhalb dieses Bereichs können zu Präzisionsverlusten führen.
Beispiel:
const maxSafeInteger = Number.MAX_SAFE_INTEGER;
console.log(maxSafeInteger); // 9007199254740991
console.log(maxSafeInteger + 1); // 9007199254740992
console.log(maxSafeInteger + 2); // 9007199254740992 // Erwartet: 9007199254740993
Wie man sieht, führt die Addition von 1 und 2 zum gleichen Ergebnis, was zu unerwartetem Verhalten führen kann.
Numeric Separators
Um die Lesbarkeit des Artikels zu verbessern, möchte ich hier off toppic noch das Thema der “Numeric Separators” einstreuen. In ES12 wurden sie in JavaScript eingeführt und erhöhen die Lesbarkeit von numerischen Werten enorm. Hier werden, wie wir das von den Trennpunkten (.) gewöhnt sind, an den entsprechenden Stellen in einer Zahl ein Unterstrich (_) eingesetzt. Der Browser ignoriert diese Unterstriche jedoch. Sie erhöhen lediglich die Lesbarkeit für uns.
const a = 123456789;
const b = 123_456_789;
console.log(a === b); // true
Einführung in BigInt
BigInt ist ein neuer primitiver Datentyp, der ganze Zahlen beliebiger Größe repräsentiert. BigInt-Werte werden durch Anhängen eines n
an das Ende der Zahl erzeugt.
Beispiel:
const bigIntValue = 1_234_567_890_123_456_789_012_345_678_901_234_567_890n;
console.log(bigIntValue); // 1234567890123456789012345678901234567890n
Alternativ kann man die BigInt
-Funktion verwenden:
// Numeric Seperators funktionieren hier leider nicht.
const bigIntFromString = BigInt("1234567890123456789012345678901234567890");
console.log(bigIntFromString); // 1234567890123456789012345678901234567890n
Operationen mit BigInt
Man kann mit BigInt ähnlich wie mit normalen Zahlen rechnen, wobei einige Einschränkungen zu beachten sind.
Addition, Subtraktion, Multiplikation, Division:
const a = 12_345_678_901_234_567_890n;
const b = 98_765_432_109_876_543_210n;
console.log(a + b); // 111111111011111111100n
console.log(b - a); // 86419753208641975320n
console.log(a * b); // 1219326311370217952237463801111263526900n
console.log(b / a); // 8n
Hinweis zur Division:
Bei der Division von BigInt-Werten wird das Ergebnis immer auf die nächste ganze Zahl abgerundet.
console.log(10n / 3n); // 3n
console.log(10n / 4n); // 2n
Einschränkungen
Keine Vermischung von BigInt und Number:
BigInt und Number sind unterschiedliche Datentypen und können nicht direkt gemischt werden. Versuche, sie zu kombinieren, führen zu einem Fehler.
const bigIntValue = 10n;
const numberValue = 5;
console.log(bigIntValue + numberValue);
// TypeError: Cannot mix BigInt and other types
Um dies zu umgehen, muss man explizit konvertieren:
console.log(bigIntValue + BigInt(numberValue)); // 15n
console.log(Number(bigIntValue) + numberValue); // 15
Einsatz mit Math-Objekt:
Die Funktionen des Math
-Objekts unterstützen BigInt nicht.
const bigIntValue = 16n;
console.log(Math.sqrt(bigIntValue));
// TypeError: Cannot convert a BigInt value to a number
Falls nötig, muss man BigInt in Number umwandeln:
console.log(Math.sqrt(Number(bigIntValue))); // 4
Achtung bei der Konvertierung:
Beim Konvertieren großer BigInt-Werte in Number kann es zu Präzisionsverlust kommen.
const bigIntValue = 123_456_789_012_345_678_901_234_567_890n;
const numberValue = Number(bigIntValue);
console.log(numberValue); // 1.2345678901234568e+29
Verwendung von BigInt mit Vergleichsoperatoren
BigInt-Werte können mit anderen BigInt- oder Number-Werten verglichen werden.
console.log(10n > 5n); // true
console.log(10n === 10); // false (unterschiedliche Typen)
console.log(10n == 10); // true (Typumwandlung)
console.log(10n >= 10); // true
console.log(10n <= 10); // true
BigInt und JSON
BigInt-Werte können nicht direkt in JSON serialisiert werden.
const bigIntValue = 12_345_678_901_234_567_890n;
const obj = { value: bigIntValue };
console.log(JSON.stringify(obj));
// TypeError: Do not know how to serialize a BigInt
Um dies zu umgehen, muss man den BigInt-Wert konvertieren, z. B. in einen String:
const obj = { value: bigIntValue.toString() };
console.log(JSON.stringify(obj)); // {"value":"12345678901234567890"}
Praktische Anwendungsfälle
1. Kryptographie und Hashing
In kryptographischen Verfahren, etwa bei der Implementierung von RSA, werden sehr große Primzahlen verwendet. Diese Zahlen liegen oft weit außerhalb des sicheren Bereichs für normale JavaScript-Number-Werte. Mit BigInt kann man solche Berechnungen direkt in JavaScript durchführen:
// Beispiel: Multiplikation sehr großer Primzahlen (vereinfachtes Beispiel)
// In der Praxis würden diese Zahlen noch viel größer und zufällig generiert sein.
const prime1 = 1_298_074_214_633_706_907_132_624_082_305_027n;
const prime2 = 3_750_809_578_651_072_525_849_623_921_260_295n;
// Multiplikation für RSA-Schlüsselberechnung:
const product = prime1 * prime2;
console.log('Produkt aus zwei großen Primzahlen:', product.toString());
// Ohne BigInt wäre diese Berechnung nicht exakt möglich.
Dieses vereinfachte Beispiel zeigt, wie man mit BigInt große Zahlen handhaben kann, die in kryptographischen Algorithmen üblich sind.
2. Arithmetik mit großen Zahlen (Finanzberechnungen)
Stell dir vor, du entwickelst eine Anwendung für Finanztransaktionen, bei der exakte Berechnungen mit sehr großen Beträgen nötig sind (etwa Zinsen auf riesige Geldsummen oder wissenschaftliche Simulationen mit großen Messwerten). Gleitkommazahlen könnten Präzisionsverluste verursachen. BigInt gewährleistet exakte ganzzahlige Berechnungen:
// Beispiel: Berechnung von Zinsen auf sehr große Beträge
const principal = 99_999_999_999_999_999_999_999n; // Sehr großer Betrag
const rate = 5n; // 5% Zinsen
const time = 2n; // 2 Jahre
// Einfache Zinsberechnung: Zinsen = (Hauptbetrag * Zinssatz * Zeit) / 100
const interest = (principal * rate * time) / 100n;
console.log('Zinsen auf sehr großen Betrag:', interest.toString());
// Keine Rundungsfehler, da ganzzahlige Arithmetik verwendet wird.
Hier wird garantiert, dass auch bei sehr großen Werten keine Präzision verloren geht, was für finanzielle oder wissenschaftliche Berechnungen von entscheidender Bedeutung ist.
3. Arbeit mit 64-Bit-Datei-IDs
In einigen Betriebssystemen oder Dateisystemen werden 64-Bit-Datei-IDs verwendet, die nicht in eine normale JavaScript-Number passen, da der sichere Integer-Bereich dort überschritten wird. Mit BigInt kann man diese IDs exakt verarbeiten:
// Beispiel: Eine 64-Bit-Datei-ID, die größer als Number.MAX_SAFE_INTEGER ist
const fileId = 18_446_744_073_709_551_615n; // 2^64 - 1 (max. 64-Bit Wert)
// Speicherung, Vergleich oder Weitergabe dieser ID ohne Präzisionsverlust
function isValidFileId(id) {
// Prüfe, ob die ID in einem bestimmten Bereich liegt
const maxFileId = 2n**64n - 1n; // Maximaler 64-Bit Wert
return id <= maxFileId;
}
console.log(isValidFileId(fileId)); // true
Hier kann man Datei-IDs sicher vergleichen, sortieren oder validieren, ohne befürchten zu müssen, dass JavaScript den Wert ungenau repräsentiert.
Fazit
BigInt erweitert JavaScript um die Fähigkeit, mit ganzen Zahlen beliebiger Größe zu arbeiten, ohne Präzisionsverlust zu riskieren. Obwohl es einige Einschränkungen gibt, insbesondere bei der Interaktion mit Number
und dem Math
-Objekt, bietet BigInt eine wertvolle Ergänzung für Entwickler, die mit großen Zahlen arbeiten müssen.
Experimentiere mit BigInt in deinem nächsten Projekt und entdecke, wie es dir hilft, präzise Berechnungen mit großen Zahlen durchzuführen!