float vergleiche
-
hallo zusammen
da ich mir gedacht habe, die ganzen float-vergleiche mit epsilon usw können mit der zeit ins gewicht (rechenzeit) fallen, wollte ich nachfragen, ob folgendes vom standard her definiert ist:const float one_f = 1.f; float d = one_f; // code der d evtl. verändert if(d == one_f) { // ... }
also sozusagen ob es definiert ist, dass ein bitweiser vergleich zweier fliesskommazahlen immer true ergibt, sofern man die eine der anderen zugewiesen hat.
-
kann mir nicht vorstellen, dass das ungleich ist - vorausgesetzt es existieren tatsächlich zwei float-Variablen und der Compiler führt keine komischen Optimierungen durch. Ob da was definiert ist, weiß ich nicht.
lustiger Code:
{ // hier ist 1.2 + 0.1 == 1.2 + 0.1 float f1 = 1.2; float f2 = f1 + 0.1; float f2_merker = f2; if( f2 == f2_merker ) cout << "f2 == f2_merker" << endl; } { // hier ist 1.2 + 0.1 != 1.2 + 0.1 (Umgebung VS 2005 oder VS 2010, OS: Windows 7) float f1 = 1.2; float f2 = f1 + 0.1; if( f2 != (f1 + 0.1) ) cout << "Ueberraschung!" << endl; // <== diese Zeile wird aufgerufen! }
möge das mal jemand auf einem Nicht-Windows-System probieren
-
Der Standard definiert hierfür nichts.
Du kannst aber davon ausgehen, das float/double/long double Vergleiche nur nach zwischenzeitlichen Rechenoperationen fehlschlagen (der Standard sagt das nicht aus), alsodouble d = 3.0; if( d == 3.0 ) // sollte true ergeben ( ich kenne keinen Compiler, der es anders macht; bin aber aufgeschlossen für neue Erkenntnisse ) d = d / 1.0; if( d == 3.0 ) // muss nicht mehr true ergeben
-
Wutz schrieb:
Der Standard definiert hierfür nichts.
Du kannst aber davon ausgehen, das float/double/long double Vergleiche nur nach zwischenzeitlichen Rechenoperationen fehlschlagen (der Standard sagt das nicht aus), alsodouble d = 3.0; if( d == 3.0 ) // sollte true ergeben ( ich kenne keinen Compiler, der es anders macht; bin aber aufgeschlossen für neue Erkenntnisse ) d = d / 1.0; if( d == 3.0 ) // muss nicht mehr true ergeben
Für double=3.0 mag das funktionieren, aber:
float f1 = 1.3; if( f1 != 1.3 ) cout << "es gibt Compiler wo 1.3!=1.3 ist" << endl;
-
Werner_logoff schrieb:
möge das mal jemand auf einem Nicht-Windows-System probieren
Muss niemand machen. Wenn Du auf Deinem Windows System alle Warnings anschaltest solltest Du sowas bekommen:
`1>main.cpp(246): warning C4305: 'Initialisierung': Verkürzung von 'double' in 'float'
1>main.cpp(247): warning C4244: 'Initialisierung': Konvertierung von 'double' in 'float', möglicher Datenverlust
`
Der Punkt ist, dass bei Deinem Zuweisungen immer von double nach float konvertiert wird. Beim Vergleich wird von float nach double konvertiert. Dadurch entsteht die Ungleichheit.
Deswegen: Immer mit eps vergleichen.
-
Werner Salomon schrieb:
cout << "es gibt Compiler wo 1.3!=1.3f ist" << endl;
FTFY.
-
möge das mal jemand auf einem Nicht-Windows-System probieren
64-Bit Archlinux mit Clang - selbes Ergebnis
Ich wollte gerade schreiben, das Literal hat Typ
double
, aber das wäre zu spät, wie ich gerade merke
-
doubler schrieb:
Werner_logoff schrieb:
möge das mal jemand auf einem Nicht-Windows-System probieren
Muss niemand machen. Wenn Du auf Deinem Windows System alle Warnings anschaltest solltest Du sowas bekommen:
`1>main.cpp(246): warning C4305: 'Initialisierung': Verkürzung von 'double' in 'float'
1>main.cpp(247): warning C4244: 'Initialisierung': Konvertierung von 'double' in 'float', möglicher Datenverlust
`
Der Punkt ist, dass bei Deinem Zuweisungen immer von double nach float konvertiert wird. Beim Vergleich wird von float nach double konvertiert. Dadurch entsteht die Ungleichheit.
try this:
{ // hier ist 1.2 + 0.1 != 1.2 + 0.1 (Umgebung VS 2005 oder VS 2010, OS: Windows 7) float f1 = 1.2f; float null_dot_one = 0.1f; float f2 = f1 + null_dot_one; if( f2 != (f1 + null_dot_one) ) cout << "Ueberraschung!" << endl; }
0 warnings
doubler schrieb:
Deswegen: Immer mit eps vergleichen.
-
wenn ich z.b. floats mit einem const float initialisiere und dann dem nutzer überlasse ob was geändert werden soll und ich dann diese änderung mit == zum const float überprüfe, dann ist == immer true wenn die floats nicht angefasst wurden. stimmt da?
es finden also keine dinge mit *1 oder /1 oder konversionen zu double etc statt.
-
wenn ich z.b. floats mit einem const float initialisiere und dann dem nutzer überlasse ob was geändert werden soll und ich dann diese änderung mit == zum const float überprüfe, dann ist == immer true wenn die floats nicht angefasst wurden. stimmt da?
Das ist korrekt.
0 warnings
Und keine Ausgabe. Alles andere ist IIRC nicht standardkonform.
-
Werner Salomon schrieb:
float f1 = 1.3; if( f1 != 1.3 ) cout << "es gibt Compiler wo 1.3!=1.3 ist" << endl;
Sicher?
Ich glaube du machst was falsch.
Ich habe im Beispiel bewusst double gewählt, da Fließkommaliterale ohne Typsuffix immer double sind. f1 ist float, erhält also nur einen implizit konvertierten double-Wert, wenn IEEE 754 definitiert ist und damit float != double.
Vergleichen tust du dann dein float f1 wieder mit double, und hier fehlen die zuvor wegkonvertierten zusätzlichen double-Infos und der Vergleich sollte fehlschlagen.
Probiere mal:float f1 = 1.3; if( f1 == 1.3f )
und dass sollte dann wieder funktionieren.
-
EDIT:
Ich wage zu behaupten, dass es immer möglich ist vorherzusagen, ob die Abfrage auf Gleichheit funktioniert oder nicht.Wenn man equivalente Operationen durchführt auf 2 unabhängigen Variablen gleichen Anfangswertes (intialisiert mit konstanten Ausdrücke, nicht mit Rechenergebnissen) muss das Ergebnis in beiden Variablen bitgleich sein. (Vorausgesetzt alles wird 1 zu 1 übersetzt).
Auch sollte die Bit-Repräsentation von konstanten Ausdrücken gleich sein mit denen von Lvalues, sofern auf diese keine Operationen angewandt wurden.
Ich gehe auch davon aus, dass wir hier Variablen gleichen Typs verwenden.
Aber: Ich wüsste auch nicht warum man es darauf ankommen lassen sollte einen Fehler hier zu machen.