代码之家  ›  专栏  ›  技术社区  ›  Mark Amery Harley Holcombe

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

  •  6
  • Mark Amery Harley Holcombe  · 技术社区  · 6 年前

    这个 %g 说明符的行为似乎不像大多数源文件中描述的那样。

    根据我发现的大多数来源,跨多种语言使用 printf 说明符 %g 说明符应该等于 %f %e -两者中以较短的输出值为准。例如,在写这个问题的时候, cplusplus.com says g 说明符是指:

    使用最短的表示法: %E %F

    以及 PHP manual says 它的意思是:

    G -更短的 %E %F .

    here's a Stack Overflow answer 声称

    %g 使用最短的表示。

    a Quora answer 声称:

    %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;
    }
    

    …然后我看到这个输出:

    1.234560e+05
    123456.000000
    123456
    
    1.234567e+06
    1234567.000000
    1.23457e+06
    

    显然, %g 输出不太匹配 任何一个 这个 %E %F 任何一个的输出 x y 上面。更重要的是,它看起来不像 %g 或者是将输出长度最小化; Y 如果,比如 X 它有 以科学记数法印刷的。

    我上面引用的所有资料都是对我撒谎吗?

    我在支持这些格式说明符的其他语言中看到相同或类似的行为,可能是因为在引擎盖下它们调用 普林特 C函数族。例如,我在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
    

    露比:

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

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

    2 回复  |  直到 6 年前
        1
  •  11
  •   Mark Amery Harley Holcombe    6 年前

    这是对 g / G C11标准中的说明符:

    双重的 表示浮点数的参数是 已转换为样式 f e (或风格) F E 如果是 G 转换说明符),取决于转换的值和 精度。让 如果不为零,则等于精度;如果精度为 省略,如果精度为零,则为1。然后,如果转换为 风格 e 会有指数 X :

    如果 gt; X __4,转换为 带风格 f (或) f )和精度 P_(X+1) .
    否则, 转换带有样式 e (或) e )和精度 1。

    最后,除非 这个 γ 使用标志,从分数中删除所有尾随零 如果 没有剩余的小数部分。

    双重的 论点 表示无穷大或NaN的样式转换为 f f 转换说明符。

    这种行为有点类似于简单地使用 %f %e ,但不等同。有两个重要区别:

    • 尾随零(可能还有小数点)在使用时会被去除 %g ,这会导致 %g 说明符将不完全匹配 任何一个 %F %E 会产生的。
    • 是否使用的决定 %F -风格或 %E -样式格式完全基于在 %E -样式符号,并且 直接取决于哪种表述会更短。有几种情况会导致此规则 %g 选择较长的表示,如问题中所示 %g 使用科学记数法,即使这使输出比需要的长4个字符。

    如果C标准的措辞难以解析,则 Python documentation 提供对相同行为的另一种描述:

    常规格式。对于给定的精度 p >= 1 , 这将数字四舍五入为 p 有效数字和 然后将结果格式化为固定点格式 或以科学记数法,视其大小而定。

    具体规则如下:假设 使用演示文稿类型格式化的结果 'e' 和 精度 p-1 会有指数 exp . 然后 如果 -4 <= exp < p ,数字已格式化 带演示文稿类型 'f' 精密度 p-1-exp . 否则,数字将被格式化。 带演示文稿类型 “e” 精密度 P-1 . 在这两种情况下,无意义的尾随零都会被删除。 从有效位开始,小数点也是 如果后面没有剩余数字,则删除。

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

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

    互联网上的许多消息来源声称 %g 从中选出最短的 %E %F 是完全错误的。

        2
  •  -4
  •   Patrick Chkoreff    6 年前

    我最喜欢的双打格式是“%.15g”。在任何情况下,它似乎都是正确的。我很肯定15是最大的可靠的十进制精度在一个双精度。