Es ist bekannt, dass sich NaNs in der Arithmetik ausbreiten, aber ich konnte keine Demonstrationen finden, deshalb schrieb ich einen kleinen Test:
#include <limits>
#include <cstdio>
int main(int argc, char* argv[]) {
float qNaN = std::numeric_limits<float>::quiet_NaN();
float neg = -qNaN;
float sub1 = 6.0f - qNaN;
float sub2 = qNaN - 6.0f;
float sub3 = qNaN - qNaN;
float add1 = 6.0f + qNaN;
float add2 = qNaN + qNaN;
float div1 = 6.0f / qNaN;
float div2 = qNaN / 6.0f;
float div3 = qNaN / qNaN;
float mul1 = 6.0f * qNaN;
float mul2 = qNaN * qNaN;
printf(
"neg: %f\nsub: %f %f %f\nadd: %f %f\ndiv: %f %f %f\nmul: %f %f\n",
neg, sub1,sub2,sub3, add1,add2, div1,div2,div3, mul1,mul2
);
return 0;
}
Das Beispiel ( hier live laufen ) liefert im Grunde das, was ich erwarten würde (das Negative ist etwas seltsam, aber es macht irgendwie Sinn):
neg: -nan
sub: nan nan nan
add: nan nan
div: nan nan nan
mul: nan nan
MSVC 2015 produziert etwas Ähnliches. Intel C ++ 15 produziert jedoch:
neg: -nan(ind)
sub: nan nan 0.000000
add: nan nan
div: nan nan nan
mul: nan nan
Speziell, qNaN - qNaN == 0.0
.
Das ... kann nicht richtig sein, oder? Was sagen die relevanten Standards (ISO C, ISO C ++, IEEE 754) dazu und warum gibt es einen Unterschied im Verhalten zwischen den Compilern?
Nan-NaN
istNaN
. Perl und Scala verhalten sich ebenfalls ähnlich.-ffast-math
on gcc)?Antworten:
Der Standard - Gleitkomma - Handling in Intel C ++ Compiler ist
/fp:fast
, die GriffeNaN
‚s unsafely (die auch Ergebnisse inNaN == NaN
sindtrue
zum Beispiel). Versuchen Sie,/fp:strict
oder anzugeben,/fp:precise
und prüfen Sie, ob dies hilfreich ist.quelle
/fp:fast
: Wenn Sie etwas Sicheres wollen , sollten Sie wahrscheinlich besser vermeiden, dass NaNs überhaupt auftauchen, und im Allgemeinen nicht==
mit Gleitkommazahlen verwenden. Sich auf die seltsame Semantik zu verlassen, die IEEE754 NaN zuweist, ist problematisch.NaN==NaN
zurückzukehrenfalse
?Dies . . . kann nicht richtig sein, richtig? Meine Frage: Was sagen die relevanten Normen (ISO C, ISO C ++, IEEE 754) dazu?
Petr Abdulin hat bereits geantwortet, warum der Compiler a gibt
0.0
Antwort .Folgendes sagt IEEE-754: 2008:
Das einzig gültige Ergebnis für die Subtraktion von zwei leisen NaN-Operanden ist also ein leises NaN; Jedes andere Ergebnis ist ungültig.
Der C-Standard sagt:
(wobei hier NaN ein leises NaN gemäß F.2.1p1 bezeichnet "Diese Spezifikation definiert nicht das Verhalten der Signalisierung von NaNs. Sie verwendet im Allgemeinen den Begriff NaN, um ruhige NaNs zu bezeichnen")
quelle
Da ich eine Antwort sehe, die die Einhaltung der Standards des Intel-Compilers in Frage stellt, und niemand anderes dies erwähnt hat, möchte ich darauf hinweisen, dass sowohl GCC als auch Clang einen Modus haben, in dem sie etwas ganz Ähnliches tun. Ihr Standardverhalten ist IEEE-konform -
- aber wenn Sie auf Kosten der Korrektheit nach Geschwindigkeit fragen, bekommen Sie, wonach Sie fragen -
Ich denke, es ist völlig fair, die Wahl des ICC als Standard zu kritisieren , aber ich würde nicht die gesamten Unix-Kriege in diese Entscheidung zurücklesen.
quelle
-ffast-math
,gcc
einhält nicht nach ISO 9899: 2011 in Bezug auf arithmetische Gleitkomma mehr.