Was würde bewirken, dass die C/C++-Operatoren

Lesezeit: 3 Minuten

Mein Verständnis der Regeln von IEEE-754-Gleitkommavergleichen ist, dass alle Vergleichsoperatoren außer != gibt false zurück, wenn eines oder beide Argumente NaN sind, während die != Der Operator gibt true zurück. Ich kann dieses Verhalten leicht mit einem einfachen eigenständigen Test reproduzieren:

for (int ii = 0; ii < 4; ++ii)
{
    float a = (ii & 1) != 0 ? NAN : 1.0f;
    float b = (ii & 2) != 0 ? NAN : 2.0f;
    #define TEST(OP) printf("%4.1f %2s %4.1f => %s\n", a, #OP, b, a OP b ? "true" : "false");
    TEST(<)
    TEST(>)
    TEST(<=)
    TEST(>=)
    TEST(==)
    TEST(!=)
}

Dies gibt die erwarteten Ergebnisse aus: (NaN ist formatiert als -1.$ in der MSVC-Laufzeit)

 1.0  <  2.0 => true
 1.0  >  2.0 => false
 1.0 <=  2.0 => true
 1.0 >=  2.0 => false
 1.0 ==  2.0 => false
 1.0 !=  2.0 => true
-1.$  <  2.0 => false
-1.$  >  2.0 => false
-1.$ <=  2.0 => false
-1.$ >=  2.0 => false
-1.$ ==  2.0 => false
-1.$ !=  2.0 => true
 1.0  < -1.$ => false
 1.0  > -1.$ => false
 1.0 <= -1.$ => false
 1.0 >= -1.$ => false
 1.0 == -1.$ => false
 1.0 != -1.$ => true
-1.$  < -1.$ => false
-1.$  > -1.$ => false
-1.$ <= -1.$ => false
-1.$ >= -1.$ => false
-1.$ == -1.$ => false
-1.$ != -1.$ => true

Wenn ich diesen Codeabschnitt jedoch in die Tiefen der inneren Schleifen meiner Anwendung einfüge, in denen alle Gleitkommaberechnungen durchgeführt werden, erhalte ich diese unerklärlichen Ergebnisse:

 1.0  <  2.0 => true
 1.0  >  2.0 => false
 1.0 <=  2.0 => true
 1.0 >=  2.0 => false
 1.0 ==  2.0 => false
 1.0 !=  2.0 => true
-1.$  <  2.0 => true
-1.$  >  2.0 => false
-1.$ <=  2.0 => true
-1.$ >=  2.0 => false
-1.$ ==  2.0 => true
-1.$ !=  2.0 => false
 1.0  < -1.$ => true
 1.0  > -1.$ => false
 1.0 <= -1.$ => true
 1.0 >= -1.$ => false
 1.0 == -1.$ => true
 1.0 != -1.$ => false
-1.$  < -1.$ => true
-1.$  > -1.$ => false
-1.$ <= -1.$ => true
-1.$ >= -1.$ => false
-1.$ == -1.$ => true
-1.$ != -1.$ => false

Aus irgendeinem Grund ist die <, <=und == Operatoren geben unerwartet wahr zurück, wenn eines oder beide Argumente NaN sind. Außerdem die != Der Operator gibt unerwartet false zurück.

Dies ist 64-Bit-Code, der mit Visual Studio 2010 erstellt wurde und auf einem Intel Xeon E5-2650 ausgeführt wird. Verwenden _mm_getcsr()habe ich bestätigt, dass das CSR-Register in beiden Szenarien denselben Wert enthält.

Was sonst könnte das Verhalten von Gleitkomma-Mathematik so beeinflussen?

  • Ich hasse es, nur ein Dilbert-Zitat anbieten zu können, aber „hier ist ein Nickel, Kleiner. Holen Sie sich einen besseren Compiler“

    – Pascal Cuoq

    13. Mai 2014 um 21:11 Uhr

  • Sind Sie sicher, dass ihr Legacy-Quasi-C89-Modus als IEEE-754-konform beworben wird? Wie auch immer, hast du Fast-Mathematik oder ähnliches aktiviert?

    – Deduplizierer

    13. Mai 2014 um 21:13 Uhr


  • Scheint, als ob Ihr Compiler einige Teile der Spezifikation für die Leistung wirft …

    – Synxis

    13. Mai 2014 um 21:13 Uhr

  • Scheint, als hätte der Compiler angenommen, dass er eine Vergleichsanweisung sparen könnte, indem er annimmt, dass a < b das Gegenteil von a > = b ist. Es macht nichts, dass es in diesem Fall unsinnige Ergebnisse liefert.

    – gnasher729

    13. Mai 2014 um 21:16 Uhr

  • @gnasher729: Das ist eine ausgezeichnete Hypothese. Ich vermute, dass die inneren Schleifen von Seans Anwendung unter dem VS-Äquivalent von -finite-math kompiliert werden, was dieses Verhalten zulassen würde.

    – Stefan Kanon

    13. Mai 2014 um 21:19 Uhr

Benutzeravatar von Sean
Sean

Dieses Verhalten ist auf die /fp:fast MSVC-Compileroption, die es dem Compiler (unter anderem) ermöglicht, Vergleiche ohne Berücksichtigung des richtigen NaN-Verhaltens durchzuführen, um schnelleren Code zu generieren. Verwenden /fp:precise oder /fp:strict bewirkt stattdessen, dass sich diese Vergleiche wie erwartet verhalten, wenn sie mit NaN-Argumenten präsentiert werden.

  • +1 und Links hinzugefügt. Denken Sie daran, dass Sie dieses Verhalten für bestimmte Codeabschnitte mit festlegen können #pragma float_control zu.

    – Billy ONeal

    13. Mai 2014 um 22:29 Uhr

  • Seltsamerweise die /fp:fast Option löst dieses ungültige NaN-Verhalten nur im Kontext einer größeren Anwendung aus. Wenn ich mich bewerbe /fp:fast zu diesem Code in einem eigenständigen main() funktionieren, es hat sich richtig verhalten.

    – Sean

    13. Mai 2014 um 22:31 Uhr


  • Danke @BillyONeal, genau das habe ich gebraucht. Sehr wenig Code erfordert eine strikte NaN-Behandlung.

    – Sean

    13. Mai 2014 um 22:39 Uhr

1403030cookie-checkWas würde bewirken, dass die C/C++-Operatoren

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

Privacy policy