在编写一些测试用例时,一些测试会检查 NaN 的结果。
我尝试使用std::isnan
但断言失败:
Assertion `std::isnan(x)' failed.
打印 的值后x
,结果发现它是负的 NaN ( -nan
),这在我的情况下是完全可以接受的。
在尝试使用NaN != NaN
和使用事实之后assert(x == x)
,编译器帮了我一个“忙”并优化了断言。
制作我自己的isNaN
功能也被优化掉了。
如何检查 NaN和-NaN 的相等性?
这很尴尬。
编译器(在本例中为 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
是不安全的。
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
您应该可以使用 C99 isnan()。
如果在您的实现中它不能正常工作(那是哪一个?)您可以通过 reinterpret_casting 到 long 并执行 IEEE 位魔术来实现自己的。
对我来说,这看起来像是您的库实现中的一个错误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 == NAN
是true
这样NAN == -NAN
。这可能会灾难性地破坏代码。我建议-ffast-math
在使用和不使用它的构建中停止或至少测试相同的结果......
您可以检查数字的位数。IEEE 754 为 NaN 定义了掩码:
这可能不是便携式的,但如果您确定您的平台,它是可以接受的。更多: http: //publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp ?topic=/com.ibm.xlf101l.doc/xlfopg/fpieee.htm
这是基于评论中发布的维基百科文章。请注意,它完全未经测试——它应该让您对可以做的事情有所了解。
bool reallyIsNan(float x)
{
//Assumes sizeof(float) == sizeof(int)
int intIzedX = *(reinterpret_cast<int *>(&x));
int clearAllNonNanBits = intIzedX & 0x7F800000;
return clearAllNonNanBits == 0x7F800000;
}
编辑:我真的认为你应该考虑向 GLibc 的家伙提交一个错误。