提问者:小点点

长两倍的尺寸和精度不匹配?


考虑以下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;
}

Ubuntu x64 13.04下使用gcc 4.8.1编译,它打印:

16 0.123456789012345678901321800735590983

这告诉我一个长的双重权重为16个字节,但小数似乎只能到第20位。这怎么可能?16个字节对应一个四边形,一个四边形会给我33到36个小数。


共3个答案

匿名用户

C实现中的long double格式使用具有一位符号、15位指数和64位有效数(总共10个字节)的Intel格式。编译器为其分配16个字节,这很浪费,但对于对齐等某些事情很有用。但是,64位仅提供log10(264)有效数字,约为20位。

匿名用户

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宽度说明符以保持浮点值的精度

printf("%.*Le\n", (LDBL_DIG + 3) - 1, ld);
printf("%.*Le\n", LDBL_DECIMAL_DIG - 1, ld);

匿名用户

您计算机上的格式确实是Intel双扩展精度格式,80位宽,具有15位指数和64位尾数。

存储器实际仅使用10个连续字节。英特尔手册(英特尔®64和IA-32体系结构软件开发人员手册合并卷: 1、2A、2B、2C、2D、3A、3B、3C、3D和4)如下所述:

在内存中存储浮点值时,半精度值存储在内存中的2个连续字节中;单精度值存储在内存中的4个连续字节中;双精度值存储在8个连续字节中;双扩展精度值存储在10个连续字节中。

但是,x86LinuxABI指定实际使用完整的16个字节。这可能是因为10字节的值在数组中只能有2的基本对齐要求,这可能会导致特殊问题。

此外,使用16的倍数更容易进行数组索引。

大多数情况下,这不是问题,因为long double通常用于最小化中间计算中的错误,然后将结果截断为double