Fließkommavergleich [duplicate]

Lesezeit: 5 Minuten

Flieskommavergleich duplicate
Sasidhar

int main()
{
    float a = 0.7;
    float b = 0.5;
    if (a < 0.7)
    {
       if (b < 0.5) printf("2 are right");
       else         printf("1 is right");
    }
    else printf("0 are right");
}

Ich hätte die Ausgabe dieses Codes erwartet 0 are right. Aber zu meiner Bestürzung ist die Ausgabe 1 is right warum?

  • Du solltest lesen “Was jeder Informatiker über Gleitkommaarithmetik wissen sollte”.

    – Andrea Bergia

    10. August 2011 um 13:03 Uhr

  • 0,7 ist kein Float, sondern ein Double. Das könnte ein Grund für dieses Verhalten sein

    – Sebastian Hoffmann

    10. August 2011 um 13:05 Uhr

  • Ein Grund ist das a ist ein float und .7 ist ein double.

    – Bo Persson

    10. August 2011 um 13:05 Uhr

  • Mitch, wenn 0.7 == 0.7 Die Antwort wäre 0 are right

    – Emil Vikström

    10. August 2011 um 13:06 Uhr

  • guter Punkt. Es ist spät. Ich sollte jetzt aufhören! …..

    – Mitch Weizen

    10. August 2011 um 13:07 Uhr

Flieskommavergleich duplicate
Benutzer703016

int main()
{
    float a = 0.7, b = 0.5; // These are FLOATS
    if(a < .7)              // This is a DOUBLE
    {
      if(b < .5)            // This is a DOUBLE
        printf("2 are right");
      else
        printf("1 is right");
    }
    else
      printf("0 are right");
}

Floats werden während des Vergleichs zu Doubles hochgestuft, und da Floats weniger präzise sind als Doubles, ist 0,7 als Float nicht das gleiche wie 0,7 als doppelt. In diesem Fall wird 0,7 als Float 0,7 als Double unterlegen, wenn es befördert wird. Und wie Christian sagte, 0,5 als Potenz von 2 wird immer genau dargestellt, sodass der Test wie erwartet funktioniert: 0.5 < 0.5 ist falsch.

Also entweder:

  • Ändern float zu doubleoder:
  • Ändern .7 und .5 zu .7f und .5f,

und Sie erhalten das erwartete Verhalten.

  • Das erste if und das zweite if sollten auf die gleiche Weise ausgewertet werden, oder?? also sollte die Antwort entweder sein 2 are right oder 0 are right aber warum 1 is right??

    – Sasidhar

    10. August 2011 um 13:08 Uhr

  • +1 Für die einzige Antwort, die beim Sehen der Frage nicht “Vergleiche niemals Schwimmer” rief und tatsächlich darüber nachdachte, was hier wirklich vor sich geht.

    – Christian Rau

    10. August 2011 um 13:13 Uhr


  • Das Verhalten ist unter der Annahme von IEEE 754-Gleitkomma zu 100 % vorhersehbar. 0.7 wird am nächsten double (0,6999999999999999555910790149937383830547332763671875) und das umwandeln in float rundet auf den nächsten float Wert (0,699999988079071044921875).

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    10. August 2011 um 14:28 Uhr

  • @sasidhar: 0,7 dargestellt als Float wird gespeichert als 0.699999988079071044921875 und als Double gespeichert ist 0.699999999999999955591079014994 Es gibt also einen Unterschied von 0.000000011920928910669204014994 die während der Zuordnung verloren geht a Diese Informationen können nicht neu erstellt werden, wenn a wird in ein Doppel umgewandelt.

    – Martin York

    10. August 2011 um 16:10 Uhr

  • @sasidhar: Sie sollten davon ausgehen, dass alle Gleitkommazahlen nicht genau gespeichert werden und ein gewisser Informationsverlust auftritt. (Daher sollte der Vergleich von Gleitkommawerten nicht genau, sondern mit einer Fehlerspanne erfolgen). Beachten Sie, dass Sie möglicherweise ein anderes Ergebnis erhalten, wenn die Variablen herausoptimiert werden und alle Werte für die Dauer des Programms in Registern bleiben. Versuchen Sie, im Release-Modus zu kompilieren, wobei der Optimierer auf die höchste Stufe gestellt ist, und sehen Sie, ob sich die Ergebnisse ändern.

    – Martin York

    10. August 2011 um 16:15 Uhr

Das Problem ist, dass die Konstanten, mit denen Sie vergleichen, sind double nicht float. Ändern Sie auch Ihre Konstanten in etwas, das leicht darstellbar ist, z. B. einen Faktor von 5 wird es sagen 0 is right. Zum Beispiel,

main()
{
    float a=0.25,b=0.5; 
    if(a<.25) 
       {
       if(b<.5) 
               printf("2 are right");
       else
               printf("1 is right");
       }
else
printf("0 are right");
}

Ausgabe:

0 are right

Diese SO-Frage auf Der effektivste Weg für Gleitkomma- und Doppelvergleiche behandelt dieses Thema.

Auch dieser Artikel bei Cygnus weiter Vergleich von Gleitkommazahlen gibt uns Tipps:

Die IEEE Float- und Double-Formate wurden so konzipiert, dass die Zahlen „lexikographisch geordnet“ sind, was – in den Worten des IEEE-Architekten William Kahan – bedeutet „wenn zwei Fließkommazahlen im gleichen Format geordnet sind ( sagen wir x < y ), dann Sie werden auf die gleiche Weise geordnet, wenn ihre Bits als Vorzeichen-Größen-Ganzzahlen neu interpretiert werden.“

Das bedeutet, dass wir, wenn wir zwei Gleitkommazahlen in den Speicher nehmen, ihr Bitmuster als ganze Zahlen interpretieren und sie vergleichen, feststellen können, welche größer ist, ohne einen Gleitkommavergleich durchzuführen. In der Sprache C/C++ sieht dieser Vergleich so aus:

if (*(int*)&f1 < *(int*)&f2)

Diese charmante Syntax bedeutet, die Adresse von f1 zu nehmen, sie als Integer-Zeiger zu behandeln und sie zu dereferenzieren. All diese Zeigeroperationen sehen teuer aus, aber sie heben sich im Grunde alle auf und bedeuten nur “f1 als Ganzzahl behandeln”. Da wir dieselbe Syntax auf f2 anwenden, bedeutet die ganze Zeile „Vergleiche f1 und f2, wobei ihre In-Memory-Darstellungen als Integer statt Floats interpretiert werden“.

  • Der ganzzahlige Vergleich geht davon aus sizeof(int) == sizeof(float). Eine noch schlimmere Annahme im Umgang mit double.

    – Zan Luchs

    10. August 2011 um 16:10 Uhr

  • Es verstößt auch gegen die strikte Aliasing-Regel.

    – osgx

    11. August 2011 um 5:09 Uhr

Dies liegt an Rundungsproblemen beim Konvertieren von Float in Double

Flieskommavergleich duplicate
Richard Tingel

Im Allgemeinen ist der Vergleich von Gleichheit mit Gleitkommazahlen ein gefährliches Geschäft (was Sie praktisch tun, wenn Sie direkt an der Grenze von > vergleichen), denken Sie daran, dass bestimmte Brüche (wie 1/3) in Dezimalzahlen nicht genau gleich ausgedrückt werden können kann von binär gesagt werden,

0.5= 0.1ist in Float oder Double gleich.

0.7=0.10110011001100 usw. für immer, 0,7 kann nicht genau binär dargestellt werden, Sie erhalten Rundungsfehler und können (sehr, sehr geringfügig) zwischen Float und Double unterschiedlich sein

Beachten Sie, dass Sie zwischen Floats und Doubles eine unterschiedliche Anzahl von Dezimalstellen abschneiden, daher Ihre inkonsistenten Ergebnisse.

Übrigens, Sie haben einen Fehler in Ihrer Logik von 0, haben Recht. Sie überprüfen b nicht, wenn Sie 0 ausgeben, sind richtig. Aber das Ganze ist ein wenig mysteriös in dem, was Sie wirklich erreichen wollen. Gleitkomma-Vergleiche zwischen Floats und Doubles haben Abweichungen, Minute, also sollten Sie mit einer Delta-„akzeptablen“ Abweichung für Ihre Situation vergleichen. Ich habe das immer über Inline-Funktionen gemacht, die nur die Arbeit erledigen (habe es einmal mit einem Makro gemacht, aber das ist zu chaotisch). Wie auch immer, ja, bei dieser Art von Beispiel gibt es viele Rundungsprobleme. Lesen Sie das Gleitkomma-Zeug und wissen Sie, dass sich .7 von .7f unterscheidet und dass die Zuweisung von .7 zu einem Float ein Double in einen Float umwandelt und somit die genaue Art des Werts ändert. Aber die Programmierannahme, dass b falsch ist, seit Sie a überprüft haben, wurde mir ausgebrüllt, und das musste ich beachten 🙂

992770cookie-checkFließkommavergleich [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy