2016-09-30 98 views
1

我有一个多行文件。第一行包含一个整数N,后面紧跟着N行,其中每行包含一对由空格分隔的浮点数。每个浮点数都有两个十进制数字。现在我有以下简单的代码,它将浮点数存储在内存中并将它们打印出来。使用fscanf从文件中读取浮动文件

#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 

+0

因此不能表示激动,你会得到这样的值。 – ameyCU

+0

输入文件?但答案很简单:浮点数并不准确。 – 4386427

+1

如果你把'float'放在bin中并且开始使用'double',这当然不会那么糟糕。在这种情况下,你必须使用'浮动',但通常它们是20世纪教科书中的遗物。 –

回答

1

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

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

举一个例子,考虑数字1.3。小数点右边的数字,因为它是十进制数,所以不能用二进制格式精确表示。既然你已经在你的例子中看到了,尝试将.5(十进制)转换为二进制(即.1)。

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

+0

但'1.5' **可以准确地表示出来,因为'.5'是** ** **。 –

+0

@WeatherVane是的,我意识到我的错字。这就是为什么我将它改为1.3 – sabbahillel

+0

好,但你仍然提到'.5' –

0

尝试更换:

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

与:

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

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

1

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

考虑一个整数。它可以代表的数值如0,1,2,...

但它不能代表相同的1.2,3.4号,...

这同样适用于浮动真!它不能代表所有数字。

例如:99999.72可能未被准确编码,因此最接近的值(可能是99999.718750)就是最终结果。

所以这些数字将四舍五入到最接近的可表示数字。

1

A float在内部表示为二进制浮点数。当我们代表基地10多家,我们有这样的:对于能够准确地在基地10表示法为代表的一批

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

。然后,在二进制就可以表示相同的号码为:

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

所以,在这里我们有这个数字的准确的二进制表示。但是,一些数字有确切的表示以10为基数没有确切的表述为float S,因为内部表示二进制:

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)=> 1.71875(基数10)。假设你看到的是99999.718750而不是99999.72,我猜你有8位可用于你的float的小数部分。