繁体   English   中英

%g printf 说明符到底是什么意思?

[英]What precisely does the %g printf specifier mean?

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

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

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

PHP 手册说它意味着:

g - 较短的%e%f

这是一个 Stack Overflow 的回答,声称

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

... 然后我看到这个 output:

1.234560e+05
123456.000000
123456

1.234567e+06
1234567.000000
1.23457e+06

显然,对于上面的xy%g output 与%e%f output 都不完全匹配。 而且,看起来%g也没有最小化 output 的长度; 如果yx一样没有以科学记数法打印,那么它的格式可能会更简洁。

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

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

>>> 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\n", 123456.0)
123456
=> nil
irb(main):025:0> printf("%g\n", 1234567.0)
1.23457e+06
=> nil

管理这个 output 的逻辑是什么?

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

根据转换的值和精度,表示浮点数的double参数以样式fe (或在G转换说明符的情况下以样式FE )转换。 如果非零,则P等于精度,如果省略精度,则为 6,如果精度为零,则为 1。 然后,如果具有样式E的转换的指数为X

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

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

表示无穷大或 NaN 的参数以fF转换说明符的样式进行转换。

这种行为有点类似于简单地使用%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 在这两种情况下,从有效数中删除无关紧要的尾随零,如果小数点后面没有剩余数字,也将删除小数点。

无论精度如何,正负无穷大、正负零和-inf格式分别为inf-inf0-0nan

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

互联网上的许多来源声称%g只是从%e%f中选择最短的那是完全错误的。

我对 %.3g 感到失望。

值 -154.924... 打印为 -155,

值 0.0206... 打印为 0.0206

1.107 变为 1.11,依此类推。

预期是:

-154.924

0.021

1.107

很奇怪!

我最喜欢的双打格式是“%.15g”。 它似乎在每种情况下都做正确的事情。 我很确定 15 也是双精度数中最大的可靠十进制精度。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM