为什么 C 打印小数点后的浮点值与输入值不同?

Why does C print float values after the decimal point different from the input value?

为什么C打印小数点后的浮点数与输入值不同?

代码如下

代码:

#include <stdio.h>
#include<math.h>
void main()
{
    float num=2118850.132000;
    printf("num:%f",num);
}

输出:

num:2118850.250000

这应该打印 2118850.132000,但它却将小数点后的数字更改为 .250000.为什么会这样? 另外,如何避免这种情况? 请指导我。

如果您使用 double 而不是 float,这将起作用:

#include <stdio.h>
#include<math.h>
void main()
{
    double num=2118850.132000;
    printf("num:%f",num);
}

您的计算机内部使用 二进制 浮点数。类型 float 具有 24 位精度,转换为 大约 7 位十进制精度。

您的号码 2118850.132 的精度为 10 位小数。所以我们马上就可以看出,可能无法将这个数字精确地表示为 float.

另外,由于二进制数的特性,以1、2、3、4、6、7、8、9结尾的小数(即0.1、0.2、0.132等数字)不能以二进制精确表示。所以这些数字总是会遇到一些转换或舍入错误。

当您输入数字 2118850.132 作为 float 时,它会在内部转换为二进制分数 1000000101010011000010.01。这相当于小数部分 2118850.25。这就是为什么 .132 似乎被转换为 0.25 的原因。

正如我提到的,float 只有 24 位精度。您会注意到 1000000101010011000010.01 正好是 24 位长。因此,例如,我们不能通过使用 1000000101010011000010.001 之类的东西来更接近您的原始数字,这相当于 2118850.125,这将更接近您的 2118850.132。不是,下一个24位小数是1000000101010011000010.00,相当于2118850.00,再高一个是1000000101010011000010.10,相当于2118850.50,这两个都离你的2118850.132更远。所以 2118850.25 和 float.

一样接近

如果您使用 double 类型,您可以更接近。类型 double 具有 53 位精度,可转换为大约 16 位十进制数字。但是您仍然遇到 .132 以 2 结尾的问题,因此永远无法用二进制精确表示。作为类型 double,您的数字将在内部表示为二进制数 1000000101010011000010.0010000111001010110000001000010(注意 53 位),相当于 2118850.132000000216066837310791015625,它更接近您的 2118850.132,但仍然不准确。 (另请注意,2118850.132000000216066837310791015625 在 16 位数字后开始与您的 2118850.1320000000 不同。)

那么如何避免这种情况呢?在一个层面上,你不能。这是有限精度浮点数的一个基本限制,它们不能完美地表示 all 实数。此外,计算机通常在内部使用二进制浮点数这一事实意味着它们几乎永远无法准确表示像 .132 这样“看起来很精确”的小数。

您可以做两件事:

  1. 如果你需要超过 7 位的精度,一定要使用类型 double,不要尝试使用类型 float.
  2. 如果您认为您的数据精确到小数点后三位,请使用 %.3f 将其打印出来。如果您将 2118850.132 作为 double,并使用 %.3f 打印它,您将得到 2118850.132,如您所愿。 (但是如果你用 %.12f 打印它,你会得到误导性的 2118850.132000000216。)