【问题标题】:can't figure out the sizeof(long double) in C is 16 bytes or 10 bytes无法确定 C 中的 sizeof(long double) 是 16 字节还是 10 字节
【发布时间】:2020-06-24 10:30:11
【问题描述】:

虽然这个网站上有一些答案,但我还是搞不懂sizeof(long double)的意思。为什么打印var3的输出是3.141592653589793115998

当我尝试执行另一个人的代码时,它的运行方式与另一个人不同。有人可以帮我解决这个问题吗?

我的测试代码:

float var1 =3.1415926535897932;
double var2=3.1415926535897932;
long double var3 =3.141592653589793213456;


printf("%d\n",sizeof(float));


printf("%d\n",sizeof(double));

printf("%d\n",sizeof(long double));

printf("%.16f\n",var1);
printf("%.16f\n",var2);
printf("%.21Lf\n",var3);

我的测试代码的输出:

4
8
16
3.1415927410125732
3.1415926535897931
3.141592653589793115998

代码与另一个人相同,但另一个人的输出是:

4
8
12
3.1415927410125732
3.1415926535897931
3.141592741012573213359

有人能告诉我为什么我们的输出不同吗?

【问题讨论】:

  • 欢迎来到 SO。请将您的代码添加到问题中。不要强迫读者关注外部链接。另外请不要将文字作为图片发布。包含改为文本。
  • 使用 GNU C 编译器,long double 是 x86 处理器上的 80 位扩展精度,与用于该类型的物理存储(可以是 96 位或 128 位)无关,[10] 在某些在其他架构中,long double 可以是 double-double(例如在 PowerPC[11][12][13] 上)或 128 位四倍精度(例如在 SPARC[14] 上)。从 gcc 4.3 开始,x86 也支持四倍精度,但作为非标准类型 __float128 而不是 long double。[15] [More info]
  • 如果您要查看所有图像,“这是我的测试代码”、“这是我的测试代码的输出”和“这是另一个人的代码和输出”帮助。谢谢!
  • @DavidRanieri 那么,如果我希望 sizeof(long double) 的输出为 10 字节,你能告诉我该怎么做吗?我不应该使用 GNU C 编译器吗?或者有什么可以推荐给我的?谢谢!
  • 我不应该使用 GNU C 编译器吗? 你有什么问题?您是否需要比某些实现提供的精度更高的精度?我们经常使用 epsilons 来处理这类问题(LDBL_EPSILON in float.h),看看en.wikipedia.org/wiki/Machine_epsilon

标签: c floating-point precision sizeof long-double


【解决方案1】:

浮点数 - 在我们的计算机中 - 不是数学real numbers

它们有很多违反直觉的属性(例如,您的 C 代码中的 (1.0-x) + x 可以不同于 1....)。更多信息,请阅读floating-point-gui.de

还要注意,数字不是数字的表示形式。例如,您的大多数示例都是the number π 的近似值(直观地说,它具有无限数量的数字或位,因为它是trancendental number,正如Évariste GaloisNiels Abel 所证明的那样)。 continuum hypothesis 是相关的。

我还是搞不懂sizeof(long double)的意思。

它是long double automatic variablebytes(或octets)的数量与char 自动变量中的字节数之比。

C11 标准(阅读 n1570 并参见 this reference)确实允许实现具有 sizeof(long double),例如 sizeof(char),等于 1。我无法命名这样的实现,但它可能是(理论上) 一些奇怪的计算机架构上的案例(例如一些DSP)。

有人能告诉我为什么我们的输出不同吗?

是什么让您认为他们可以平等?

实际上,浮点数通常是IEEE754。但在 IBM 大型机(例如 z/Series)或 VAXes 上,它们不是

float var1 =3.1415926535897932;
double var2 =3.1415926535897932;

请注意,在执行上述这些指令后,可能会有一个 C 实现 where (double)var1 != var2 或 where var1 != (float)var2

如果您需要比 long double 在特定 C 实现上实现的更精确(例如,您最近的 GCC 编译器,可能是 cross-compiler),请考虑使用一些 arbitrary precision arithmetic 库,例如 GMPlib

我建议仔细阅读printf(3) 的文档,以及您在C standard library 中使用的每个other function 的文档。我还建议阅读您的 C 编译器的文档。

您可能对static program analysis 工具感兴趣,例如Frama-CClang static analyzer。另请阅读this draft 报告。

如果您的 C 编译器是最新的 GCC,请编译 with 所有警告和调试信息,因此 gcc -Wall -Wextra -g 并学习如何使用 GDB 调试器。

【讨论】:

    【解决方案2】:

    谁能告诉我为什么我们的输出不同?

    C 允许不同的编译器/实现使用不同的浮点编码并以略微不同的方式处理评估。

    精度

    sizeof 的差异暗示这两种实现可能采用不同的精度。然而,差异可能是由于填充,在这种情况下,出于性能原因,添加了额外的字节以保持对齐。

    更好的精度评估是打印 epsilon:1.0 和下一个较大的类型值之间的差。

    #include <float.h>
    
    printf("%e %e %Le\n", FLT_EPSILON, DBL_EPSILON, LDBL_EPSILON);
    

    示例结果

    1.192093e-07 2.220446e-16 1.084202e-19
    

    FLT_EVAL_METHOD

    当这是 0 时,浮点类型计算为该类型。对于 2 等其他值,浮点计算使用更广泛的类型,并且仅在最后将结果保存到目标类型。

    printf("FLT_EVAL_METHOD %d\n", FLT_EVAL_METHOD);
    

    以下几个可能的值中的两个:

    FLT_EVAL_METHOD
    0 仅根据类型的范围和精度评估所有操作和常量;
    2 将所有操作和常量评估为long double 类型的范围和精度。

    注意常量3.1415926535897932, 3.141592653589793213456 通常都是double 常量。两者都没有 L 后缀来构成 long double。两者都有3.1415926535897931...val2相同 double 值,val3 应该得到相同的值。然而,使用FLT_EVAL_METHOD==2,常量可以评估为long double,这肯定是“来自另一个人的输出”代码中发生的情况。

    打印FLT_EVAL_METHOD 以查看差异。

    【讨论】:

      猜你喜欢
      • 2019-10-08
      • 1970-01-01
      • 2011-06-13
      • 2011-08-24
      • 2015-12-27
      • 1970-01-01
      • 2015-07-23
      • 2012-08-05
      相关资源
      最近更新 更多