具有说明符“%g”的printf的精度

时间:2015-06-05 05:26:21

标签: c printf

有人能解释一下printf中[.precision]如何使用说明符“%g”吗?我对以下输出感到困惑:

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

我了解到%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

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

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

3 个答案:

答案 0 :(得分:5)

%g使用最短的表示。

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

当您指定%.16g时,您表示您希望使用最多16个有效数字来表示最短的数字。

如果最短的代表性数字超过16printf会缩短数字字符串,方法是剪切最后的2数字,然后留下3122.550000000000 ,实际上是最短形式的3122.55,解释了你获得的结果。

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

为了进一步举例,当您使用%.17g并且17小数点包含的值不同于0(特别是2)时,您最终得到了完整号码3122.5500000000002

  

我的问题是:为什么%.16g会给出%.17g时的确切数字   可'?吨

实际上%.17g为您提供了准确的结果,而%.16g只给出了一个带有错误的圆角近似值(与内存中的值进行比较)。

如果您想要更加固定的精度,请改用%f%F

答案 1 :(得分:0)

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

double value = 3122.55;

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

该16位有效数字的值为3122.550000000000。对于17个有效数字,它是3122.5500000000002。这些就是%.16g%.17g给您的代表。

请注意,十进制数字的最接近double表示形式至少可以精确到15个十进制有效数字。因此,在这种情况下,您需要打印到16或17位数字才能开始在输出中看到这些明显的不正确之处-对于任何较小的有效数字,double表示形式都必须与您键入的原始十进制数字匹配

最后一点:你这么说

  

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

尽管这是关于%g行为的流行总结,但这也是错误的。请参阅What precisely does the %g printf specifier mean?,在其中进行详细讨论,并显示使用科学记数法的%g的示例,即使比不使用科学记数法的时间长4个字符。

答案 2 :(得分:0)

十进制表示3122.55不能精确地用二进制浮点表示形式表示。

双精度二进制浮点值可以正确表示十进制值的大约15个有效数字(注意不要小数位数);此后的数字可能不相同,并且在极端情况下甚至没有任何实际意义,这将是从浮点表示形式转换为十进制数字字符串的伪像。

  

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

规则是:

其中 P 是精度(如果未指定精度,则为6,如果precision为零,则为1),而 X 是E / e样式表示法所需的十进制指数然后:

  • 如果 P > X ≥-4 ,则转换的样式为f或F,精度为 P < / em>-1- X
  • 否则,转换的样式为e或E,精度为 P − 1

InputArtifacts precision 的修改导致以下输出不同:

%g

尽管在格式说明符中具有相同的精度。