9

IEEE754 要求 NaN 是无序的;当一个或两个操作数为 NaN 时,小于、大于、等于等都应该返回 false。

F F F F F T当在所有优化级别使用 g++ 编译时,以及使用 VC++ 的 CL.exe(32 位版本 15.00.30729.01)编译时没有优化参数或 /Od、/fp:fast 、/拱:SSE。

但是,当使用 /O1 或 /O2(以及任何/没有其他优化参数)编译时T T F F F T,即使使用 /Op 也会产生结果。

64 位版本的 CL.exe 产生许多变体 - T T F F F T,T T T F F TT 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 版本的问题

4

4 回答 4

5

因此,总而言之,有许多不同的问题:

  • 原始示例代码通过违反严格的别名产生了未定义的行为。修复此问题足以解决某些 32 位编译器版本的问题。

  • 修复了该问题后,删除/fp:fast解决了我可用的 32 位和 64 位编译器的所有版本的问题

  • Martinho 提到这个问题在 cl 16.0 中不再存在,即使/fp:fast

于 2013-04-03T12:31:24.367 回答
4

您通过强制转换int*to 来调用未定义的行为float*。我已经用 VS 2010 尝试了你的代码,使用std::numeric_limits<float>::quiet_NaN()而不是强制转换,它给出了预期的结果(除了最后一个是false/O2/fp:fast

更新

我已将修改后的示例复制粘贴到 VS 2010 和 VS 2005 中。在这两个版本中,32 位编译器都会产生正确的结果 ( F F F F F T),而 64 位编译器则不会。

于 2013-04-03T12:03:47.160 回答
4

这是因为 QNaN 函数通过违反严格的别名来调用 UB。VS 编译器完全有权产生任何行为。

于 2013-04-03T12:03:57.367 回答
0

我相信您正在寻找/fp:strict选择。

您可能还需要float_control编译指示。

所有这些都在“按类别编译器选项”下的文档中

于 2013-04-03T12:17:47.793 回答