VC ++ Optimierungen brechen Vergleiche mit NaN?

8

Nach IEEE754 müssen NaNs ungeordnet sein; kleiner als, größer als, gleich usw. sollten alle falsch zurückgeben, wenn einer oder beide Operanden NaN sind.

Das folgende Beispiel liefert das korrekte F F F F F T wie erwartet, wenn es mit g ++ auf allen Optimierungsebenen kompiliert wird und mit CL ++.exe (32-Bit Version 15.00.30729.01) von VC ++ ohne Optimierungsargumente oder eine Kombination aus / Od kompiliert wird , / fp: schnell, / arch: SSE.

Wenn jedoch mit / O1 oder / O2 (und / oder anderen Optimierungsargumenten) kompiliert wird, ergibt sich T T F F F T , auch wenn / Op ebenfalls angegeben ist.

Die 64-Bit-Version von CL.exe bietet viele Variationen - T T F F F T , T T T F F T , T T T F F F usw. - abhängig von der Optimierungsstufe und ob / fp: fast angegeben ist, aber wie bei der 32-Bit-Version , konformes Verhalten scheint nur bei deaktivierter Optimierung möglich zu sein.

Mache ich einen offensichtlichen Fehler? Gibt es eine Möglichkeit, den Compiler dazu zu veranlassen, die Standards zu erfüllen, ohne dabei alle anderen Optimierungen zu opfern?

%Vor%

Ein Beispiel build.cmd , das das Problem reproduziert:

%Vor%

BEARBEITEN

Für das Protokoll wurde das ursprünglich in der Frage angegebene Beispiel verwendet

%Vor%

um ein NaN zu erzeugen; Wie eine Reihe von Kommentaren und Antworten darauf hinweist, ist dies ein undefiniertes Verhalten, und das Ersetzen durch std :: numeric_limits :: quiet_NaN () hat das Problem für einige Versionen der 32-Bit-CL.exe

behoben     
moonshadow 03.04.2013, 11:52
quelle

4 Antworten

5

Zusammenfassend gab es eine Reihe von separaten Problemen:

  • Der ursprüngliche Beispielcode ergab ein undefiniertes Verhalten, indem er striktes Aliasing verletzte. Dies zu beheben war ausreichend, um das Problem für einige Versionen des 32-Bit-Compilers zu lösen.

  • mit diesem Problem behoben, entfernt /fp:fast das Problem für alle Versionen der 32-Bit-und 64-Bit-Compiler für mich verfügbar

  • Martinho erwähnt, dass das Problem in cl 16.0 nicht mehr existiert, auch nicht mit /fp:fast

moonshadow 03.04.2013 12:31
quelle
4

Das liegt daran, dass die QNaN-Funktion UB aufruft, indem sie striktes Aliasing verletzt. Der VS-Compiler ist gut in seinem Recht, jedes Verhalten zu erzeugen.

    
Puppy 03.04.2013 12:03
quelle
4

Sie rufen undefiniertes Verhalten auf, indem Sie int* auf float* umwandeln. Ich habe Ihren Code mit VS 2010 ausprobiert, wobei std::numeric_limits<float>::quiet_NaN() anstelle der Besetzung verwendet wurde, und es gab das erwartete Ergebnis (alle außer der letzten waren false ) mit /O2 und /fp:fast .

AKTUALISIEREN

Ich habe das überarbeitete Beispiel in VS 2010 und VS 2005 kopiert. In beiden Fällen liefert der 32-Bit-Compiler korrekte Ergebnisse ( F F F F F T ), während der 64-Bit-Compiler keine Ergebnisse liefert.

p>     
Angew 03.04.2013 12:03
quelle
0

Ich glaube, Sie suchen nach der Option /fp:strict .

Vielleicht möchten Sie auch das Pragma float_control .

All das war richtig in der Dokumentation unter "Compileroptionen nach Kategorie"

Ben 03.04.2013 12:17
quelle