具有说明符"%g"的printf的精度

css*_*ulu 14 c printf

任何人都可以解释一下[.precision]printf 如何使用说明符"%g"吗?我对以下输出感到困惑:

double value = 3122.55;
printf("%.16g\n", value); //output: 3122.55
printf("%.17g\n", value); //output: 3122.5500000000002
Run Code Online (Sandbox Code Playgroud)

我已经知道%g使用最短的表示法.

但以下的输出仍然让我感到困惑

printf("%.16e\n", value); //output: 3.1225500000000002e+03
printf("%.16f\n", value); //output: 3122.5500000000001819
printf("%.17e\n", value); //output: 3.12255000000000018e+03
printf("%.17f\n", value); //output: 3122.55000000000018190
Run Code Online (Sandbox Code Playgroud)

我的问题是:为什么%.16g给出确切的数字而%.17g不能?

似乎16位有效数字可以准确.谁能告诉我原因?

use*_*443 7

%g 使用最短的表示.

浮点数通常不会作为基数存储10,而是2(性能,大小,实用性原因).但是,无论您的表示基础是什么,总会存在有理数,这些数字在变量存储它们的某个任意大小限制中是不可表达的.

如果您指定%.16g,则表示您希望使用最大16有效数字给出最短的数字表示.

如果最短的表示具有多个16数字,printf将通过2在最末端切割数字来缩短数字字符串,留下您3122.550000000000实际上3122.55以最短形式解释您获得的结果.

一般来说,%g总会给你最短的结果,这意味着如果可以缩短代表你的数字的数字序列而不会损失任何精度,那么它就会完成.

为了进一步举例,当你使用%.17g并且17小数位数包含一个不同于0(2特别是)的值时,你得到了完整的数字3122.5500000000002.

我的问题是:为什么%.16g给出确切的数字而%.17g 不能?

它实际上是%.17g给出精确结果的,同时%.16g只给出一个带有错误的圆角近似值(与内存中的值进行比较).

如果您想要更加固定的精度,请使用%f%F替代.

  • @cssmlulu除了@ user35443的注释之外,`%g`使用有效位数作为其精度说明符.这里有更多解释:[在C中%g和%f之间有什么区别?](http://stackoverflow.com/a/5913115/4895040).其中一个重要数字规定,[非零数字之间的所有零都是重要的.](http://www.usca.edu/chemistry/genchem/sigfig.htm),如果你使用`%.17g将适用``3122.5500000000002`从'5`和'2'之间的零被认为是重要的.这就是包含这些零的原因. (2认同)

Mar*_*ery 7

十进制值 3122.55 不能用二进制浮点精确表示。当你写

double value = 3122.55;
Run Code Online (Sandbox Code Playgroud)

您最终会得到可以精确表示的最接近的可能值。碰巧,该值正是 3122.5500000000001818989403545856475830078125

到 16 位有效数字的那个值是3122.550000000000. 到 17 位有效数字,它是3122.5500000000002. 所以这些都是使交涉%.16g,并%.17g给你。

请注意,double十进制数的最接近表示保证至少精确到 15 位十进制有效数字。这就是为什么在这种情况下您需要打印到 16 或 17 位数字才能开始在输出中看到这些明显的不准确之处 - 对于任何较少数量的有效数字,double表示保证与您输入的原始十进制数相匹配。

最后一点:你说

我了解到%g使用最短的表示。

虽然这是对%g行为方式的流行总结,但它也是错误的。请参阅%g printf 说明符的确切含义是什么?我在这里详细讨论了这个问题,并展示了一个%g使用科学记数法的例子,即使它比不使用科学记数法要长 4 个字符。