如果任一参数为 NaN,啥会导致 C/C++ <、<= 和 == 运算符返回 true?
Posted
技术标签:
【中文标题】如果任一参数为 NaN,啥会导致 C/C++ <、<= 和 == 运算符返回 true?【英文标题】:What would cause the C/C++ <, <=, and == operators to return true if either argument is NaN?如果任一参数为 NaN,什么会导致 C/C++ <、<= 和 == 运算符返回 true? 【发布时间】:2014-07-01 17:38:58 【问题描述】:我对 IEEE-754 浮点比较规则的理解是,除了 !=
之外的所有比较运算符,如果其中一个或两个参数都是 NaN,则将返回 false,而 !=
运算符将返回 true。我可以通过简单的独立测试轻松重现此行为:
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(!=)
这会打印出预期的结果:(NaN 在 MSVC 运行时被格式化为 -1.$
)
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
但是,当我将这段代码粘贴到应用程序的内部循环的深处时,所有浮点计算都在其中执行,我得到了这些莫名其妙的结果:
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
由于某种原因,<
、<=
和 ==
运算符在其中一个或两个参数为 NaN 时意外返回 true。此外,!=
运算符意外返回 false。
这是 64 位代码,使用 Visual Studio 2010 构建,在 Intel Xeon E5-2650 上运行。使用_mm_getcsr()
,我已确认 CSR 寄存器在两种情况下都保持相同的值。
还有什么可以像这样影响浮点数学的行为?
【问题讨论】:
我讨厌只提供 Dilbert 的名言,但“这是五分钱,孩子。让自己成为一个更好的编译器” 您确定他们的传统准 C89 模式被宣传为符合 IEEE-754?无论如何,您是否启用了快速数学或类似功能? 似乎你的编译器为了性能而抛出了规范的某些部分...... 似乎编译器假设它可以通过假设 a = b 相反来节省一条比较指令。没关系,在这种情况下它会产生无意义的结果。 @gnasher729:这是一个很好的假设。我怀疑 sean 的应用程序的内部循环是在 VS 等效的 -ffinite-math 下编译的,这将允许这种行为。 【参考方案1】:此行为是由于/fp:fast
MSVC 编译器选项造成的,该选项(除其他外)允许编译器执行比较而不考虑正确的 NaN 行为,以生成更快的代码。使用 /fp:precise
或 /fp:strict
会导致这些比较在出现 NaN 参数时按预期进行。
【讨论】:
+1 并添加了链接。请记住,您也可以使用#pragma float_control
为特定代码部分设置此行为。
奇怪的是,/fp:fast
选项只会在更大的应用程序上下文中触发这种无效的 NaN 行为。当我在独立的main()
函数中将/fp:fast
应用于此代码时,它的行为正确。
谢谢@BillyONEal,这正是我所需要的。很少有代码需要严格的 NaN 处理。以上是关于如果任一参数为 NaN,啥会导致 C/C++ <、<= 和 == 运算符返回 true?的主要内容,如果未能解决你的问题,请参考以下文章
virtualenvwrapper 安装失败 - “啥会导致 ImportError:没有名为核心的模块”等?
MSMQ:从队列接收时,啥会导致“资源不足以执行操作”错误?
在 windbg 中,啥会导致消息“警告:无法验证 mydll.dll 的时间戳”?
在 os.system() 期间,啥会导致“IOError: [Errno 9] Bad file descriptor”?