double vergleichen: Wie lange reicht ==-operator aus?



  • Wenn ich doubles einsetze, dann habe ich bisher gerne mit == gearbeitet da es mir nicht auf die 14 Nachkommastelle ankommt. Bspw. scheint mir sowas kein Problem zu sein:

    double x = wert;
    if(x == 130.2) {
    
    }
    

    Oder sehe ich das falsch? Gefühlt scheint es kritisch zu werden, wenn man per == auf viele Nachkommastellen vergleicht 😕



  • "==" vergleicht immer auf die gesamte Variablenbreite. Hinzu kommt noch, dass Fließkommazahlen teilweise je nach Architektur im Rechner mit einer höheren Genauigkeit verarbeitet werden, als die mit der sie im Speicher stehen. Das führt dann zu Phänomenen wie z.B. dass eine Variable der ich irgendwann exakt 0.3 zugewiesen habe später bei einem Vergleich mit 0.3 nicht mehr true liefert.



  • Ich habe gerade realisiert das ich bisher einfach nur unglaublich viel Glück hatte, da ich in doubles nur ganze Zahlen gespeichert habe. Damit war wohl die ganze Zeit ein Vergleichen von doubles problemlos möglich.

    Sicherheitshalber hab ich jetzt den Datentyp geändert 🕶



  • Wenn man nur Ganzzahlen verwendet ist es immer eine gute Idee ganzzahlige Datentypen zu verwenden. Damit spart man sich viel Ärger und ist deutlich schneller.



  • DoppelterSpass schrieb:

    Oder sehe ich das falsch?

    Ja, siehe:

    #include <iostream>
    #include <iomanip>
    
    using namespace std;
    
    int main()
    {
       double wert = 130.2;
       double andererWert = 129.2;
    
       for(int i = 0; i < 10; ++i)
          andererWert += 0.1;
    
       cout << "wert        ======> " << wert << '\n';
       cout << "andererWert ======> " << andererWert << '\n';
    
       if(wert == andererWert)
          cout << "\nwert ist gleich andererWert\n";
       else
          cout << "\nwert ist ungleich andererWert\n";
    
       cout << setprecision(20) << "\nwert        ======> " << wert << '\n';
       cout << "andererWert ======> " << andererWert << '\n';
    }
    

  • Mod

    TNA schrieb:

    Das führt dann zu Phänomenen wie z.B. das eine Variable der ich irgendwann exakt 0.3 zugewiesen habe später bei einem Vergleich mit 0.3 nicht mehr true liefert.

    Das ist unmöglich (wenn wir mal Nicht-Standardumgebungen ignorieren). Einfache Zuweisung verändert niemals den Wert von Zahlen. Ungenauigkeiten ergeben sich genau dann, wenn das exakte Ergebnis einer Operation nicht exakt im Zieltyp dargestellt werden kann, also
    - bei Ergebnissen von Rechenoperationen (z.B. überschüssige Stellen bei der Multiplikation, Werte von Literalen wie 0.3 u.ä.),
    - ein Wert eines Typs in einen eines Typs mit kleinerem Wertebereich/Genauigkeit konvertiert werden muss (double->float u.ä.)



  • Das ist doch genau bei 0,3 der Fall. 0,3 ist als Fließkommazahl nie exakt 0,3 und die Anzahl der Stellen kann eben variieren. Datentypen garantieren immer nur eine Mindestgenauigkeit währen intern manchmal genauer gerechnet wird. Die Repräsentation von "0,3" im Hauptspeicher muss nicht gleich der Repräsentation von 0,3 in einem Register oder Direktoperand sein.



  • camper schrieb:

    TNA schrieb:

    Das führt dann zu Phänomenen wie z.B. das eine Variable der ich irgendwann exakt 0.3 zugewiesen habe später bei einem Vergleich mit 0.3 nicht mehr true liefert.

    Das ist unmöglich

    Genau bei float ist es eben doch möglich (wie du selber schreibst).

    float f=0.3; // int f=0.3; ist das gleiche Phänomen leichter verständlich
    assert(f!=0.3);
    

    Nur bei double (und vermutlich long double) ist es nicht mehr möglich, weil das Literal 0.3 immer als double dargestellt wird.



  • Es reicht solange bis man damit auf die Nase fällt 😃

    Beschäftige Dich mal ein bisschen damit wie Dein Rechner die Zahlen intern verarbeitet. Du wirst schnell sehen, dass es simple Zahlen gibt die überhaupt nicht exakt darstellbar sind z.B. 0.1

    Mit dem Wissen wirst Du dann NIE wieder auf die Idee kommen Fließkommazahlen per == zu vergleichen.

    if ( ( 0.1 + 0.1 ) == 0.2 ) wird nie wahr sein. 😃



  • MichelRT schrieb:

    if (0.1+0.1==0.2) wird nie wahr sein. 😃

    Sag niemals nie.
    Auf meinem Rechnner ist das gerade das Gegenteil der Fall 😃


  • Mod

    weallfloat schrieb:

    camper schrieb:

    TNA schrieb:

    Das führt dann zu Phänomenen wie z.B. das eine Variable der ich irgendwann exakt 0.3 zugewiesen habe später bei einem Vergleich mit 0.3 nicht mehr true liefert.

    Das ist unmöglich

    Genau bei float ist es eben doch möglich (wie du selber schreibst).

    float f=0.3; // int f=0.3; ist das gleiche Phänomen leichter verständlich
    assert(f!=0.3);
    

    Nur bei double (und vermutlich long double) ist es nicht mehr möglich, weil das Literal 0.3 immer als double dargestellt wird.

    Da musst du aber auch korrekterweise mit 0.3f vergleichen. Und das sollte dann auch erfolgreich sein.



  • SeppJ schrieb:

    weallfloat schrieb:

    camper schrieb:

    TNA schrieb:

    Das führt dann zu Phänomenen wie z.B. das eine Variable der ich irgendwann exakt 0.3 zugewiesen habe später bei einem Vergleich mit 0.3 nicht mehr true liefert.

    Das ist unmöglich

    Genau bei float ist es eben doch möglich (wie du selber schreibst).

    float f=0.3; // int f=0.3; ist das gleiche Phänomen leichter verständlich
    assert(f!=0.3);
    

    Nur bei double (und vermutlich long double) ist es nicht mehr möglich, weil das Literal 0.3 immer als double dargestellt wird.

    Da musst du aber auch korrekterweise mit 0.3f vergleichen. Und das sollte dann auch erfolgreich sein.

    Es ging um eine wörtliche Umsetzung des Zitats.
    Selbst float f=0.3;assert(f==0.3f); (wörtliche Umsetzung deiner Aussage) ist implementation-defined.


  • Mod

    weallfloat schrieb:

    Selbst float f=0.3;assert(f==0.3f); (wörtliche Umsetzung deiner Aussage) ist implementation-defined.

    Ich wette, ich kann die benutzte Implementierung erraten. Beim ersten Versuch. Auf egal welchem System.


  • Mod

    weallfloat schrieb:

    Selbst float f=0.3;assert(f==0.3f); (wörtliche Umsetzung deiner Aussage) ist implementation-defined.

    Wenn man annimmt, dass die Wahl in 2.14.4/2 nicht mit der in 4.8/1 übereinstimmen muss. Ansonsten eben

    float f=0.3;assert(f==float(0.3));
    

    Das unmmöglich bezog sich vor allem auf den Fakt, dass

    eine Variable ... exakt 0.3 zugewiesen

    unmöglich ist. Da 0.3 mit den Standardtypen nicht exakt darstellbar ist, kann es logischerweise auch nicht exakt der Wert sein, der in der Variablen gespeichert wird.


Anmelden zum Antworten