关于浮点精度:为什么迭代次数不相等?

时间:2011-06-25 10:23:37

标签: matlab floating-point

有两个类似的matlab程序,一个迭代10次,另一个迭代11次。

一:

i = 0;
x = 0.0;
h = 0.1;
while x < 1.0
    i = i + 1;
    x = i * h;
    disp([i,x]);
end

另:

i = 0;
x = 0.0;
h = 0.1;
while x < 1.0
    i = i + 1;
    x = x + h;
    disp([i,x]);
end

我不明白为什么浮点添加操作和多重操作之间存在差异。

3 个答案:

答案 0 :(得分:4)

使用浮点计数器进行迭代时,您应该非常小心。作为一个例子,我将告诉你在你的情况下发生了什么(这是一个Java程序,但你的情况应该是相同的):click here to run it yourself

double h = 0.1;
System.out.println(10*h-1.0);
System.out.println(h+h+h+h+h+h+h+h+h+h-1.0);

它只是在执行乘法与seprarate添加时将差异打印为1。

由于浮点数的表示不准确,结果如下所示:

0.0
-1.1102230246251565E-16

因此,如果在后一种情况下将其用作循环条件,则会有一个额外的迭代(尚未达到一个)。

尝试使用计数器变量i这是一个整数,你不会遇到这样的问题。

答案 1 :(得分:2)

比较以下内容的输出:

>> fprintf('%0.20f\n', 0.1.*(1:10))
0.10000000000000001000
0.20000000000000001000
0.30000000000000004000
0.40000000000000002000
0.50000000000000000000
0.60000000000000009000
0.70000000000000007000
0.80000000000000004000
0.90000000000000002000
1.00000000000000000000

>> fprintf('%0.20f\n', cumsum(repmat(0.1,1,10)))
0.10000000000000001000
0.20000000000000001000
0.30000000000000004000
0.40000000000000002000
0.50000000000000000000
0.59999999999999998000
0.69999999999999996000
0.79999999999999993000
0.89999999999999991000
0.99999999999999989000

还要与使用MATLAB的COLON运算符进行比较:

>> fprintf('%0.20f\n', 0.1:0.1:1)
0.10000000000000001000
0.20000000000000001000
0.30000000000000004000
0.40000000000000002000
0.50000000000000000000
0.59999999999999998000
0.69999999999999996000
0.80000000000000004000
0.90000000000000002000
1.00000000000000000000

如果要查看64位二进制表示,请使用:

>> format hex
>> [(0.1:0.1:1)' (0.1.*(1:10))' cumsum(repmat(0.1,10,1))]
   3fb999999999999a   3fb999999999999a   3fb999999999999a
   3fc999999999999a   3fc999999999999a   3fc999999999999a
   3fd3333333333334   3fd3333333333334   3fd3333333333334
   3fd999999999999a   3fd999999999999a   3fd999999999999a
   3fe0000000000000   3fe0000000000000   3fe0000000000000
   3fe3333333333333   3fe3333333333334   3fe3333333333333
   3fe6666666666666   3fe6666666666667   3fe6666666666666
   3fe999999999999a   3fe999999999999a   3fe9999999999999
   3feccccccccccccd   3feccccccccccccd   3feccccccccccccc
   3ff0000000000000   3ff0000000000000   3fefffffffffffff

一些建议的读数(与MATLAB相关):

答案 2 :(得分:0)

浮点数的表示是精确的,除了浮点运算在基数2中,小数(如0.1)具有无限的二进制扩展。由于浮点数具有有限的位数,因此必须舍入0.1的无限扩展,并且在加法时累积误差累积,导致差异。

但是,大多数浮点操作都是不精确的:结果USUALLY需要比固定位数更多的精度位,因此CPU自动舍入结果以适应可用的精确。正如您所注意到的,这种舍入误差会累积在长计算链中,并导致实际与“正确”结果之间存在巨大差异。 (“正确”被定义为在无限精度算术中获得的结果。)