【问题标题】:sizeof long double and precision not matching?sizeof long double 和精度不匹配?
【发布时间】:2013-06-27 07:11:31
【问题描述】:

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

16 0.123456789012345678901321800735590983

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

【问题讨论】:

标签: c floating-point precision long-double


【解决方案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) 说明如下:

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

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

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

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

【讨论】:

    【解决方案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);
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • gcc 编译期间是否有标志强制 long double = quad ?
      • @Vincent:我不知道。它没有硬件支持,使用这种类型会很慢。您可以搜索扩展精度(固定但比硬件支持时间长)或任意精度(可变)以获取有关替代方案的信息。他们会很慢。
      • 小修正:Intel 80 位浮点类型使用 15 位作为指数,1 位作为符号,而不是 16 位作为指数。
      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-31
        相关资源
        最近更新 更多