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