负NaN不是NaN?

时间:2010-08-29 21:13:31

标签: c++ nan fast-math

在编写一些测试用例时,有些测试会检查NaN的结果。

我尝试使用std::isnan,但断言失败:

Assertion `std::isnan(x)' failed.

在打印x的值后,结果显示它是负NaN(-nan),这在我的情况下是完全可以接受的。

在尝试使用NaN != NaN并使用assert(x == x)这一事实后,编译器为我做了一个'恩惠'并优化了断言。

正在优化我自己的isNaN功能。

如何检查NaN -NaN?

的相等性

6 个答案:

答案 0 :(得分:32)

这令人尴尬。

编译器(在这种情况下是GCC)正在优化比较而isnan返回false的原因是因为我团队中的某个人已开启-ffast-math

来自文档:

-ffast-math
    Sets -fno-math-errno, -funsafe-math-optimizations,
    -fno-trapping-math, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans and fcx-limited-range.

    This option causes the preprocessor macro __FAST_MATH__ to be defined.

    This option should never be turned on by any -O option since it can result in incorrect output for programs which depend on an exact implementation of IEEE or ISO rules/specifications for math functions. 

注意结束语 - -ffast-math是不安全的。

答案 1 :(得分:4)

isnan()预计会有-ffast-math的未定义行为。

这是我在测试套件中使用的内容:

#if defined __FAST_MATH__
#   undef isnan
#endif
#if !defined isnan
#   define isnan isnan
#   include <stdint.h>
static inline int isnan(float f)
{
    union { float f; uint32_t x; } u = { f };
    return (u.x << 1) > 0xff000000u;
}
#endif

答案 2 :(得分:1)

这看起来像是图书馆向我isnan()实施的错误。它在Snow Leopard上的gcc 4.2.1上工作正常。但是,尝试这个呢?

std::isnan(std::abs(yourNanVariable));

显然,我无法测试,因为std::isnan(-NaN)在我的系统上是true

编辑:使用-ffast-math,无论-O切换,Snow Leopard上的gcc 4.2.1都认为NAN == NANtrue, {是NAN == -NAN。这可能会破坏灾难性的代码。我建议不要使用-ffast-math或者至少在使用和不使用它的构建中测试相同的结果......

答案 3 :(得分:0)

你应该可以使用C99 isnan()。

如果在你的实现中它不能正常工作(哪一个是?)你可以实现自己的,通过reinterpret_casting到long并做IEEE bit魔术。

答案 4 :(得分:0)

您可以查看数字位。 IEEE 754已为NaN定义了掩码:

  • 信号NaN由X'7F80 0001'和X'7FBF FFFF'之间或X'FF80 0001'和X'FFBF FFFF'之间的任何位模式表示。
  • 安静的NaN由X'7FC0 0000'和X'7FFF FFFF'之间或X'FFC0 0000'和X'FFFF FFFF'之间的任何位模式表示。

这可能不是便携式的,但如果你确定你的平台,那就可以接受了。更多:http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlf101l.doc/xlfopg/fpieee.htm

答案 5 :(得分:-3)

这是基于评论中发布的维基百科文章。请注意,它完全未经测试 - 它应该让您了解可以做的事情。

bool reallyIsNan(float x)
{
    //Assumes sizeof(float) == sizeof(int)
    int intIzedX = *(reinterpret_cast<int *>(&x));
    int clearAllNonNanBits = intIzedX & 0x7F800000;
    return clearAllNonNanBits == 0x7F800000;
}

编辑:我真的认为你应该考虑在那个问题上向GLIBc人员提交一个错误。