【问题标题】:gcc 9.3.0 printf %Lf output not correctgcc 9.3.0 printf %Lf 输出不正确
【发布时间】:2021-07-26 00:58:43
【问题描述】:

printf("%Lf", long double) 将输出截断为double。或者,我做错了什么?

Gcc 9.3.0 Ubuntu 20.04.2,Linux 5.8.0-59-generic

printf("print m_pi  %.45f\n", M_PI);
printf("print m_pil %.45LF\n", M_PIl);
printf("maple Pi    3.141592653589793238462643383279502884197\n");
printf("m_pil def   3.141592653589793238462643383279502884L\n");

输出:

print m_pi  3.141592653589793115997963468544185161590576172
print m_pil 3.141592653589793238512808959406186204432742670
maple Pi    3.141592653589793238462643383279502884197
m_pil def   3.141592653589793238462643383279502884L

似乎 gcc printf 正在将 long double 截断为 13 位 +-。

【问题讨论】:

  • M_PIl 是如何定义的?
  • 在 math.h 中,它包含在 cmath 中。 3.141592653589793238462643383279502884L
  • 看'man printf',f和F是一样的,只是F是大写的。

标签: gcc floating-point printf precision long-double


【解决方案1】:

printf("%Lf", long double) 将输出截断为双倍

它显然不会截断任何内容。很容易看出doublelong double 的结果完全不同,long doubledouble 更精确

所以没有什么问题。在 x86 上,long double 通常是 80-bit extended precision 类型,其精度为 around 18 digits3.141592653589793238 正确到 19 位有效数字

如果您需要更高的精度,请通过设置-mlong-double-128 选项使用quadruple precision 或直接使用__float128。当然这是由软件模拟的,所以它会比原生 x87 80 位格式慢很多

Demo on Godbolt

要获得更高的精度,您必须使用 3rd 方任意精度浮点库


为什么size(long double) 是 16 字节?

大小与精度无关。就像 C++ 中允许的陷阱表示和填充位一样,类型的大小可以比实际精度更宽

在 80 位扩展格式中,内部表示为 10 字节,但添加了填充字节以将类型对齐为 4 字节 (x86) 或 8 字节 (x86-64),从而导致 64- 中的 16 字节类型位模式。可以通过 gcc 中的-m96/128bit-long-double 选项更改填充

这里重要的是LDBL_DIG/LDBL_MANT_DIG/LDBL_MAX_EXP/LDBL_MAX_10_EXPstd::numeric_limits<long double>::digits/digits10/max_exponent/max_exponent10这是类型的真正精度。事实上,通过更改上述-m-long-double 选项的组合,您会得到许多不同的结果:

默认结果是 size = 16,digits10 = 18,digits2 = 64。如果禁用填充,您将得到 size = 10,但由于未对齐,这会以性能为代价。在Godbolt上查看更多演示

在 PowerPC 中您还可以看到the same phenomena when changing the floating-point format。虽然大小仍然是 16 字节,但精度可能会有所不同。使用-mabi=ibmlongdoubledouble-double arithmetic,这是默认值)你会得到 (size, digits10, digits2) = (16, 31, 106) 但使用-mabi=ieeelongdouble 元组将变为 (16, 33, 113)

【讨论】:

  • 为什么 size(long double) 是 16 字节?
  • 如果我的回答有帮助请点击绿色复选标记accept it
猜你喜欢
  • 2014-05-29
  • 2012-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-13
  • 1970-01-01
  • 1970-01-01
  • 2019-08-03
相关资源
最近更新 更多