在c中浮动奇怪的不精确错误

时间:2014-12-23 13:39:28

标签: c floating-point floating-accuracy approximation

今天发生了一件奇怪的事情,当我尝试编译并执行此代码的输出并不是我所期望的。下面的代码只是将浮动值添加到float数组中,然后将其打印出来。 简单的代码:

int main(){
    float r[10];
    int z;
    int i=34;
    for(z=0;z<10;z++){
        i=z*z*z;
        r[z]=i;
        r[z]=r[z]+0.634;
        printf("%f\n",r[z]);
    }
}

输出:

0.634000
1.634000
8.634000
27.634001
64.634003
125.634003
216.634003
343.634003
512.633972
729.633972

请注意,从.634之后的27个出现的数字应该不存在。谁知道为什么会这样?这是由浮点近似引起的事件?..

P.S我有一个linux debian系统,64位

感谢所有

4 个答案:

答案 0 :(得分:5)

数字可以用以下形式表示:

  

[sign] [尾数] * 2 [指数]

当内存空间较小时,会出现舍入或相对错误。

来自wiki

  

单精度浮点格式是计算机数字格式,在计算机内存中占用 4字节(32位),并使用浮点表示宽动态范围的值。

enter image description here

IEEE 754标准将binary32指定为:

Sign bit: 1 bit
Exponent width: 8 bits
Significand precision: 24 bits (23 explicitly stored)
  

这从 6到9有效十进制数字精度(如果a   最多6个有效小数的十进制字符串转换为IEEE   754单精度然后转换回相同的数量   有效小数,则最终字符串应与原始字符串匹配;   如果IEEE 754单精度转换为十进制字符串   至少有9个有效小数,然后转换回单个,   那么最终的数字必须与原来的[4]相匹配。

编辑(爱德华的评论):更大(更多位)的浮点表示允许更高的精度

答案 1 :(得分:1)

是的,这是floating point近似误差或Round-off error。浮点数表示使用quantization来表示大范围的数字,因此它仅表示步骤并将所有中间数字舍入到最近的步骤。如果所需数字不是这些步骤之一,则会导致错误。

答案 2 :(得分:1)

除了其他有用的答案外,可以说明打印的数字多于默认数字:

int main(){
    float r[10];
    int z;
    int i=34;
    for(z=0;z<10;z++){
        i=z*z*z;
        r[z]=i;
        r[z]=r[z]+0.634;
        printf("%.30f\n",r[z]);
    }
}

给出

0.634000003337860107421875000000
1.633999943733215332031250000000
8.633999824523925781250000000000
27.634000778198242187500000000000
64.634002685546875000000000000000
125.634002685546875000000000000000
216.634002685546875000000000000000
343.634002685546875000000000000000
512.633972167968750000000000000000
729.633972167968750000000000000000

请注意,0.634实际上并不是#34; 0.634&#34;,而是float代表的最接近的数字。

答案 3 :(得分:0)

“float”只有大约六位数的精度,所以你得到的错误并不意外。

如果使用“double”,则精度约为15位。你出错,但你会得到125.634000000000003而不是125.634003。

因此,您总会得到四舍五入的错误,而您的结果将不会完全您所期望的,但通过使用双倍效果将是最小的。警告:如果您执行添加125 + 0.634然后减去125的操作,结果将(很可能)为0.634。无论你使用float还是double。但是加倍,结果将非常非常接近0.634。

原则上,如果选择float和double,除非你有一个非常非常好的理由,否则你不应该使用float。