13

考虑以下 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用under编译Ubuntu x64 13.04,它打印:

16 0.123456789012345678901321800735590983

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

4

4 回答 4

12

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

于 2013-06-29T17:33:46.133 回答
4

的各种 C 实现long double可能具有不同的范围和精度。sizeof底层浮点表示法的提示,但未指定它。Along 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);
于 2013-06-29T19:30:21.617 回答
2

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

存储器实际使用的存储器只有 10 个连续字节。英特尔手册(英特尔® 64 和 IA-32 架构软件开发人员手册组合卷:1、2A、2B、2C、2D、3A、3B、3C、3D 和 4)说明如下:

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

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

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

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

于 2018-11-27T19:28:33.440 回答
0

sizeof运算符返回数据类型的大小(以字节为单位) 。浮点格式类型与数据类型的字节大小并不能真正相比,更大的大小通常意味着更好的精度。

于 2013-06-29T17:32:48.400 回答