使用fscanf从文件中读取浮点数

时间:2016-09-30 18:39:25

标签: c

我有一个多行文件。第一行包含整数N,后跟正好N行,其中每行包含一对由空格分隔的浮点数。每个浮点数都有两位小数。现在我有以下简单的代码,它将浮点数存储在内存中并打印出来。

    #include <stdio.h>
    #include <stdlib.h>

    struct coordinates {
         float x;
         float y;
    };

    typedef struct coordinates coords;

    int main(int argc, char** argv) {
      unsigned int N, i;
      coords *points;
      FILE *fp;

      if (argc != 2) {
          printf("Usage: ./bigCircle <input_file>\n");
          exit(0);
      }
      fp = fopen(argv[1], "r");
      N = fscanf(fp, "%u", &N);

      points = (coords *)malloc(N*sizeof(coords));
      for (i=0; i<N; i++) {
          fscanf(fp, "%f %f", &points[i].x, &points[i].y);
          printf("%f %f\n", points[i].x, points[i].y);
      }

      return 0;
   }

问题在于,打印的浮点数具有更多的非零十进制数字,并且仅在四舍五入到小数点后第二位时才成为正确的十进制数字。例如,对于

  99999.72 -50167.43

我的程序打印

  99999.718750 -50167.429688

为什么会这样?为什么我没有

  99999.720000 -50167.430000

4 个答案:

答案 0 :(得分:1)

一旦将数字以二进制浮点格式放入该位置,它就会被数字化。您的计算机无法准确表示此数字。因此,输出不完全是您输入的数字。

您的输出"%f"未指定两位小数作为限制。因此,当它尝试输出您已读入的值时,它将输出更多数字。

作为一个例子,考虑数字1.3。小数点右边的数字,因为它是十进制数,不能用二进制格式精确表示。由于您已在示例中看到过,请尝试将.5(十进制)转换为二进制(即.1)。

作为一个例子,考虑值1/8(2 ^ -3)这是八进制的0.1。但是,十进制为.125,二进制为.001。它可以准确地表达,因为它是2的整数幂。除非数字可以表示为有限数量的2的总和,它永远不能在计算机中完全表达。

答案 1 :(得分:1)

这非常简单 - 这是格式可以编码的数字的问题。

考虑一个整数。它可以表示0,1,2,...等值。

但它不能代表1.2,3.4 ......等数字。

浮子也是如此!它不能代表所有数字。

例如:99999.72可能无法准确编码,因此最接近的值(可能是99999.718750)就是您最终得到的结果。

因此数字将四舍五入到最接近的可表示数字。

答案 2 :(得分:1)

float在内部表示为二进制浮点数。当我们在基数10中表示数字时,我们有类似的东西:

1.625 = 1 + 6/10 + 2/100 + 5/1000

表示可以用基数10表示法精确表示的数字。然后,在二进制中我们可以表示相同的数字:

1.625(base 10) = 1 + 1/2 + 0/4 + 1/8 => 1.101(base 2)

所以,这里我们有一个这个数字的精确二进制表示。但是,一些在基数10中具有精确表示的数字不具有float的精确表示,因为内部表示是二进制的:

1.72(base 10) = 1 + 7/10 + 2/100, but

1.72(base 10) = 1 + 1/2 + 0/4 + 1/8 + 1/16 + 1/32 + 0/64
               + 0/128 + 0/256 + 0/512 + 1/1024 + ...

最后的部分总和给出:

1.1011100001(base 2) => 1.71972656(base 10) != 1.72.

因此,确切的二进制表示可能很大,以适应可用存储,或者可能没有精确的二进制表示!

顺便提一下,1.10111(基数2)=&gt; 1.71875(基数10)。鉴于你看到了99999.718750而不是99999.72,我猜你的float的小数部分有8位可用。

答案 3 :(得分:0)

尝试替换:

printf("%f %f\n", points[i].x, points[i].y);

与此:

printf("%.2f %.2f\n", points[i].x, points[i].y);

通过上述内容,您告诉printf打印第一个。实数的X十进制数字(在我们的例子中为2)。第一个打印整个浮点数