Menu

JavaScript: Numbers, BigInt & Floating-Point-Präzision

Wie der Number-Typ in JavaScript wirklich funktioniert — Floating-Point-Probleme, MAX_SAFE_INTEGER und wann du besser zu BigInt greifst.

Ein Zahlentyp für (fast) alles

In den meisten Sprachen gibt es getrennte Typen für Ganzzahlen und Fließkommazahlen. JavaScript hatte historisch nur einen einzigen: den Number-Typ. Egal ob du 42, 3.14 oder -0.001 schreibst — du bekommst immer denselben primitiven Wert, nämlich eine 64-Bit-Fließkommazahl nach IEEE 754 (double precision).

index.js
Output
Click Run to see the output here.

Praktisch, oder? Kein Cast zwischen int und float, kein Overflow bei 2^31. Aber die Darstellung als Fließkommazahl hat ihren Preis — und Anfänger tappen regelmäßig in genau diese Falle. 2020 kam deshalb ein zweiter numerischer Typ dazu: BigInt. Er springt überall dort ein, wo Number an seine Grenzen stößt.

Die Sache mit der Fließkomma-Genauigkeit

Führ mal das hier aus:

index.js
Output
Click Run to see the output here.

Die erste Zeile gibt 0.30000000000000004 aus, die zweite false. Das ist keine Macke von JavaScript – Python, Java, C und jede andere Sprache, die IEEE-754-Floats nutzt, verhält sich exakt gleich.

Der Grund: 0.1 und 0.2 lassen sich im Binärsystem nicht exakt darstellen, genauso wie 1/3 im Dezimalsystem nicht sauber aufgeht. Gespeichert wird jeweils die nächstgelegene binäre Näherung, und die winzigen Fehler summieren sich. Das passende mentale Modell: Betrachte Number-Werte mit Nachkommastellen als Näherungen, die zufällig sehr dicht an dem liegen, was du hingeschrieben hast.

Für Geldbeträge heißt das: Speichere 19,99 € nicht als 19.99. Rechne stattdessen in Cent mit Ganzzahlen – also 1999 – und formatiere erst bei der Ausgabe. Das ist die wichtigste Gewohnheit, um der mangelnden Fließkomma-Genauigkeit in JavaScript aus dem Weg zu gehen.

Floats sicher vergleichen

Da ein Gleichheitsvergleich hier unzuverlässig ist, solltest du bei Bedarf mit einer Toleranz arbeiten:

index.js
Output
Click Run to see the output here.

Number.EPSILON steht für die kleinste Differenz zwischen 1 und der nächsten darstellbaren Zahl – eine brauchbare Standardtoleranz für Werte in der Nähe von 1. Bei besonders großen oder sehr kleinen Beträgen brauchst du dagegen eine Toleranz, die mit den Eingabewerten mitskaliert.

Der sichere Integer-Bereich in JavaScript

Ganze Zahlen bis zu einer bestimmten Größe werden in einem 64-Bit-Float exakt dargestellt. Darüber hinaus verlierst du Stück für Stück an Genauigkeit – Bit für Bit:

index.js
Output
Click Run to see the output here.

2^53 - 1 ist die letzte Ganzzahl, unterhalb derer wirklich jede Ganzzahl darstellbar ist. Darüber hinaus existieren manche Integer im Number-Typ schlicht nicht mehr – sie werden auf den nächstgelegenen Nachbarn gerundet. Genau hier lauert ein stiller Datenverlust: Wenn du 64-Bit-IDs aus einer Datenbank als einfache JSON-Zahlen einliest, kracht es früher oder später.

BigInt kommt ins Spiel

BigInt ist ein eigenständiger primitiver Typ für beliebig große Ganzzahlen. Du erzeugst einen BigInt, indem du ein n an ein Integer-Literal anhängst oder BigInt(...) aufrufst:

index.js
Output
Click Run to see the output here.

BigInts haben keine feste Obergrenze – sie sind nur durch den verfügbaren Speicher begrenzt. Sie sind das richtige Werkzeug für:

  • Datenbank-IDs oder Snowflake-IDs von Twitter/X, die über 2^53 hinausgehen.
  • Kryptografische Berechnungen.
  • Jede Ganzzahlarithmetik, bei der exakte Ergebnisse wichtiger sind als reine Geschwindigkeit.

Für alltägliche Zähler, Array-Indizes oder Geldbeträge in Cent sind sie dagegen nicht das passende Werkzeug – der normale Number-Typ ist schneller und spielt mit jeder API der Sprache zusammen.

Rechnen mit BigInt

Alle gewohnten Operatoren funktionieren – solange beide Operanden BigInts sind:

index.js
Output
Click Run to see the output here.

Die Division schneidet Richtung Null ab – Nachkommastellen gibt es bei BigInts schlicht nicht. Wenn du einen Bruch brauchst, bist du wieder bei Number (oder bei einer Decimal-Bibliothek).

Typen nicht mischen

Die Regel, über die praktisch jeder einmal stolpert: Number und BigInt darfst du in derselben Expression nicht mischen.

index.js
Output
Click Run to see the output here.

Vergleiche sind die einzige Ausnahme — <, >, == wandeln über die Grenze hinweg um:

index.js
Output
Click Run to see the output here.

== hält sie also für gleich, === nicht. Wer bereits konsequent === verwendet (und das solltest du), sollte numerische Vergleiche zwischen beiden Typen als Warnsignal im Design betrachten – entscheide dich für eine Seite und konvertiere.

Umwandlung zwischen Number und BigInt

Zwei Konvertierungen, zwei Stolperfallen:

index.js
Output
Click Run to see the output here.

Der Weg Number → BigInt ist strikt: Dezimalstellen und NaN werfen einen Fehler. Umgekehrt, also BigInt → Number, ist nachgiebiger, dafür aber verlustbehaftet — alles oberhalb von MAX_SAFE_INTEGER wird gerundet. Wenn du einen BigInt vom Server bekommst und ihn umwandeln willst, frag dich lieber zweimal, ob das wirklich nötig ist.

Besondere Werte im Number-Typ

Wo wir gerade dabei sind: Im Number-Typ gibt es drei Werte, die mathematisch gesehen gar keine Zahlen sind:

index.js
Output
Click Run to see the output here.

Infinity und -Infinity tauchen auf, wenn du durch Null teilst oder den Wertebereich von Floats sprengst. NaN ("not a number") erscheint dagegen, wenn eine Rechenoperation kein sinnvolles Ergebnis liefert.

Eine bekannte Eigenheit: NaN ist nicht einmal zu sich selbst gleich — das ist kein Bug in JS, sondern so in IEEE 754 festgelegt. Zum Prüfen nimmst du Number.isNaN(x). Die ältere globale Funktion isNaN wandelt ihr Argument vorher in eine Zahl um und liefert deshalb falsche Ergebnisse (isNaN("hello") gibt true zurück). Greif also immer zu Number.isNaN.

Strings in Zahlen umwandeln

Nutzereingaben und JSON-Werte kommen oft als String an. Es gibt drei Wege, daraus eine Zahl zu machen:

index.js
Output
Click Run to see the output here.

Number() ist streng – alles, was nicht numerisch ist, liefert NaN. Ausnahmen sind der leere String und reine Whitespaces, die 0 ergeben. parseInt und parseFloat dagegen sind nachsichtig: Sie lesen so weit wie möglich und hören auf, sobald etwas Nicht-Numerisches kommt. Nimm das, was zu deinem Ziel passt, und prüfe das Ergebnis vorher auf NaN.

Wenn du BigInts aus Strings parsen willst, nutze BigInt("123") – die Funktion ist strikt und wirft bei ungültiger Eingabe einen Fehler.

Die wichtigsten Regeln auf einen Blick

  • Für Zähler, Mathematik, Koordinaten und die meisten Alltagszahlen: Number.
  • Für Geldbeträge: in ganzzahlige Cent umrechnen und Number verwenden, oder zu einer Decimal-Bibliothek greifen.
  • Für ganze Zahlen größer als 2^53 (Datenbank-IDs, Kryptografie, Kombinatorik): BigInt mit dem n-Suffix.
  • Floats mit einer Toleranz vergleichen, nie mit ===.
  • Ungültige Ergebnisse mit Number.isNaN und Number.isFinite prüfen, nicht mit den globalen Varianten.
  • Number und BigInt nicht im selben Ausdruck mischen – immer explizit konvertieren.

Als Nächstes: null vs. undefined

JavaScript kennt zwei Arten, „kein Wert" auszudrücken – null und undefined – und die beiden sind nicht austauschbar. Im nächsten Kapitel schauen wir uns an, was jedes davon bedeutet, worin sie sich unterscheiden und wann du welches verwenden solltest.

Häufig gestellte Fragen

Warum ergibt 0.1 + 0.2 in JavaScript nicht 0.3?

Weil der Number-Typ in JavaScript ein 64-Bit-IEEE-754-Float ist — und 0.1 und 0.2 lassen sich binär nicht exakt darstellen. Heraus kommt 0.30000000000000004. Das ist kein Bug von JavaScript, sondern passiert genauso in Python, Java und überall sonst, wo dasselbe Float-Format genutzt wird. Für Geldbeträge rechnest du entweder in Cent (also mit ganzen Zahlen) oder nutzt eine Decimal-Bibliothek.

Was ist BigInt in JavaScript und wann brauche ich es?

BigInt ist ein eigener numerischer Primitiv-Typ für ganze Zahlen jenseits von Number.MAX_SAFE_INTEGER (2^53 - 1). Du erzeugst einen BigInt mit einem angehängten n — also 9007199254740993n — oder per BigInt(value). Sinnvoll ist das bei 64-Bit-Datenbank-IDs, in der Kryptografie oder überall dort, wo Präzision wichtiger ist als Geschwindigkeit.

Kann ich Number und BigInt in JavaScript mischen?

Nein. 1n + 1 wirft direkt einen TypeError: Cannot mix BigInt and other types. Du musst explizit konvertieren, entweder mit BigInt(n) oder Number(b). Vergleichsoperatoren wie < oder == funktionieren zwar typübergreifend, aber === liefert false, weil die Typen eben unterschiedlich sind.

Lerne mit Coddy zu programmieren

LOS GEHT'S