考虑以下C代码:
#include <stdio.h>
int main(int argc, char* argv[])
{
const long double ld = 0.12345678901234567890123456789012345L;
printf("%lu %.36Lf\n", sizeof(ld), ld);
return 0;
}
在gcc 4.8.1
下与Ubuntu x64 13.04
一起编辑,打印出来:
16 0.123456789012345678901321800735590983
这告诉我一个长的双重16字节,但小数似乎只对第20位。这怎么可能? 16个字节对应四元组,四元组给出33到36个小数。
答案 0 :(得分:7)
C实现中的long double
格式使用Intel格式,带有一位符号,一个15位指数和一个64位有效数字(总共十个字节)。编译器为它分配16个字节,这对于诸如对齐之类的一些事情是浪费的。但是,64位仅提供log 10 (2 64 )有效数字,大约为20位。
答案 1 :(得分:2)
long double
的各种C实现可能具有变体范围和精度。 sizeof
提示基础浮点表示法,但不指定它。 long double
不需要具有33到36个小数。它甚至可以与double
完全相同。
如果没有对精度进行硬编码,但是使用所有可用的精度并且不过度,建议:
const long double ld = 0.12345678901234567890123456789012345L;
printf("%.*Le\n", LDBL_DIG + 3, ld);
printf("%.*Le\n", LDBL_DIG + 3, nextafterl(ld, ld*2));
这打印出来(在我的eclipse intel 64位上),当然,你的可能会有所不同。
1.234567890123456789013e-01
1.234567890123456789081e-01
[编辑]
经过审核,+ 2就足够了。最好使用LDBL_DECIMAL_DIG
。见Printf width specifier to maintain precision of floating-point value
printf("%.*Le\n", (LDBL_DIG + 3) - 1, ld);
printf("%.*Le\n", LDBL_DECIMAL_DIG - 1, ld);
答案 2 :(得分:1)
您计算机上的格式确实是Intel双扩展精度格式,宽度为80位,具有15位指数和64位尾数。
实际上只有10个连续字节的存储器用于存储。英特尔手册(Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D and 4)说:
将浮点值存储在内存中时,半精度值存储在内存中的两个连续字节中; 单精度值存储在内存中的4个连续字节中;双精度值存储在8中 连续字节;和双精度扩展值存储在10个连续字节中。
但是,x86 Linux ABI指定实际使用了完整的16个字节。这可能是因为10字节的值在数组中只能具有 2 的基本对齐要求,这可能会导致特殊的问题。
此外,使用16的倍数进行数组索引更容易。
在大多数情况下,这不是问题,因为long double
通常用于使中间计算中的错误最小化,然后将结果截断为double
。
答案 3 :(得分:0)
sizeof
运算符返回数据类型的字节。浮点格式类型实际上与数据类型的字节大小不相上下,其他大小通常意味着更高的精度。