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

6
考虑以下printf指令:
printf("%# 01.1g", 9.8);

它应该打印什么?

我正在阅读cppreference.com上关于g格式说明的描述,其中(删除了G的文本):

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

对于使用样式efg转换,将执行以下操作:
如果非零,则令P等于精度;如果未指定精度,则令P等于6;如果精度为0,则令P等于1。然后,如果使用样式e进行转换会得到指数X:

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

除非要求使用替代表示法,否则会删除尾随的零,并且如果没有小数部分,则删除小数点字符。

在我们的情况下,

  • P = 1,明确指定。
  • X = 0,因为“使用样式e进行转换”,即"%# 01.1e",得到9.8e+00(调整Godbolt程序,你就会看到)。
  • 1 > 0 >= -4 成立。

因此,转换应该使用样式f和精度P - 1 - X = 1 - 1 - 0 = 0,即"%# 01.0f",得到10.

...但这并不是glibc生成的结果:我得到的是1.e01,也可以在Godbolt上看到。

所以:

  • 我是否误读了引用的文本?
  • cppreference.com错了吗?
  • 这难道是glib 2.36的一个错误?
2个回答

2
关于“带有样式E的转换”存在一些不清楚之处,以及关于E和g的精度意义上的差异。
对于E来说,精度是小数点后要显示的位数,根据C 2018 7.21.6.1 4。而对于g来说,精度是最大有效数字的数量。这两者是不同的;E在小数点前面有一个额外的数字,比其名义“精度”多一位。
因此,在考虑如何将9.8格式化为%.1g时,我们首先考虑它在%.0E下的格式化方式,而不是%.1E,因为%.1g和%.0E都要求一位数字,而%.1E要求两位数字。对于%.0E,将产生“1e+01”。所以指数X是1,而不是0。

只是为了确保一下 - 你的回答是基于官方标准的文本,还是你在解释glibc的行为? - ein supports Moderator Strike
只是为了确保一下 - 你的回答是基于官方标准的文本,还是你在解释glibc的行为? - einpoklum
@einsupportsModeratorStrike: 两者都要考虑。想一想“P > X”的原因。如果X就像我描述的那样,而且P > X > 0,那么我们会在小数点前产生P位数字。但是根据另一种解释,有时我们必须在小数点前产生P位数字和一个“0”,所以是P + 1位数字。这不符合g格式的精神;应该恰好有P位数字(或者更少,如果我们要求去除尾部的零)。 - Eric Postpischil
@einsupportsModeratorStrike: 两者都要考虑。想一想“P > X”的原因。如果X就像我描述的那样,而且P > X > 0,那么我们会在小数点前产生P位数字。但是根据另一种解释,有时我们不得不在小数点前产生P位数字和一个“0”,所以是P + 1位数字。这不符合g格式的精神;应该恰好有P位数字(或者更少,如果我们要求去除尾部的零)。 - Eric Postpischil
@einsupportsModeratorStrike:还要注意,如果选择了e格式,在你引用的段落的第二个项目中会发生什么;所使用的精度是P − 1。因此,比较 P > X 是在考虑“如果按照第二个项目打印,会发生什么?”它在选择使用 e 和精度 P − 1 或者使用 f 和精度 P − 1 − X 之间进行选择,所以应该使用与第二个项目相关联的 X - Eric Postpischil
显示剩余3条评论

-1
根据C标准(草案),精确度意味着“gG转换的最大有效数字位数”。
"%# 01.1g"中,精确度为1,这意味着该值将四舍五入为一个有效数字位数(9.8会四舍五入为10)。
现在让我们看一下同一标准草案中g的定义:
一个表示浮点数的double参数,根据转换的值和精度,以样式fe(或在G转换说明符的情况下以样式FE)进行转换。如果非零,则让P等于精度;如果省略了精度,则为6;如果精度为零,则为1。然后,如果使用样式E进行转换将具有指数X

  • 如果P > X ≥ −4,则转换采用样式f(或F),精度为P - (X + 1)。
  • 否则,转换采用样式e(或E),精度为P - 1。

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

P > X 是错误的,因此“否则”子句生效,意味着应该使用指数格式。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接