以下代码假定我们使用的是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";
}
输出:
isnan(value1):true
isnan(value2):false
isnan(value3):false
value1:3.3614005946481929011e-4764
value2:9.7056260598879139386e-4764
value3:6.3442254652397210376e-4764
此处value1
被归类为&#34;不支持&#34;由387或更高,因为它具有非零而非全部指数 - 它实际上是&#34;非常规&#34;。并且isnan
按预期工作:值实际上不是数字(尽管不完全是NaN)。第二个值value2
设置了整数位,并且也按预期工作:它不是NaN。第三个是缺失整数位的值。
但不知何故,两个数字value1
和value2
都会打印出来,而且这些值与缺少的整数位完全不同!这是为什么?我尝试的所有其他方法,例如printf
和to_string
只提供0.00000
。
更奇怪的是,如果我使用value1
进行任何算术,在后续打印中我会得到nan
。考虑到这一点,operator<<(long double)
如何设法实际打印除nan
以外的任何内容?它是显式设置整数位,还是解析数字而不是对它进行任何FPU算术? (假设在Linux 32位上使用g ++ 4.8)。
答案 0 :(得分:1)
我尝试过的所有其他方法,比如printf和to_string 0.00000
operator<<(long double)
实际执行的操作是使用num_put<>
库中的locale
类来执行数字格式设置,而后者又使用其中一个printf
- 族函数(请参阅C ++标准的第27.7.3.6和22.4.2.2节。
根据设置,long double
locale
使用的printf转换说明符可能是以下任意一种:%Lf
,%Le
,%LE
,{{1 }},%La
,%LA
或%Lg
。
在您(和我的)案例中,似乎是%LG
:
%Lg
value1:0.00000000000000000000
value1:3.36140059464819290106e-4764
value1:0x4.3d1ac8f246f235200000p-15826
value1:3.3614005946481929011e-4764
value1:3.3614005946481929011e-4764
考虑到这一点,运营商&lt;&lt;(long double)如何管理 实际打印除了南?它是否显式设置整数 位,或者它可能会解析数字而不是执行任何FPU算术 在它上面?
打印非标准化值。
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";
使用的从二进制到十进制浮点表示的转换可以在没有任何FPU算术的情况下执行。您可以在printf()
源文件中找到glibc实现。
答案 1 :(得分:0)
我正在尝试这个:
long double value = std::numeric_limits<long double>::quiet_NaN();
std::cout << "isnan(value): " << std::boolalpha << std::isnan(value) << "\n";
std::cout << "value: " << std::setprecision(20) << value << "\n";
所以我的假设就像这里所说的那样:http://en.cppreference.com/w/cpp/numeric/math/isnan当被std::isnan
和std::numeric_limits<long double>::quiet_NaN() != std::numeric_limits<double>::quiet_NaN()
评估时,{@ 3}}值被转换为double而不是long double:
{{1}}