C++ 负的NaN不是NaN?

C++ 负的NaN不是NaN?,c++,nan,fast-math,C++,Nan,Fast Math,在编写一些测试用例时,一些测试检查NaN的结果 我尝试使用std::isnan但断言失败: Assertion `std::isnan(x)' failed. 打印了x的值后,结果是负NaN(-NaN),这在我的情况下是完全可以接受的 在尝试使用NaN!=NaN并使用断言(x==x),编译器帮了我一个“忙”,并优化了断言 制作我自己的isNaN功能也在进行优化 如何检查NaN和-NaN是否相等?有一个C99 isnan(),您应该可以使用它 如果在你的实现中它不能正常工作(那是哪一个?),你可

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

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

Assertion `std::isnan(x)' failed.
打印了
x
的值后,结果是负NaN(
-NaN
),这在我的情况下是完全可以接受的

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

制作我自己的
isNaN
功能也在进行优化

如何检查NaN和-NaN是否相等?

有一个C99 isnan(),您应该可以使用它


如果在你的实现中它不能正常工作(那是哪一个?),你可以实现你自己的,方法是重新解释“长”并执行IEEE位魔术。

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

bool reallyIsNan(float x)
{
    //Assumes sizeof(float) == sizeof(int)
    int intIzedX = *(reinterpret_cast<int *>(&x));
    int clearAllNonNanBits = intIzedX & 0x7F800000;
    return clearAllNonNanBits == 0x7F800000;
}
bool reallyIsNan(浮点x)
{
//假设sizeof(float)=sizeof(int)
int intIzedX=*(重新解释铸造(&x));
int clearlallnonnanbits=intIzedX&0x7f80000;
返回ClearAllNonnabits==0x7F800000;
}

编辑:我真的认为你应该考虑在这一点上和GLibc的家伙一起犯错误。

< P>你可以检查数字的位数。IEEE 754定义了NaN的掩码:

  • 信令NaN由X'7F80 0001'和X'7FBF FFFF'之间或X'FF80 0001'和X'FFBF FFFF'之间的任何位模式表示
  • 安静的NaN由X'7FC0 0000'和X'7FFF FFFF'之间或X'FFC00000'和X'FFFF FFFF'之间的任何位模式表示
这可能是不可移植的,但如果您确信您的平台是可以接受的。更多信息:

这太尴尬了

编译器(在本例中为GCC)优化比较并返回
isnan
的原因是我的团队中有人打开了
-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. -法斯特数学 设置-fno math errno,-funsafe数学优化, -fno捕获数学,-仅限FNITE数学,-fno舍入数学,-fno信令NAN和fcx有限范围。 此选项导致定义预处理器宏\uuuu FAST\u MATH\uuuu。 任何-O选项都不应打开此选项,因为它可能导致程序的输出不正确,而这些程序依赖于数学函数的IEEE或ISO规则/规范的精确实现。
注意结尾的句子-
-ffast math
是不安全的。

在我看来,这似乎是您的库的
isnan()
实现中的一个错误。在gcc 4.2.1中,它在雪豹上运行良好。但是,试试这个怎么样

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

编辑:使用
-ffast math
,无论
-O
开关如何,雪豹上的gcc 4.2.1都认为
NAN==NAN
真的
,就像
NAN=-NAN
一样。这可能会严重破坏代码。我建议停止使用
-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
#如果定义uu快速u数学__
#艾斯南酒店
#恩迪夫
#如果!伊斯南
#定义isnan isnan
#包括
静态内联int-isnan(浮点f)
{
并集{float f;uint32_t x;}u={f};
返回(u.x 0xff000000u;
}
#恩迪夫

o_o?负的NaN就是NaN。你能展示一下你是如何编写自己的
isNaN
,如果你有编译器的内置版本的话,你可以展示一下吗?测试NaN的一种方法(正如你所注意到的,有几种)是在(指数是11..11)处测试位模式。@KennyTM来自维基百科:“由于在实践中,编码的NaN同时具有符号和可选的‘诊断信息’(有时称为有效负载),因此这些信息通常也可以在NaN的字符串表示中找到,例如:-NaN"。有一个NaN或许多NaN取决于您想如何看待它,此编译器打印它的方式可能更令人困惑,而不是有用。对我来说,这闻起来像是您的标准库实现的
std::isnan
中的一个错误。考虑到我已经听到的一些恐怖故事,我甚至连我自己都没有发现这种错误的想法n glibc令人惊讶。这是善意的,别误会我,但编译器作者长期以来都犯了浮点错误。这将是我最后的选择,我仍在努力寻找最可移植的解决方案。@LiraNuna这并不是那么简单。如果你在实现它时牢记endiannes,它将是可移植的。我刚刚注意到当MS编译器与/fp:fast flag一起使用时,也会出现同样的问题。但与/fp:precise一起使用时效果很好。对于
Inf
,这也会返回
true
。@Sam:正如我所说,我没有测试它,我是从维基百科获得的。我从未对它的正确性发表过任何声明。无论如何,OP已经回答了这个问题。我不明白我们为什么要这么做我问了一个1.5年的问题,这个问题已经被标记为“已回答”,并对此进行抱怨。我不是在抱怨,你是。我在谷歌搜索中发现了这个问题,但没有令人满意的答案。我对不正确或不完整的答案进行评论,因为我不想让其他人花时间去找出他们不正确或不完整的原因.而且,批准的答案给出的是解释,而不是解决方案。这个问题有多老完全没有关系。如果你有问题,你可能错过了这个网站的重点。放松点,伙计。哦,顺便说一句,我还认为负面评论比不加评论就投反对票要文明一个数量级nswer不提供任何细节,也不提供解决问题的方法。请投反对票