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

huangapple go评论85阅读模式
英文:

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

问题

考虑以下的printf指令:

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

它应该打印什么?

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

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

对于g格式的转换,将执行ef样式的转换。让P等于精度(如果不为零)、6(如果未指定精度)或1(如果精度为0)。然后,如果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的一个bug?
英文:

Consider the following printf instruction:

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

what should it print?

I'm reading the description of the g specifier on cppreference.com, which says (text for G removed):

> converts floating-point number to decimal or decimal exponent notation depending on the value and the precision.
>
> For the g conversion style conversion with style e or f will be
> performed.<br>Let P equal the precision if nonzero, 6 if the
> precision is not specified, or 1 if the precision is ​0​. Then, if a
> conversion with style e would have an exponent of X:
>
> * if P > X ≥ −4, the conversion is with style f and precision P − 1 − X.
> * otherwise, the conversion is with style e and precision P − 1.
>
> Unless alternative representation is requested the trailing zeros are
> removed, also the decimal point character is removed if no fractional
> part is left.

In our case,

  • P = 1 , specified explicitly.
  • X = 0, since a "conversion with style e", i.e. &quot;%# 01.1e&quot;, yields 9.8e+00 (adjust the GodBolt program and you'll see).
  • 1 > 0 >= -4 holds.

consequently, the conversion should be with style f and precision P - 1 - X = 1 - 1 - 0 = 0, i.e. &quot;%# 01.0f&quot;, which yields 10..

... but that is not what glibc produces: I get 1.e01, as can also be seen on <kbd>GodBolt</kbd>.

So,

  • Am I mis-reading the quoted text?

  • Is cppreference.com wrong?

  • Is this - perish the tought - a glib 2.36 bug?

答案1

得分: 2

这涉及到“样式 E 的转换”存在一些不清晰之处,以及关于 Eg 的精度含义存在差异。

对于 E,精度是小数点后要显示的位数,根据 C 2018 7.21.6.1 4。而对于 g,精度是最大有效位数。它们之间存在差异;E 在小数点前有额外的一位数字,因此总共比其名义上的“精度”多一位数字。

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

英文:

This is a lack of clarity about “a conversion with style E” and a discrepancy about what the precision means for E and g.

With E, the precision is the number of digits to appear after the decimal point, per C 2018 7.21.6.1 4. With g, the precision is the maximum number of significant digits. Those differ; E has an additional digit before the decimal point, giving a total of one more digit than its nominal “precision.”

Thus, in considering how to format 9.8 for %.1g, we first consider how it would be formatted for %.0E, not %.1E, as both %.1g and %.0E request one digit, whereas %.1E requests two digits. For %.0E, “1e+01” would be produced. So the X, the exponent, is 1, not 0.

答案2

得分: -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都是正确的,实际上后者似乎直接基于标准。

英文:

According to the C standard (draft), precision means

> the maximum number of significant digits for the g and G conversions

In &quot;%# 01.1g&quot; the precision is 1 which means that the value will be rounded to one significant digit (9.8 is rounded to 10).

Now let's look at the definition of g from the same standard draft:

> A double argument representing a floating-point number is converted in
style f or e (or in style F or E in the case of a G conversion specifier),
depending on the value converted and the precision. Let P equal the
precision if nonzero, 6 if the precision is omitted, or 1 if the precision is zero.
Then, if a conversion with style E would have an exponent of X:
> - if P > X ≥ −4, the conversion is with style f (or F) and precision P − (X + 1).
> - otherwise, the conversion is with style e (or E) and precision P − 1.

In our case P = 1 (precision), X = 1 (exponent of 1e+01 which is 10 in exponential format)

P > X is false so the "otherwise" clause takes effect meaning that the exponential format should be used.

So both glibc and cppreference are correct and in fact the latter seems to be directly based on the standard.

huangapple
  • 本文由 发表于 2023年7月11日 04:10:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76657018.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定