31

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

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

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

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

在尝试使用NaN != NaN和使用事实之后assert(x == x),编译器帮了我一个“忙”并优化了断言。

制作我自己的isNaN功能也被优化掉了。

如何检查 NaN-NaN 的相等性?

4

6 回答 6

42

这很尴尬。

编译器(在本例中为 GCC)优化比较并isnan返回false的原因是因为我团队中有人打开了-ffast-math.

从文档:

-ffast-数学
    设置 -fno-math-errno、-funsafe-math-optimizations、
    -fno-trapping-math、-ffinite-math-only、-fno-rounding-math、-fno-signaling-nans 和 fcx-limited-range。

    此选项导致定义预处理器宏 __FAST_MATH__。

    任何 -O 选项都不应打开此选项,因为它可能导致依赖于数学函数的 IEEE 或 ISO 规则/规范的精确实现的程序的错误输出。

注意结尾的句子 --ffast-math是不安全的。

于 2010-08-29T21:51:04.007 回答
5

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
于 2011-09-17T14:29:47.280 回答
1

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

如果在您的实现中它不能正常工作(那是哪一个?)您可以通过 reinterpret_casting 到 long 并执行 IEEE 位魔术来实现自己的。

于 2010-08-29T21:26:26.693 回答
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在使用和不使用它的构建中停止或至少测试相同的结果......

于 2010-08-29T21:52:58.047 回答
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

于 2010-08-29T21:30:24.227 回答
-3

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

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

编辑:我真的认为你应该考虑向 GLibc 的家伙提交一个错误。

于 2010-08-29T21:30:19.590 回答