gpt4 book ai didi

c++ - NAN 差异 - std::nan 与 quiet_NaN() 与宏 NAN

转载 作者:行者123 更新时间:2023-12-01 14:48:09 29 4
gpt4 key购买 nike

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

我看了一些其他的答案,例如What is difference between quiet NaN and signaling NaN? 。但我仍然不太明白为什么 NAN-nan(ind)std::numeric_limits<double>::quiet_NaN()nan ,或者为什么我们有 std::nan("")std::nan("1") 如果在一天结束时它们似乎是相同的概念。

任何解释或澄清链接都会很棒。

#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
}

最佳答案

IEEE 标准 754 代表 NaN通过指数为全 1 和非零分数的位模式(注意所有浮点十进制值都由“符号”、“指数”和“分数”表示),然后,有很多您可以表示不同的 NaN,因为“非零分数”可能有很多不同的值。

突出您的 NaN表示,用这个扩展你的代码:

#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 评论),它确实可以说明我在下面解释的内容),该程序输出:
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”作为指数
  • 那么“分数”的不同值......实际上是任何值,但绝不仅仅是零,否则它就不再是 NaN 了。

  • 实际上,这个“分数”或“有效载荷”(参见 Ruslan 评论)值可用于存储您想要存储的任何信息(如“为什么这里有一个 nan”?),这称为 NaN-boxing .

    这主要是为什么您在某些时候可能有“不同”的 NaN 值( quiet_NaNsignaling_NaN 或任何您创建的 NaN 符合 IEEE 标准 754 ......即使有不同的内存表示,它们都是 NaN值( x!=xstd::isnan(x)==true )。

    所以,回答你的问题:

    why NAN is -nan(ind) whereas std::numeric_limits<double>::quiet_NaN() is nan



    可能是因为您的编译器这样定义了 NAN 宏,所以使用另一个编译器可能会有所不同。顺便说一句,它就像最小/最大宏,即使定义它们是个坏主意,也不要使用它们,更喜欢 std函数是标准的一部分,因此应该与您使用的任何编译器相同。

    why we have std::nan("") and std::nan("1") if at the end of the day they both seem to be the same concept.



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

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

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

    关于c++ - NAN 差异 - std::nan 与 quiet_NaN() 与宏 NAN,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61253965/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com