码迷,mamicode.com
首页 > 其他好文 > 详细

一个由于浮点数精度导致的错误

时间:2015-05-22 22:21:04      阅读:835      评论:0      收藏:0      [点我收藏+]

标签:

 

 

今天看到一篇文章:http://younglab.blog.51cto.com/416652/241886,大概是说在使用Javascript进行下面的浮点数计算时出现了问题:

obj.style.opacity =  (parseInt(obj.style.opacity *100) + 1)/100;

obj.style.opacity是一个浮点数,范围从0~1,初始值为0。这句代码每隔一小段时间执行一次,从而让目标由透明慢慢变为不透明(淡入效果)。起初,obj.style.opacity能够按照预期的每次以0.01逐步增加,但增加到0.29时就一直保持不变了。

作者只是记录了这个问题,没有写出为什么。读完这篇博客后我的第一感觉是:这又是一个由于浮点数精度所引发的问题。

下面让我们来写一个小程序重现一下这个问题。

double opacity = 0;

for (int i = 0; i < 100; i++) {
     System.out.println("opacity=" + opacity);
     System.out.println("opacity*100=" + (opacity * 100));
     System.out.println("----------------------------");

     opacity = ((int) (opacity * 100 + 1)) / 100.0;
}

程序是用Java写的,共执行100次循环,采用了与那篇文章中相同的计算方法。正常情况下opacity会由0逐步增大到1。

由于Java和JS采用的是相同的浮点数格式,所以结果是相同的。下面是程序的输出内容:

opacity=0.0
opacity*100=0.0
----------------------------
opacity=0.01
opacity*100=1.0
----------------------------
opacity=0.02
opacity*100=2.0
----------------------------
opacity=0.03
opacity*100=3.0

(中间省略……)

opacity=0.27
opacity*100=27.0
----------------------------
opacity=0.28
opacity*100=28.000000000000004
----------------------------
opacity=0.29
opacity*100=28.999999999999996
----------------------------
opacity=0.29
opacity*100=28.999999999999996

……后面一直重复相同的内容

可以发现,当opacity的值为0.29时,实际上在内存中的准确值是0.28999999999999996,因为Java在将浮点数转换为字符串时会做一些处理,让结果看起来更“美观”一些,所以会将其转成“0.29”。这一点在乘以100以后就比较明显了。

由于0.29在内存中实际保存的是0.28999999999999996,所以当乘以100变成28.999999999999996后强制转换为整数后,结果是28而不是期望的29。而这正是导致这个问题的真正原因。

需要注意的是,在这段程序中,除数必须写成100.0。这是由于在Java中有整数除法和浮点数除法两种不同的运算,如果写成100,那么被除数和除数将都是整数,Java就会按照整数除法来计算,就会导致每次计算的结果都是0。JS里没有这个问题,因为JS没有整数除法,所有除法都会当成浮点数除法来对待。

总结

只要稍有经验的程序员都知道浮点数不能直接进行相等比较,但是像这篇文章中所介绍的问题可能并不那么常见,因此有时不容易意识到发生了问题。

每个程序员都应该知道计算机中是采用近似值来保存浮点数的,当进行浮点数相关的计算时,需要时刻提防由于精度问题所导致的误差,并注意避免那些会影响到结果正确性的误差(所谓正确性,就是误差超出了所允许的最大范围)。


附:由于计算问题引起的软件灾难
http://ta.twi.tudelft.nl/users/vuik/wi211/disasters.html

 

一个由于浮点数精度导致的错误

标签:

原文地址:http://www.cnblogs.com/antineutrino/p/4523257.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!