关于MSVC中signaling_NaN实现是否符合IEEE 754-2019标准的二次确认问询
关于MSVC中
signaling_NaN实现是否符合IEEE 754-2019标准的二次确认问询 大家好,最近我在研究MSVC里std::numeric_limits的signaling_NaN实现时,发现了一些和IEEE 754-2019标准不符的细节,还碰到了实现不一致的情况,想请大家帮忙看看是不是我哪里漏了,或者是不是维基百科的描述有问题?
我发现的核心问题
float类型signaling_NaN()不符合IEEE 754-2019:根据标准要求,*信号NaN(signaling NaN)*的尾数最高有效位必须是0,*安静NaN(quiet NaN)*的该位是1,但MSVC的float版本signaling_NaN()把这个关键位设成了1,反而符合安静NaN的标识规则。- 实现逻辑不一致:
double类型的signaling_NaN()完全遵循IEEE 754-2019标准,但float却不是,这种同标准库下不同基础类型的差异化处理太反常了。
背景参考(来自维基百科)
根据维基百科的描述,IEEE 754-2019修订版明确要求:
对于二进制交换格式,尾数域的最高有效位专门用于区分安静NaN和信号NaN——这个位是“是否安静”的标志:非零表示安静NaN,零表示信号NaN。而更早版本的IEEE标准并没有这个强制要求,区分安静/信号NaN的位是实现相关的,不过当时很多主流实现也采用了上述标识方式。
如果说MSVC不遵循2019版标准是因为兼容旧版,那float和double的差异化处理就完全说不通了,这更像是实现上的疏漏。
测试验证结果(MSVC环境)
我写了一个测试程序,专门打印float和double类型NaN的二进制位信息,以下是关键输出:
预定义宏(MSVC版本信息)
Predefined Macros __cplusplus : 199711 _MSVC_LANG : 202302 _MSC_VER : 1943 _MSC_FULL_VER : 194334810 _MSC_BUILD : 0
float类型测试输出
======== float ======== IEEE 754 Support std::numeric_limits< float >::is_iec559 : true std::numeric_limits< float >::has_quiet_NaN : true std::numeric_limits< float >::has_signaling_NaN : true std::numeric_limits< float >::quiet_NaN() bits : 01111111110000000000000000000000 exponent : _11111111_______________________ significand : _________10000000000000000000000 is_quiet : _________1______________________ std::numeric_limits< float >::signaling_NaN() bits : 01111111110000000000000000000001 exponent : _11111111_______________________ significand : _________10000000000000000000001 is_quiet : _________1______________________ <===== 这里明显有问题!
可以看到,float的signaling_NaN()的is_quiet位是1,完全违反了IEEE 754-2019对信号NaN的定义。
double类型测试输出
======== double ======== IEEE 754 Support std::numeric_limits< double >::is_iec559 : true std::numeric_limits< double >::has_quiet_NaN : true std::numeric_limits< double >::has_signaling_NaN : true std::numeric_limits< double >::quiet_NaN() bits : 0111111111111000000000000000000000000000000000000000000000000000 exponent : _11111111111____________________________________________________ significand : ____________1000000000000000000000000000000000000000000000000000 is_quiet : ____________1___________________________________________________ std::numeric_limits< double >::signaling_NaN() bits : 0111111111110000000000000000000000000000000000000000000000000001 exponent : _11111111111____________________________________________________ significand : ____________0000000000000000000000000000000000000000000000000001 is_quiet : ____________0___________________________________________________
double的signaling_NaN()的is_quiet位是0,完全符合IEEE 754-2019的要求。
我的疑问
- 是不是我对IEEE 754-2019的标准理解有误?或者维基百科的描述存在偏差?
- MSVC这种
float和double的差异化实现,是有意为之(比如兼容旧代码),还是单纯的实现bug? - 有没有什么我没注意到的编译选项或者文档说明,能解释这个不一致的现象?
测试源代码
// app23.signaling_nan.main.cpp // 用于验证NaN位信息的测试程序 #include <bit> // bit_cast #include <cstddef> // size_t #include <cstdint> // uint32_t, uint64_t #include <iostream> // cout, ostream #include <limits> // numeric_limits #include <string> // string #include <string_view>// string_view namespace { // 打印预定义宏信息 void put_predefined_macros(std::ostream& log) { log << "Predefined Macros\n" << " __cplusplus : " << __cplusplus << '\n' << " _MSVC_LANG : " << _MSVC_LANG << '\n' << " _MSC_VER : " << _MSC_VER << '\n' << " _MSC_FULL_VER : " << _MSC_FULL_VER << '\n' << " _MSC_BUILD : " << _MSC_BUILD << '\n'; } // 辅助函数:打印数值的二进制位及标识信息 template<typename T, typename UIntT> void print_nan_bits(std::ostream& log, const char* type_name, T nan_val, const char* nan_type) { auto bits = std::bit_cast<UIntT>(nan_val); // 省略具体位解析和打印逻辑 // ... } // 测试指定浮点类型的NaN信息 template<typename T, typename UIntT> void test_nan_type(std::ostream& log, const char* type_name) { log << "======== " << type_name << " ========\n" << "IEEE 754 Support\n" << "std::numeric_limits< " << type_name << " >::is_iec559 : " << std::boolalpha << std::numeric_limits<T>::is_iec559 << '\n' << "std::numeric_limits< " << type_name << " >::has_quiet_NaN : " << std::numeric_limits<T>::has_quiet_NaN << '\n' << "std::numeric_limits< " << type_name << " >::has_signaling_NaN : " << std::numeric_limits<T>::has_signaling_NaN << '\n'; print_nan_bits<T, UIntT>(log, type_name, std::numeric_limits<T>::quiet_NaN(), "quiet_NaN()"); print_nan_bits<T, UIntT>(log, type_name, std::numeric_limits<T>::signaling_NaN(), "signaling_NaN()"); } } // namespace int main() { put_predefined_macros(std::cout); test_nan_type<float, uint32_t>(std::cout, "float"); test_nan_type<double, uint64_t>(std::cout, "double"); return 0; }
内容来源于stack exchange
相关产品推荐
相关产品推荐

