c - %g printf 说明符究竟是什么意思?
问题描述
说明%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;
}
...然后我看到这个输出:
1.234560e+05
123456.000000
123456
1.234567e+06
1234567.000000
1.23457e+06
显然,%g
输出不完全匹配其中一个或以上的%e
或%f
输出。更重要的是,它看起来也不是最小化输出长度;如果它没有以科学记数法打印,则可以更简洁地格式化。x
y
%g
y
x
我上面引用的所有消息来源都是在骗我吗?
我在支持这些格式说明符的其他语言中看到了相同或相似的行为,这可能是因为它们在后台调用了printf
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
控制这个输出的逻辑是什么?
解决方案
这是C11 标准中g
/说明符的完整描述:G
根据转换的值和精度,表示浮点数的双
f
精度参数以样式或e
(或以样式F
或E
在G
转换说明符的情况下)进行转换。如果不为零,则令P等于精度,如果省略精度,则令 P 等于 6,如果精度为零,则令 P 等于 1。然后,如果带有样式的转换E
的指数为X:如果P > X ≥ −4,则转换为样式
f
(orF
) 和精度P − (X + 1)。
否则,转换为样式e
(orE
) 和精度P − 1。最后,除非使用#标志,否则将从结果的小数部分删除任何尾随零,如果没有剩余小数部分,则删除小数点字符。
表示无穷大或 NaN的双
f
参数以orF
转换说明符的样式进行转换。
这种行为有点类似于简单地使用 and 中的最短表示%f
,%e
但不是等效的。有两个重要的区别:
- 使用 时,尾随零(可能还有小数点)会被去除
%g
,这可能导致说明符的输出与任何一个或将产生的%g
内容不完全匹配。%f
%e
- 关于是否使用
%f
-style 或%e
-style 格式的决定纯粹基于%e
-style 表示法中所需的指数大小,而不直接取决于哪种表示会更短。在几种情况下,此规则会导致%g
选择更长的表示形式,例如问题中显示的%g
使用科学记数法的情况,即使这会使输出的 4 个字符比需要的长。
如果 C 标准的措辞难以解析,Python 文档提供了相同行为的另一种描述:
一般格式。对于给定的精度,这会将数字四舍五入为
p
>=
1
有效数字,然后根据其大小将结果格式化为定点格式或科学记数法。
p
精确的规则如下:假设用表示类型
和精度格式化的结果
'e'
将具有 exponent
p-1
。然后如果
exp
,数字被格式化为表示类型
-4
<=
exp
<
p
和精度
'f'
。否则,数字将使用presentation type
p-1-exp
和precision进行格式化
'e'
。在这两种情况下,从有效数字中删除无关紧要的尾随零,如果小数点后面没有剩余数字,则也将删除小数点。
p-1
无论精度如何,正负无穷、正负零和 nan 的格式分别为、
的精度、
inf
和 。
-inf
0
-0
nan
被视为等同于 的精度
0
。默认精度为
1
.
6
互联网上的许多消息来源声称%g
只选择最短的%e
并且%f
完全是错误的。
推荐阅读
- ruby-on-rails - 创建预签名帖子时,AWS SDK 不包括 X-Amz-Credential 中的访问密钥 (AKID),但仅在 Heroku 上
- elm - 具有默认值的 Elm 类型别名
- python - 如何使 python ide 在高 dpi 显示器上工作而不会模糊
- java - 在 JAVA 中这种排序叫什么?
- metal - 正确的是将数组从 Metal Kernel 函数传递给本地函数
- java - android - 如何从另一个布局声明一个小部件?
- android-studio - 应用程序退出时出现未处理的异常
包含 - java - Firebase android 可以在模拟器上运行,但不能在设备上运行
- aws-lambda - 使用 Amazon 登录以获得 Alexa Skills (LWA)
- sql - 如何在 SQL 中对一组元素进行大小写