NAN 差异 - std::nan vs quiet_NaN() vs Macro NAN
NAN Differences - std::nan vs quiet_NaN() vs Macro NAN
我想知道以下 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 的指数和非零小数(请注意,所有浮点十进制值均由 "sign" 表示,一个"exponent" 和 a"fraction"),那么,您可以表示很多不同的 NaN,因为 "a non-zero fraction" 可能有很多不同的值。
要突出显示您的 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”作为指数
- 然后 "fraction" 的不同值...实际上是任何值,但绝不会只有零,否则它将不再是 NaN。
实际上,此 "fraction" 或 "payload"(请参阅 Ruslan 评论)值可用于存储您想要存储的任何信息(如 "why was there a nan here"?),这是叫,NaN-boxing。
这就是为什么您在某些时候可能具有 "different" NaN 值的主要原因(quiet_NaN, signaling_NaN 或您创建的任何 NaN
符合 IEEE 标准 754...即使具有不同的内存表示,它们都是 NaN
值(x!=x
和 std::isnan(x)==true
)。
所以,回答你的问题:
why NAN is -nan(ind)
whereas std::numeric_limits<double>::quiet_NaN()
is nan
可能是因为您的编译器这样定义了 NAN 宏,使用其他编译器可能会有所不同。顺便说一句,它就像 min/max 宏,即使定义它们的想法不好,也不要使用它们,更喜欢 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.
也许 "to help you play with NaN-boxing" 可能是一个答案,即使我怀疑这些函数是为特定目的而创建的。正确的答案可能只是“如果您需要不同于 std::quiet_NaN
和 std::signaling_NaN
的东西,让您决定要为 NaN
使用什么 "fraction" 值”
来源:
https://steve.hollasch.net/cgindex/coding/ieeefloat.html
还使用输出NaN
内存表示。
我想知道以下 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 的指数和非零小数(请注意,所有浮点十进制值均由 "sign" 表示,一个"exponent" 和 a"fraction"),那么,您可以表示很多不同的 NaN,因为 "a non-zero fraction" 可能有很多不同的值。
要突出显示您的 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”作为指数
- 然后 "fraction" 的不同值...实际上是任何值,但绝不会只有零,否则它将不再是 NaN。
实际上,此 "fraction" 或 "payload"(请参阅 Ruslan 评论)值可用于存储您想要存储的任何信息(如 "why was there a nan here"?),这是叫,NaN-boxing。
这就是为什么您在某些时候可能具有 "different" NaN 值的主要原因(quiet_NaN, signaling_NaN 或您创建的任何 NaN
符合 IEEE 标准 754...即使具有不同的内存表示,它们都是 NaN
值(x!=x
和 std::isnan(x)==true
)。
所以,回答你的问题:
why NAN is
-nan(ind)
whereasstd::numeric_limits<double>::quiet_NaN()
is nan
可能是因为您的编译器这样定义了 NAN 宏,使用其他编译器可能会有所不同。顺便说一句,它就像 min/max 宏,即使定义它们的想法不好,也不要使用它们,更喜欢 std
函数,它们是标准的一部分,因此应该与任何您使用的编译器。
why we have
std::nan("")
andstd::nan("1")
if at the end of the day they both seem to be the same concept.
也许 "to help you play with NaN-boxing" 可能是一个答案,即使我怀疑这些函数是为特定目的而创建的。正确的答案可能只是“如果您需要不同于 std::quiet_NaN
和 std::signaling_NaN
的东西,让您决定要为 NaN
使用什么 "fraction" 值”
来源: https://steve.hollasch.net/cgindex/coding/ieeefloat.html
还使用NaN
内存表示。