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), also

    double 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), also

    double 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.


  • Mod

    Werner Salomon schrieb:

    cout << "es gibt Compiler wo 1.3!=1.3f ist" << endl;
    

    FTFY.


  • Mod

    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.


  • Mod

    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.


Anmelden zum Antworten