%g printf 说明符究竟是什么意思? [英] What precisely does the %g printf specifier mean?

查看:40
本文介绍了%g printf 说明符究竟是什么意思?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

%g 说明符的行为方式似乎与大多数来源记录的行为方式不同.

The %g specifier doesn't seem to behave in the way that most sources document it as behaving.

根据我发现的大多数来源,在使用 printf 说明符的多种语言中,%g 说明符应该等同于 %f%e - 为提供的值产生较短的输出.例如,在撰写此问题时,cplusplus.com 说 g 说明符的意思是:

According to most sources I've found, across multiple languages that use printf specifiers, the %g specifier is supposed to be equivalent to either %f or %e - whichever would produce shorter output for the provided value. For instance, at the time of writing this question, cplusplus.com says that the g specifier means:

使用最短的表示:%e%f

Use the shortest representation: %e or %f

PHP 手册说 意思是:

g - %e%f 的较短者.

g - shorter of %e and %f.

这里有一个 Stack Overflow 答案声称

%g 使用最短的表示.

一个 Quora 回答声称:

%g 打印这两种表示中最短的数字

%g prints the number in the shortest of these two representations

但这种行为并不是我在现实中看到的.如果我编译并运行这个程序(作为 C 或 C++ - 这是一个在两者中具有相同行为的有效程序):

But this behaviour isn't what I see in reality. If I compile and run this program (as C or C++ - it's a valid program with the same behaviour in both):

#include <stdio.h>

int main(void) {
    double x = 123456.0;
    printf("%e
", x);
    printf("%f
", x);
    printf("%g
", x);
    printf("
");

    double y = 1234567.0;
    printf("%e
", y);
    printf("%f
", y);
    printf("%g
", y);
    return 0;
}

...然后我看到这个输出:

... then I see this output:

1.234560e+05
123456.000000
123456

1.234567e+06
1234567.000000
1.23457e+06

显然,%g 输出与 either %e%f 输出不完全匹配对于上面的 xy.更重要的是,看起来 %g 也没有最小化输出长度;y 如果像 x 一样没有以科学记数法打印,则可以更简洁地格式化.

Clearly, the %g output doesn't quite match either the %e or %f output for either x or y above. What's more, it doesn't look like %g is minimising the output length either; y could've been formatted more succinctly if, like x, it had not been printed in scientific notation.

我上面引用的所有消息来源都是在骗我吗?

Are all of the sources I've quoted above lying to me?

我在支持这些格式说明符的其他语言中看到了相同或相似的行为,这可能是因为它们在底层调用了 printf 系列 C 函数.例如,我在 Python 中看到了这个输出:

I see identical or similar behaviour in other languages that support these format specifiers, perhaps because under the hood they call out to the printf family of C functions. For instance, I see this output in Python:

>>> print('%g' % 123456.0)
123456
>>> print('%g' % 1234567.0)
1.23457e+06

在 PHP 中:

php > printf('%g', 123456.0);
123456
php > printf('%g', 1234567.0);
1.23457e+6

在 Ruby 中:

irb(main):024:0* printf("%g
", 123456.0)
123456
=> nil
irb(main):025:0> printf("%g
", 1234567.0)
1.23457e+06
=> nil

控制这个输出的逻辑是什么?

What's the logic that governs this output?

推荐答案

这是C11标准中g/G说明符的完整描述:

This is the full description of the g/G specifier in the C11 standard:

表示浮点数的 double 参数是以 fe 样式转换(或在 G 的情况下以 FE 样式转换转换说明符),取决于转换的值和精确.如果非零则令 P 等于精度,如果精度为 6省略,如果精度为零,则为 1.然后,如果转换与样式 E 的指数为 X:

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:

    如果 P > X ≥ -4,则转换为具有样式 f(或 F)和精度 P - (X + 1).
    否则,转换使用样式 e(或 E)和精度 P - 1.

     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.

最后,除非使用 # 标志,从小数部分中删除任何尾随零结果的一部分和小数点字符被删除,如果没有剩余的小数部分.

Finally, unless the # flag is used, any trailing zeros are removed from the fractional portion of the result and the decimal-point character is removed if there is no fractional portion remaining.

双重参数表示无穷大或 NaN 以 fF 的样式转换转换说明符.

A double argument representing an infinity or NaN is converted in the style of an f or F conversion specifier.

这种行为有点类似于简单地使用 %f%e 中的最短表示,但不是等效的.有两个重要的区别:

This behaviour is somewhat similar to simply using the shortest representation out of %f and %e, but not equivalent. There are two important differences:

  • 使用 %g 时会去除尾随零(可能还有小数点),这可能会导致 %g 说明符的输出不完全匹配 %f%e 都会产生.
  • 决定是使用 %f-style 还是 %e-style 格式,完全取决于 中所需的指数大小>%e 样式的表示法,并且 not 直接取决于哪种表示会更短.在几种情况下,此规则会导致 %g 选择较长的表示形式,例如问题中显示的情况,即 %g 使用科学记数法,即使这会使输出比需要的长 4 个字符.
  • Trailing zeros (and, potentially, the decimal point) get stripped when using %g, which can cause the output of a %g specifier to not exactly match what either %f or %e would've produced.
  • The decision about whether to use %f-style or %e-style formatting is made based purely upon the size of the exponent that would be needed in %e-style notation, and does not directly depend on which representation would be shorter. There are several scenarios in which this rule results in %g selecting the longer representation, like the one shown in the question where %g uses scientific notation even though this makes the output 4 characters longer than it needs to be.

如果 C 标准的措辞难以解析,Python 文档 提供了另一个相同行为的描述:

In case the C standard's wording is hard to parse, the Python documentation provides another description of the same behaviour:

一般格式.对于给定精度 p >= 1,这会将数字四舍五入为 p 有效数字和然后将结果格式化为定点格式或以科学计数法,取决于其大小.
General format. For a given precision p >= 1, this rounds the number to p significant digits and then formats the result in either fixed-point format or in scientific notation, depending on its magnitude.

确切的规则如下:假设结果格式为 'e' 和精度 p-1 将具有指数 exp.然后if -4 <= exp < p,数字被格式化具有表示类型 'f' 和精度p-1-exp.否则,数字被格式化具有表示类型 'e' 和精度 p-1.在这两种情况下,都会删除无关紧要的尾随零从有效位开始,小数点也是如果后面没有剩余数字,则删除.

The precise rules are as follows: suppose that the result formatted with presentation type 'e' and precision p-1 would have exponent exp. Then if -4 <= exp < p, the number is formatted with presentation type 'f' and precision p-1-exp. Otherwise, the number is formatted with presentation type 'e' and precision p-1. In both cases insignificant trailing zeros are removed from the significand, and the decimal point is also removed if there are no remaining digits following it.

正负无穷,正负无穷zero 和 nans 被格式化为 inf, -inf,0-0nan,不管精度.

Positive and negative infinity, positive and negative zero, and nans, are formatted as inf, -inf, 0, -0 and nan respectively, regardless of the precision.

互联网上许多声称 %g 只是从 %e%f 中挑选最短的消息的来源是完全错误的.

The many sources on the internet that claim that %g just picks the shortest out of %e and %f are simply wrong.

这篇关于%g printf 说明符究竟是什么意思?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆