%g printf说明符的确切含义是什么?

Mar*_*ery 7 c language-agnostic floating-point printf format-specifiers

该%g说明符似乎并不在多数来源记录它运行得的方式行事.

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

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

而PHP手册说这意味着:

g - %e和%f中的较短者.

而且这里有一个堆栈溢出的答案是声称,

%g 使用最短的表示.

而Quora的回答声称:

%g 以这两个表示中最短的方式打印数字

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

#include <stdio.h>

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

    double y = 1234567.0;
    printf("%e\n", y);
    printf("%f\n", y);
    printf("%g\n", y);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

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

1.234560e+05
123456.000000
123456

1.234567e+06
1234567.000000
1.23457e+06
Run Code Online (Sandbox Code Playgroud)

显然,%g输出不完全匹配任一的%e或%f输出,用于任一x或y以上.更重要的是,它看起来不像%g是最小化输出长度; y可能已经被格式化更简洁,如果像x,它没有被科学记数法印.

我上面引用的所有资料都在向我说谎吗?

我在支持这些格式说明符的其他语言中看到了相同或相似的行为,也许是因为它们引用了printfC函数族.例如,我在Python中看到了这个输出:

>>> print('%g' % 123456.0)
123456
>>> print('%g' % 1234567.0)
1.23457e+06
Run Code Online (Sandbox Code Playgroud)

在PHP中:

php > printf('%g', 123456.0);
123456
php > printf('%g', 1234567.0);
1.23457e+6
Run Code Online (Sandbox Code Playgroud)

在Ruby中:

irb(main):024:0* printf("%g\n", 123456.0)
123456
=> nil
irb(main):025:0> printf("%g\n", 1234567.0)
1.23457e+06
=> nil
Run Code Online (Sandbox Code Playgroud)

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

Mar*_*ery 14

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

甲双表示浮点数参数被转换风格f或e(或风格F或E在A的情况下G 转换说明),这取决于转换的值和精度.设P等于非零的精度,如果省略精度则设为6,如果精度为零则设为1.然后,如果带样式的转换E的指数为X:

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

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

甲双参数表示无穷大或NaN被转换的样式f或F 转换说明.

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

  • 尾随零(以及潜在的小数点)开始使用时剥离%g,这可能导致输出%g符将不完全匹配什么要么 %f还是%e会一直产生.
  • 关于是否使用%f样式或%e样式格式的决定完全基于%e样式表示法所需的指数大小,并不直接取决于哪个表示更短.有些情况下,在这种规则导致几种情况%g选择较长的代表性,如你问题中所示的地方%g使用,尽管这使得再输出4个字符比它需要的是科学记数法.

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

一般格式.对于给定的精度p >= 1,将数字舍入为p有效数字,然后根据其大小以定点格式或科学记数法格式化结果.

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

正和负无穷大,正的和负的零,和NaN,被格式化为inf,-inf, 0,-0和nan的分别,而不管精度.

精度0被视为等于精度1.默认精度为6.

互联网上的许多消息来源声称%g只选择最短的%e并且%f完全错误.

  • 将它们称为“来源”可能会给这些网页带来过多的可信度。 (5认同)