IEEE754要求NaNs无序;当一个或两个操作数都是NaN时,小于,大于,等等都应该返回false。
下面的示例在使用g ++在所有优化级别编译时,以及在使用VC ++的CL.exe(32位版本15.00.30729.01)编译时,没有优化参数或任何组合的情况下产生正确的F F F F F T
。 / od,/ fp:fast,/ arch:SSE。
但是,当使用/ O1或/ O2(以及任何其他优化参数)编译时,T T F F F T
结果,即使指定了/ Op也是如此。
64位版本的CL.exe产生了许多变体 - T T F F F T
,T T T F F T
,T T T F F F
等 - 取决于优化级别以及是否指定了/ fp:fast,但是对于32位版本,只有在禁用所有优化的情况下才能实现符合规定的行为。
我犯了一些明显的错误吗?有没有办法让编译器在不牺牲所有其他优化的情况下遵守标准?
#include <limits>
#include <stdio.h>
int main( int argc, char const ** argv )
{
float test = std::numeric_limits<float>::quiet_NaN();
printf( "%c %c %c %c %c %c\n",
(test < test) ? 'T' : 'F',
(test <= test) ? 'T' : 'F',
(test == test) ? 'T' : 'F',
(test > test) ? 'T' : 'F',
(test >= test) ? 'T' : 'F',
(test != test) ? 'T' : 'F'
);
return 0;
}
重现问题的示例build.cmd
:
set "PATH=c:\program files (x86)\Microsoft Visual Studio 9.0\VC\bin\amd64;c:\program files (x86)\Microsoft Visual Studio 9.0\Common7;c:\program files (x86)\Microsoft Visual Studio 9.0\Common7\IDE"
set "LIB=c:\program files (x86)\microsoft visual studio 9.0\vc\lib\x64;c:\program files\Microsoft SDKs\Windows\v6.0A\Lib\x64"
cl test.cpp /fp:fast /Od /c /I "c:\program files (x86)\microsoft visual studio 9.0\vc\include"
link "/LIBPATH:C:/Program Files (x86)/Microsoft Visual Studio 9.0/vc/lib/amd64" "/LIBPATH:C:\Program Files\Microsoft SDKs\Windows\v6.0A\/Lib/x64" /DEBUG /IGNORE:4199 /IGNORE:4221 /MACHINE:X64 /SUBSYSTEM:CONSOLE test.obj
test
修改
对于记录,最初在问题中给出的示例
inline float QNaN()
{
static int const QNaNValue = 0x7fc00000;
return *(reinterpret_cast<float const*>(&QNaNValue));
}
产生NaN;正如一些注释和答案所指出的,这是未定义的行为,并用std :: numeric_limits :: quiet_NaN()替换它实际上修复了某些版本的32位CL.exe的问题
答案 0 :(得分:5)
总而言之,有许多不同的问题:
原始示例代码违反了严格别名,从而产生了未定义的行为。修复此问题足以解决某些版本的32位编译器的问题。
修复了该问题,删除/fp:fast
解决了我可用的32位和64位编译器的所有版本的问题
Martinho提到即使使用/fp:fast
答案 1 :(得分:4)
您通过将int*
强制转换为float*
来调用未定义的行为。我已经使用std::numeric_limits<float>::quiet_NaN()
而不是强制转换使用VS 2010尝试了您的代码,它使用false
和{{1}给出了预期结果(除了最后一个/O2
之外) }}
<强>更新强>
我已将修改后的示例复制粘贴到VS 2010和VS 2005中。在这两者中,32位编译器生成正确的结果(/fp:fast
),而64位编译器则不生成。F F F F F T
。
答案 2 :(得分:4)
这是因为QNaN函数通过违反严格别名来调用UB。 VS编译器完全有权产生任何行为。
答案 3 :(得分:0)
我相信您正在寻找/fp:strict
选项。
您可能还需要float_control
pragma。
所有这些都在“按类别编译选项”
下的文档中是正确的