首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NAN差异- std::nan vs quiet_NaN() vs Macro

NAN差异- std::nan vs quiet_NaN() vs Macro
EN

Stack Overflow用户
提问于 2020-04-16 15:23:07
回答 1查看 475关注 0票数 2

我想知道以下类型的nan之间有什么区别。除了NAN_macro的视觉差异(它的计算结果为-nan(ind),而不是nan)之外,它们的行为似乎都是一样的(如下面的示例脚本所示)。

我看了一下其他一些答案,例如安静的NaN和信号NaN有什么区别?。但我仍然不太明白为什么NAN-nan(ind),而std::numeric_limits<double>::quiet_NaN()nan,或者为什么我们有std::nan("")std::nan("1"),如果最终它们看起来都是相同的概念。

任何解释或澄清联系将是很好的。

代码语言:javascript
复制
#include <cmath>
#include <limits>

int main()
{
    using num_lim = std::numeric_limits<double>;

    const double NAN_macro   = static_cast<double>(NAN);  // -nan(ind)
    const double NAN_quiet   = num_lim::quiet_NaN();      // nan
    const double NAN_sig     = num_lim::signaling_NaN();  // nan
    const double NAN_str     = std::nan("");              // nan
    const double NAN_str1    = std::nan("1");             // nan
    const double NAN_strLong = std::nan("some string");   // nan

    const bool isnan_macro   = std::isnan(NAN_macro);    // true
    const bool isnan_quiet   = std::isnan(NAN_quiet);    // true
    const bool isnan_sig     = std::isnan(NAN_sig);      // true
    const bool isnan_str     = std::isnan(NAN_str);      // true
    const bool isnan_str1    = std::isnan(NAN_str1);     // true
    const bool isnan_strLong = std::isnan(NAN_strLong);  // true

    const bool not_equal_macro   = (NAN_macro   != NAN_macro);   // true
    const bool not_equal_quiet   = (NAN_quiet   != NAN_quiet);   // true
    const bool not_equal_sig     = (NAN_sig     != NAN_sig);     // true
    const bool not_equal_str     = (NAN_str     != NAN_str);     // true
    const bool not_equal_str1    = (NAN_str1    != NAN_str1);    // true
    const bool not_equal_strLong = (NAN_strLong != NAN_strLong); // true

    const double sum_macro   = 123.456 + NAN_macro;    // -nan(ind)
    const double sum_quiet   = 123.456 + NAN_quiet;    // nan
    const double sum_sig     = 123.456 + NAN_sig;      // nan
    const double sum_str     = 123.456 + NAN_str;      // nan
    const double sum_str1    = 123.456 + NAN_str1;     // nan
    const double sum_strLong = 123.456 + NAN_strLong;  // nan
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-20 19:49:54

IEEE 754用比特模式表示NaN,其指数为所有1s和非零分数(请注意,所有浮点十进制值都由“符号”、“指数”和“分数”表示),然后,您可以表示许多不同的NaN,因为“非零分数”可能有很多不同的值。

要突出显示您的NaN表示,请使用以下内容扩展代码:

代码语言:javascript
复制
#include <cmath>
#include <limits>
#include <bitset>
#include <iostream>

union udouble {
  double d;
  unsigned long long u;
};

void Display(double doubleValue, char* what)
{
    udouble ud;
    ud.d = doubleValue;
    std::bitset<sizeof(double) * 8> b(ud.u);
    std::cout << "BitSet : " << b.to_string() << " for " << what << std::endl;
}

int main()
{
    using num_lim = std::numeric_limits<double>;

    const double NAN_macro   = static_cast<double>(NAN);  // -nan(ind)
    const double NAN_quiet   = num_lim::quiet_NaN();      // nan
    const double NAN_sig     = num_lim::signaling_NaN();  // nan
    const double NAN_str     = std::nan("");              // nan
    const double NAN_str1    = std::nan("1");             // nan
    const double NAN_strLong = std::nan("some string");   // nan

    ...

    Display( NAN_macro, "NAN_macro" );
    Display( NAN_quiet, "NAN_quiet" );
    Display( NAN_sig, "NAN_sig" );
    Display( NAN_str, "NAN_str" );
    Display( NAN_str1, "NAN_str1" );
    Display( NAN_strLong, "NAN_strLong" );
}

即使它有一些UB (可以修复,请参阅Ruslan注释),它确实可以说明我在下面解释的内容),这个程序输出:

代码语言:javascript
复制
BitSet : 0111111111111000000000000000000000000000000000000000000000000000 for NAN_macro
BitSet : 0111111111111000000000000000000000000000000000000000000000000000 for NAN_quiet
BitSet : 0111111111110100000000000000000000000000000000000000000000000000 for NAN_sig
BitSet : 0111111111111000000000000000000000000000000000000000000000000000 for NAN_str
BitSet : 0111111111111000000000000000000000000000000000000000000000000001 for NAN_str1
BitSet : 0111111111111000000000000000000000000000000000000000000000000000 for NAN_strLong

他们都有:

  • "0“作为符号(您可能会得到NAN_macro的"1”,正如您将其报告为-nan,我没有)。我使用了g++,我打赌某些编译器对NAN宏的定义可能有所不同,我怀疑这是C++标准的一部分。
  • "11111111111“为指数
  • 那么“分数”...any的不同值实际上,但不只是零,否则它将不再是一个NaN。

实际上,这个“分数”或“有效载荷”(请参阅Ruslan注释)值可以用来存储您想要存储的任何信息(比如“为什么这里有一个nan”?),这个值叫做南拳

这就是为什么您可能在某个点上有“不同的”NaN值(非数非数或您创建的任何NaN都符合IEEE 754...even,如果有不同的内存表示,这些值都是NaN值(x!=xstd::isnan(x)==true) )。

所以,回答你的问题:

为什么NAN是-nan(ind)std::numeric_limits<double>::quiet_NaN()是nan

因为您的编译器像这样定义了NAN宏,所以使用另一个编译器可能会有所不同。顺便说一句,它就像min/max宏,即使您有定义它们的错误想法,不要使用它们,更喜欢std函数,因为它们是标准的一部分,所以应该与您使用的任何编译器一样工作。

为什么我们有std::nan("")std::nan("1"),如果在一天结束时,它们似乎都是相同的概念。

也许“帮助你玩南拳”是一个答案,即使我怀疑这些功能是为了这个特定的目的而创建的。正确的答案可能只是“如果您需要与NaNstd::signaling_NaN不同的东西,请让您决定要用于您的std::quiet_NaNstd::signaling_NaN的”分数“值”。

资料来源:https://steve.hollasch.net/cgindex/coding/ieeefloat.html

还使用https://stackoverflow.com/a/40737266/3336423输出NaN内存表示。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61253965

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档