Double mit if prüfen
-
Hallo Leute,
ich habe gerade folgendes festgestellt:double b = 12.34; if (a == 12.34) { cout << "a=" << a << endl; }Hier läuft alles wunderbar.
Allerdings hier:
double a = 12.04; if (a == 12.04) { cout << "a=" << a << endl; }passiert nix. Ich glaube das liegt an der führenden 0 nach dem Punkt.
Ist das Euch auch schon aufgefallen oder ein Bug. Benutze Visual C++ 2003.
Gibts da ein Workaround oder einen Trick?Liebe Grüsse
Tonda
-
die zahlen sind halt nicht gleich
-
tja. schrieb:
die zahlen sind halt nicht gleich
Mmhh...ich erkenne an 12.04 und 12.04 keinen Unterschied.
Vielleicht kannst Du es mir näher erklären.Tonda
-
Nachtrag:
Im ersten Beispiel muss es natürlichdouble a = 12.34;heissen. War ein Vertipper.
Aber es geht ja eher um das 2. Beispiel.
-
Das kann nicht sein und ist auch nicht so.
-
Mann kann (sollte) Floatingpoint Zahlen nicht auf Gleichheit prüfen da in diesen Formaten die wenigsten Zahlen genau darstellbar sind. Es kommt immer wieder zu Rundungsfehlern und dann versagt der Vergleich.
Kann mir zwar nicht erklären warum die Konstante 12.04 ungleich einer Variablen mit dem Wert 12.04 sein sollte aber ich würde so einen Vergleich gar nicht erst versuchen.
Kurt.
-
Tonda schrieb:
Allerdings hier:
double a = 12.04; if (a == 12.04) { cout << "a=" << a << endl; }passiert nix. Ich glaube das liegt an der führenden 0 nach dem Punkt.
Ist das Euch auch schon aufgefallen oder ein Bug. Benutze Visual C++ 2003.Kann ich nicht bestätigen, habs allerdings nur mit VC++ 2005 getestet. Es gibt auch keinen Grund, warum dies nicht funktionieren sollte. Denn egal ob der Wert verlustfrei in ein double passen oder nicht, beide Literale haben letztendlich die gleiche binäre Darstellung. Dein Originalcode muss deshalb anders aussehen.
-
Zunächst mal hab ich auf dem 2003er kein Problem für dieses Beispiel in das if zu kommen, kann es sein, das der real getestete Code etwas anders aussieht?

Sobald die 12.04 das Egebnis einer noch so primitiven Berechnung ist, hat man je nach Situation schon verloren, denn wie die anderen schon sagten ist == für float oder double auf jeden Fall zu vermeiden. Wenn Du wirklich auf ein Ergebnis prüfen musst, dann prüfe ob der Betrag der Differenz kleiner ist als eine gewünschte Genauigkeit, so wird aus dem == ein < und die Welt ist in Ordnung (wenn Du es mit der Genauigkeit nicht übertreibst).
Generell sind selbst einfach aussehende Zahlen im Computer manchmal verblüffend schwer darzustellen, dazu kurz dieses Beispiel:
Wir wollen die komplizierte Zahl 12.3125 in eine (hypothetische aber realistische) binäre interne Darstellung umrechnen:
Vorkomma: 12 / 2 = 6 -> 0 6 / 2 = 3 -> 00 3 / 2 = 1.5 -> 100 Endlich, ein Bit :) 1 / 2 = 0.5 -> 1100 Und noch eines, fertig! Nachkomma: 0.3125 * 2 = 0.625 -> 1100.0 Hm, 0 vorm Komma = 0-Bit 0.625 * 2 = 1.25 -> 1100.01 Ah 1, also ein 1-Bit (die 1 wird entsorgt) 0.25 * 2 = 0.5 -> 1100.010 diesmal wieder nix... 0.5 * 2 = 1.0 -> 1100.0101 Noch eine 1, fertig!Nun wollen wir die viel einfacher aussehende Zahl 0.1 umrechnen:
Vorkommaanteil ist einfach: 0 :) Nun kommt der Nachkommaanteil: 0.1 * 2 = 0.2 -> 0.0 0.2 * 2 = 0.4 -> 0.00 0.4 * 2 = 0.8 -> 0.000 0.8 * 2 = 1.6 -> 0.0001 Ha! Ein erstes Bit! Weg mit dem Vorkommateil 0.6 * 2 = 1.2 -> 0.00011 noch eines! 0.2 * 2 = 0.4 -> 0.000110 hm... 0.4 * 2 = 0.8 -> 0.0001100 äh... 0.8 * 2 = 1.6 -> 0.00011001 also... 0.6 * 2 = 1.2 -> 0.000110011 sieht so aus als ob das noch dauern könnte...Die Umrechnung von z.B. 12.04 überlasse ich als Übung dem geneigten Leser.

Man sieht, schon sowas einfaches wie 0.1 kann der Computer mit seiner (üblicherweise) binären Mantisse nicht abbilden. Es kommt eine Periode raus, die halt je nach Datentyp abgeschnitten weden muß, da die Mantisse selbst bei Double oft nicht mehr als 52 Bit hat.
Also kann man damit auch nicht "korrekt" rechnen. Daher unterscheiden sich schon einfache Zahlen. So ist z.B. double(float(12.04)) != double(12.04) weil halt auch 12.04 eine periodische Binärdarstellung hat und im ersten Fall halt deutlich weniger Bits genommen werden als im zweiten. Die kann der Computer für den Vergleich durch den cast auf double nicht mehr hinzuerfinden.

-
Danke, Danke für die Posts
longDouble schrieb:
Zunächst mal hab ich auf dem 2003er kein Problem für dieses Beispiel in das if zu kommen, kann es sein, das der real getestete Code etwas anders aussieht?

In der Tat:
double a = 12.34; double b = 12.34; double c = 0; //1 c = a + b; //24,68 = 12,34 + 12,34 if (c == 24.68) { cout << "c = a + b = " << " " << c << " Soll: 24,68" << endl; } else throw exeption(1); //2 c = a + 12.68; //25,02 = 12,34 + 12,68 if (c == 25.02) { cout << "c = a + 12.68 = " << " " << c << " Soll: 25,02" << endl; } else throw exeption(2); //3 a += b; //24,68 = 12,34 + 12,34 if (a == 24.68) { cout << " a += b = " << " " << a << " Soll: 24,68" << endl; } else throw exeption(3); //4 a += [u]12.34[/u]; //37,02 = 24,68 + 12,34 cout << a << endl; if (a == 37.02) { cout << " a += 12,34 = " << " " << a << " Soll: 37,36" << endl; } else throw exeption(4);Bei Nummer 4 tritt der Fehler!? auf.
cout a gibt 37.02 aus. Trotzdem wird if nicht ausgeführt. Der Witz ist aber, wenn ich den unterstrichenen Wert ändere, z.B. 12.33 (die if-Bedingung dementsprechend auch auf 37.01 ändere) funktioniert alles, d.h. die der if-Block wird ausgeführt.@Zuk && Floatingzahlen
Ich weiss. Es ist nur zum Rumprobieren mit Exeptions.Liebe Grüsse
Tonda
-
dann ist ja jetzt alles geregelt oder?
-
Der Dubugger ist dein Freund und Helfer.