在编写一些测试用例时,有些测试会检查NaN的结果。
我尝试使用std::isnan
,但断言失败:
Assertion `std::isnan(x)' failed.
在打印x
的值后,结果显示它是负NaN(-nan
),这在我的情况下是完全可以接受的。
在尝试使用NaN != NaN
并使用assert(x == x)
这一事实后,编译器为我做了一个'恩惠'并优化了断言。
正在优化我自己的isNaN
功能。
如何检查NaN 和 -NaN?
的相等性答案 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 == NAN
是true
, {是NAN == -NAN
。这可能会破坏灾难性的代码。我建议不要使用-ffast-math
或者至少在使用和不使用它的构建中测试相同的结果......
答案 3 :(得分:0)
你应该可以使用C99 isnan()。
如果在你的实现中它不能正常工作(哪一个是?)你可以实现自己的,通过reinterpret_casting到long并做IEEE bit魔术。
答案 4 :(得分:0)
您可以查看数字位。 IEEE 754已为NaN定义了掩码:
这可能不是便携式的,但如果你确定你的平台,那就可以接受了。更多: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人员提交一个错误。