假设我们想以两种不同的方式计算(a + b) 2 ,即
(a + b)*(a + b)
a 2 + 2 a b + b 2
现在,假设b = -2.7
和format long
。如果我们使用1.690000000000001
在公式中插入这两个数字,我们会在a = 1.4;
b = -2.7;
format long
r = (a + b) * (a + b)
r2 = a^2 + 2*a*b + b^2
abs_diff = abs(r - r2)
两种情况下获得,也就是说,如果我运行以下脚本:
r = 1.690000000000001
r2 = 1.690000000000001
abs_diff = 6.661338147750939e-16
我获得了
r
这里发生了什么?我可以预览r2
或r
的不同结果(因为Matlab将执行不同的浮点运算),但不能预测它们差异的绝对值。
我还注意到r2
和rel_err1 = abs(1.69 - r) / 1.69
rel_err2 = abs(1.69 - r2) / 1.69
的相对误差是不同的,也就是说,如果我这样做
rel_err1 = 3.941620205769786e-16
rel_err2 = 7.883240411539573e-16
我获得了
r
这只会让我觉得r2
实际上并不是eps / 2
。有没有办法完全看到它们,如果它们真的不同?如果没有,发生了什么?
此外,两个相对误差都不小于{{1}},这是否意味着发生溢出?如果是的话,在哪里?
注意:这是一个特例。我知道我们正在处理浮点数和舍入错误。但是我希望通过这个例子来更好地理解它们。
答案 0 :(得分:3)
不要依赖format long
的输出来得出两个数字相等的结论......
a = 1.4;
b = -2.7
r1 = (a + b) * (a + b);
r2 = a^2 + 2*a*b + b^2;
r3 = (a+b)^2;
相反,您可以使用以下方法检查其十六进制表示:
>> num2hex([r1 r2 r3])
ans =
3ffb0a3d70a3d70d
3ffb0a3d70a3d710
3ffb0a3d70a3d70d
或printf
系列函数:
>> fprintf('%bx\n', r1, r2, r3)
3ffb0a3d70a3d70d
3ffb0a3d70a3d710
3ffb0a3d70a3d70d
甚至:
>> format hex
>> disp([r1; r2; r3])
3ffb0a3d70a3d70d
3ffb0a3d70a3d710
3ffb0a3d70a3d70d
答案 1 :(得分:1)
Floating point arithmetic is not associative
虽然在数学上这两个是相等的,但它们不是浮点数学。
r = (a + b) * (a + b)
r2 = a^2 + 2*a*b + b^2
在浮点数学中执行的顺序操作非常相关。这就是为什么当你做浮点数学时你需要非常小心你的乘法/除法的顺序,特别是在使用非常大的数字和非常小的数字时。