我有一段代码重复地减少从1开始的变量。经过两次迭代后,结果是不精确的,这是一个惊喜。
有效过程可以通过以下两行显示:
>> (1 - 0.1) - 0.9
0
>> (1 - 0.05 - 0.05) - 0.9
-1.110223024625157e-16
第二种情况的结果在Matlab和Octave中都不为零。
同样,以下C代码显示了问题:
#include <stdio.h>
void main () {
double x1, x2;
x1=1-0.05-0.05;
x2=1-0.1;
printf("x1 exact:%d, x2 exact:%d\n", x1==0.9, x2==0.9);
}
在Intel Xeon(R)CPU E5-2680上使用gcc版本4.7.0编译,结果是
x1 exact:0, x2 exact:1
表明第一次计算是不精确的,而第二次计算是精确的。
我可以通过使用long double(后缀&#34; L&#34;对于所有文字,以及声明为long double的变量)在C中克服此问题。这让我有点困惑:我认为不精确的结果可以解释为0.05在基数2中没有精确的表示;但是使用long double并不能改变这个事实......那么为什么结果会有所不同呢?
我真正想要的是在Matlab中克服它的方法。有什么想法吗?
有趣的是,在这两种情况下,同样计算的MS Excel结果都是准确的。
答案 0 :(得分:2)
如您所知,0.1
和0.9
等十进制数字在二进制文件中没有精确的表示形式。所以如果你做这样的事情:
float f = 0.1;
if(f * 9 == 0.9)
printf("exact\n");
else
printf("inexact\n");
,或者如果您在原始问题中编写代码,它可能会打印&#34;确切&#34;,它可能会打印&#34;不精确&#34;,这取决于...各种各样的事情。在我看来,不值得花太多时间试图找出原因或原因。如果它打印出来&#34;不精确&#34;,好吧,我们知道为什么,它一开始并不准确。如果它打印&#34;确切&#34;,我们得到了#34;幸运&#34; - 某些不确定的地方相互取消了某些东西 - 或者其他东西 - 但我们不能依赖它,所以它不是很有趣。
由于我们不能指望它,我们必须编写在打印时执行适当舍入的代码,或者使用&#34;足够接近&#34;平等比较。一旦我们编写了该代码,它就能正常工作,无论具体的比较是否具有任何机会,似乎都有效。
答案 1 :(得分:1)
...结果是......表明第一次计算是不精确的,而第二次计算是精确的。
此推断不正确。 1 - .05 - .05 == .9
为false且1 - .1 == .9
为真的事实表明,计算1 - .05 - .05
中出现的舍入错误不会产生等于.9
的结果,而是舍入错误计算1 - .1
中出现的结果会产生等于.9
的结果。由于在源代码中使用.9
的浮点结果本身不是.9,1 - .1
等于.9
这一事实并不意味着1 - .1
是准确的。它只是意味着它与.9
有相同的舍入误差。
在表达式1 - .1 == .9
中,有三个舍入错误:
.1
从源代码中的十进制数字转换为二进制浮点值时,结果不是.1,而是0.1000000000000000055511151231257827021181583404541015625。.9
从源代码中的十进制数字转换为二进制浮点值时,结果为0.90000000000000002220446049250313080847263336181640625。恰好,舍入错误在双方都产生了相同的结果,因此对等式的测试评估为真。
在计算1 - .05 - .05
时,舍入错误为:
.05
转换为0.05000000000000000277555756156289135105907917022705078125。1 - .05
的结果为0.9499999999999999555910790149937383830547332763671875。1 - .05 - .05
的结果为0.899999999999999911182158029987476766109466552734375`。这里发生的事情是,在减去1 - .05
时,碰巧附近的可表示值略小于.95。因此,当减去.05
时,我们看到的略大于.05,我们从略低于.95的东西中减去略大于.05的东西。这种错误组合产生的数学结果足够.9,它更接近下一个较低的可表示值0.89999999999999911182158029987476766109466552734375,而不是0.90000000000000002220446049250313080847263336181640625。
当您使用long double
进行类似的计算时,舍入误差恰好不同。在以这些方式检查浮点计算时,long double
不会优于double
计算结果恰好落在您获得的相同结果上的频率理想的数学。在您的示例中可能已经发生了您选择的数字,但使用其他数字会产生有效的随机结果,就好像每个计算都有一个随机错误向上或向下一步。如果这些错误恰好在两个不同的计算中具有相同的净效应,那么这两个结果是相等的。如果这些错误恰好具有不同的净效应,则两个结果不相等。