Rus*_*lan 11 c++ floating-point nan
以下代码假定我们在x86兼容系统上并long double
映射到x87 FPU的80位格式.
#include <cmath>
#include <array>
#include <cstring>
#include <iomanip>
#include <iostream>
int main()
{
std::array<uint8_t,10> data1{0x52,0x23,0x6f,0x24,0x8f,0xac,0xd1,0x43,0x30,0x02};
std::array<uint8_t,10> data2{0x52,0x23,0x6f,0x24,0x8f,0xac,0xd1,0xc3,0x30,0x02};
std::array<uint8_t,10> data3{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x30,0x02};
long double value1, value2, value3;
static_assert(sizeof value1 >= 10,"Expected float80");
std::memcpy(&value1, data1.data(),sizeof value1);
std::memcpy(&value2, data2.data(),sizeof value2);
std::memcpy(&value3, data3.data(),sizeof value3);
std::cout << "isnan(value1): " << std::boolalpha << std::isnan(value1) << "\n";
std::cout << "isnan(value2): " << std::boolalpha << std::isnan(value2) << "\n";
std::cout << "isnan(value3): " << std::boolalpha << std::isnan(value3) << "\n";
std::cout << "value1: " << std::setprecision(20) << value1 << "\n";
std::cout << "value2: " << std::setprecision(20) << value2 << "\n";
std::cout << "value3: " << std::setprecision(20) << value3 << "\n";
}
Run Code Online (Sandbox Code Playgroud)
输出:
isnan(value1):true
isnan(value2):false
isnan(value3):false
value1:3.3614005946481929011e-4764
value2:9.7056260598879139386e-4764
value3:6.3442254652397210376e-4764
这里value1
被387及更高版本归类为"不支持",因为它具有非零而非全部指数 - 它实际上是"不正常".并且isnan
按预期工作:价值确实不是一个数字(尽管不完全是NaN).第二个值value2
设置了整数位,并且也按预期工作:它不是NaN.第三个是缺失整数位的值.
但不知何故,这两个数字value1
,并value2
出现印刷,值由缺少整数位不同正是!这是为什么?我试过的所有其他方法,喜欢printf
和to_string
给予0.00000
.
更奇怪的是,如果我做任何算术value1
,在随后的打印中我确实得到了nan
.考虑到这一点,operator<<(long double)
甚至如何实际打印任何东西,但nan
?它是显式设置整数位,还是解析数字而不是对它进行任何FPU算术?(假设在Linux 32位上使用g ++ 4.8).
我尝试过的所有其他方法(例如 printf 和 to_string)仅给出 0.00000。
实际上所做operator<<(long double)
的是使用库num_put<>
中的类locale
来执行数字格式化,这又使用printf
-family 函数之一(请参阅 C++ 标准的第 27.7.3.6 和 22.4.2.2 节)。
根据设置,long double
by使用的printf 转换说明符locale
可能是以下任意一种:%Lf
、%Le
、%LE
、%La
、%LA
或。%Lg
%LG
在你(和我)的情况下,它似乎是%Lg
:
printf("value1: %.20Lf\n", value1);
printf("value1: %.20Le\n", value1);
printf("value1: %.20La\n", value1);
printf("value1: %.20Lg\n", value1);
std::cout << "value1: " << std::setprecision(20) << value1 << "\n";
Run Code Online (Sandbox Code Playgroud)
值1:0.00000000000000000000
值1:3.36140059464819290106e-4764
值1:0x4.3d1ac8f246f235200000p-15826
值1:3.3614005946481929011e-4764
值1:3.3614005946481929011e-4764
考虑到这一点,operator<<(long double) 甚至如何设法实际打印除 nan 之外的任何内容?它是否显式设置整数位,或者它可能解析该数字而不是对其进行任何 FPU 算术?
它打印非标准化值。
从二进制到十进制浮点表示的转换printf()
可以在没有任何 FPU 算术的情况下执行。您可以在源文件中找到 glibc 实现stdio-common/printf_fp.c
。