CodeGym /Kurse /C# SELF /Genauigkeitsprobleme und spezielle Werte

Genauigkeitsprobleme und spezielle Werte

C# SELF
Level 6 , Lektion 3
Verfügbar

1. Einführung

Man denkt, wenn der Computer "schlau" ist, dann sollte 0.1 + 0.2 einfach 0.3 ergeben. Aber so einfach ist das nicht. Lass uns das mal an einem einfachen Beispiel anschauen.

double x = 0.1;
double y = 0.2;
double sum = x + y;
Console.WriteLine(sum); // Was gibt das Programm aus?
Addition von Gleitkommazahlen: Wir erwarten 0.3, aber was kommt wirklich raus?

Und jetzt versuch mal, das mit 0.3 zu vergleichen:

Console.WriteLine(sum == 0.3); // Kommt hier true oder false raus?

Wenn du False siehst, wundere dich nicht!

Der Grund liegt in der Darstellung der Zahlen im Speicher

Computer arbeiten mit Zahlen im Binärsystem. Aber nicht jede Dezimalbruch kann als endlicher Binärbruch dargestellt werden, genauso wie 1/3 nicht exakt als Dezimalbruch (0.333...) geschrieben werden kann. Zum Beispiel ist 0.1 im Binärsystem ein unendlicher Bruch und muss zum Speichern "abgerundet" werden.

Auf gut Deutsch: double tut manchmal so, als würde es deine Zahl exakt speichern, aber in Wirklichkeit ist es nur ein sehr naher Näherungswert.

2. Welche "Bugs" gibt es bei der Arithmetik mit double?

Schauen wir uns praktische Beispiele an.

Beispiel 1. Der klassische "Zaubertrick" 0.1 + 0.2

double a = 0.1;
double b = 0.2;
double sum = a + b;
Console.WriteLine(sum);            // 0.30000000000000004
Console.WriteLine(sum == 0.3);     // False

Der Computer gibt nicht 0.3 aus, sondern 0.30000000000000004. Der Unterschied ist klein, aber wenn du zum Beispiel mit Finanzen arbeitest – dann ist das schon kritisch.

Beispiel 2. Iterative Addition

double result = 0;
for (int i = 0; i < 10; i++)
{
    result += 0.1;
}
Console.WriteLine(result); // 0.9999999999999999

Du wolltest 1.0 – bekommen hast du etwas weniger. Wieder liegt es am Runden im double.

Warum das in echten Anwendungen wichtig ist

Viele denken: "Was soll's, so ein kleiner Fehler, wen juckt's!" Schauen wir uns ein Beispiel aus der Zahlungswelt an.

Angenommen, deine Online-Bank summiert 100 Transaktionen à 0.1 Euro. Wenn dein Programm bei jeder Iteration ein Hunderttausendstel Euro "verliert", dann fehlen bei einer Bank im großen Stil plötzlich echte Euros. Und dann kommt sofort der Buchhalter zu dir und fragt: "Wo ist unser Geld?!"

3. Wie vergleicht man Gleitkommazahlen richtig

Da double oft nicht genau den Wert speichern kann, den du erwartest, kann ein direkter Vergleich mit == "schiefgehen". Stattdessen vergleicht man üblicherweise den Betrag der Differenz mit einer sehr kleinen Zahl (epsilon).

Beispiel für Vergleich mit Toleranz

double a = 0.1 + 0.2;
double b = 0.3;
double epsilon = 0.000001;

if (Math.Abs(a - b) < epsilon)
{
    Console.WriteLine("Fast gleich!"); // So ist der Vergleich sicherer
}

Hier sagen wir: "Wenn der Unterschied zwischen den Zahlen kleiner als eine Millionstel ist, dann gelten die Zahlen als gleich."

4. Spezielle Werte von double: Infinity, NaN, -Infinity

Der Typ double speichert nicht nur Zahlen, sondern auch besondere Werte. Die tauchen in Situationen auf, die ein Mathematik-Dozent jedem Studenten strengstens verbieten würde.

Unendlichkeit (Infinity)

Was passiert, wenn du 1 durch 0 teilst?

double result = 1.0 / 0.0;
Console.WriteLine(result); // Infinity

In C# (und vielen anderen Sprachen) löst eine Division durch 0 bei double keine Exception aus! Stattdessen wird das Ergebnis zu einem speziellen Wert "positive Unendlichkeit".

Minus Unendlichkeit (-Infinity)

Wenn du eine negative Zahl durch 0 teilst, bekommst du negative Unendlichkeit:

double result = -1.0 / 0.0;
Console.WriteLine(result); // -Infinity

"Keine Zahl" (NaN — Not a Number)

Wenn du etwas ganz Verrücktes machst, zum Beispiel die Wurzel aus einer negativen Zahl berechnen willst:

double result = Math.Sqrt(-1);
Console.WriteLine(result); // NaN

Oder das Ergebnis von 0.0 / 0.0:

double result = 0.0 / 0.0;
Console.WriteLine(result); // NaN

NaN – das ist "alles, was im echten Leben keine Zahl wäre".

Prüfen auf spezielle Werte

In C# gibt es Funktionen, um auf spezielle Werte zu prüfen:

Console.WriteLine(double.IsInfinity(result));    // true wenn Unendlichkeit
Console.WriteLine(double.IsNaN(result));         // true wenn NaN

Tabelle: Wie double auf ungewöhnliche Operationen reagiert

Operation Ergebnis Was im double gespeichert wird
1.0 / 0.0
Infinity +∞
-1.0 / 0.0
-Infinity -∞
0.0 / 0.0
NaN Keine Zahl
Math.Sqrt(-1)
NaN Keine Zahl
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION