解释 printf(“%# 01.1g”,9.8) 中的格式说明符

Interpreting the format specifier in printf("%# 01.1g",9.8)

提问人:einpoklum 提问时间:7/11/2023 最后编辑:einpoklum 更新时间:7/11/2023 访问量:143

问:

请考虑以下 printf 指令:

printf("%# 01.1g", 9.8);

它应该打印什么?

我正在阅读 cppreference.com 上 g 说明符的描述,上面写着(删除的文本):G

根据值和精度将浮点数转换为十进制或十进制指数表示法。

对于 g 转换样式,样式为 ef 的样式转换将是 执行。
设 P 等于非零的精度,如果 未指定精度,如果精度为 0,则为 1。然后,如果 使用样式 e 的转换将具有 X 的指数:

  • 如果 P > X ≥ −4,则转换采用样式 f 和精度 P − 1 − X。
  • 否则,转换的样式为 e,精度为 P − 1。

除非请求替代表示,否则尾随的零为 删除,如果没有小数,也会删除小数点字符 部分还剩下。

在我们的例子中,

  • P = 1 ,明确指定。
  • X = 0,因为“样式为 e 的转换”,即 ,产生(调整 GodBolt 程序,你会看到)。"%# 01.1e" 9.8e+00
  • 1 > 0 >= -4 个成立。

因此,转换应使用样式 f 和精度 P - 1 - X = 1 - 1 - 0 = 0,即 ,其产生 。"%# 01.0f" 10.

...但这不是 glibc 产生的:我明白了,正如在 GodBolt 上看到的那样。 1.e01

所以

  • 我是否误读了引用的文本?
  • cppreference.com 错了吗?
  • 这是 - 灭亡 tought - 一个油嘴滑舌的 2.36 错误吗?
C 浮点 printf 语言-律师-格式 -说明符

评论


答:

2赞 Eric Postpischil 7/11/2023 #1

这是对“有风格的转换”缺乏明确性,并且对精度的含义和存在差异。EEg

使用 ,精度是小数点后出现的位数,根据 C 2018 7.21.6.1 4。其中 ,精度为最大有效位数。这些不同; 在小数点之前有一个额外的数字,总共比其名义上的“精度”多一个数字。EgE

因此,在考虑如何格式化 9.8 时,我们首先考虑如何格式化为 ,而不是 ,因为两者都请求一个数字,而请求两个数字。对于 ,将产生 “1e+01”。所以 X,指数,是 1,而不是 0。%.1g%.0E%.1E%.1g%.0E%.1E%.0E

评论

0赞 einpoklum 7/11/2023
只是为了确保 - 你是根据官方标准的文本来回答,还是在解释 glibc 的行为方式?
0赞 Eric Postpischil 7/11/2023
@einsupportsModeratorStrike:两者兼而有之。想想“P > X”的原因。如果 X 如我所描述的,并且 P > X > 0,那么我们将在小数点之前生成 P 位。但是对于另一种解释,我们有时必须产生 P 位数字和小数点前的“0”,因此 P + 1 位。这不是格式的精神;应该正好有 P 位(如果我们要求删除尾随小数零,则更少)g
0赞 Eric Postpischil 7/11/2023
@einsupportsModeratorStrike:还要注意,如果在引用段落的第二个项目符号项中选择了格式会发生什么;使用的精度为 P − 1。因此,P > X 的比较是在考虑“如果我根据第二个项目符号项目打印它会发生什么?它选择在精度为 P − 1 或精度为 P − 1 − X 之间进行打印,因此应使用的 X 是与第二个项目符号项关联的 Xeef
-1赞 vitaut 7/11/2023 #2

根据C标准(草案),精度是指

和 转换的最大有效位数gG

精度为 1,这意味着该值将四舍五入到一个有效数字(9.8 四舍五入为 10)。"%# 01.1g"

现在让我们看一下同一标准草案中的定义:g

表示浮点数的参数将转换为 style 或(或 in style 或在转换说明符的情况下), 取决于转换后的值和精度。设 P 等于 如果不为零,则为 precision,如果省略精度,则为 6,如果精度为零,则为 1。 然后,如果具有样式的转换的指数为 XdoublefeFEGE

  • 如果 P > X ≥ −4,则转换为样式 (或 ) 和精度 P − (X + 1)。fF
  • 否则,转换为样式 (或 ) 和精度 P − 1。eE

在我们的例子中,P = 1(精度),X = 1(1e+01 的指数,指数格式为 10)

P > X 为 false,因此“否则”子句生效,这意味着应使用指数格式。

所以 glibc 和 cppreference 都是正确的,事实上后者似乎直接基于标准。