论坛首页 Java企业应用论坛

浮点数运算的陷阱

浏览 4151 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (2) :: 隐藏帖 (4)
作者 正文
   发表时间:2010-04-03  
    浮点数的运算不能说是精确的,因为某些数字不能准确表示为二进制(例如: 0.1),以下是一个用浮点数运算的例子,例子证明了我们应该慎用浮点数运算。

/**
 * @author crane.ding
 */
public class Test {

	public static void main(String[] args) {
		final float ff = 0.6f + 0.1f;
		final double fd = 0.6f + 0.1d;
		final double df = 0.6d + 0.1f;
		final double dd = 0.6d + 0.1d;
		
		System.out.println(ff + " : " +(ff == 0.7f));
		System.out.println(fd + " : " +(fd == 0.7d));
		System.out.println(df + " : " +(df == 0.7d));
		System.out.println(dd + " : " +(dd == 0.7d));

		System.out.println("\nfloat");
		for (float f = 0; f < 1; f = f + 0.1f)
			System.out.println(f);
		
		System.out.println("\ndouble");
		for (double d = 0; d < 1; d = d + 0.1)
			System.out.println(d);
	}

}

运行结果如下:
0.70000005 : false
0.7000000238418579 : false
0.7000000014901161 : false
0.7 : true

float
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.70000005
0.8000001
0.9000001

double
0.0
0.1
0.2
0.30000000000000004
0.4
0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999

从以上的运行结果我们不难看出,浮点数的运算是有误差的,例如0.2加0.1就不等于0.3;对于金额的运行如果采用浮点数,那计算出来的金额就不一定是准确的;这也是许多程序开发人员经常接触,而未考虑到的一个小陷阱。
   发表时间:2010-04-04  
不是未考虑,用BigDecimal,而且这样的文章这里也有不少的.
0 请登录后投票
   发表时间:2010-04-04  
呵呵! 是啊,昨天突然想到就在博客上做一下笔记记下来! BigDecimal的目的就是精确的表示小数,但是其开销也是挺大的。BigDecimal对象是不可变的,每一次操作都会产生新的BigDecimal对象,显然BigDecimal不太适合大量的数据运算。
0 请登录后投票
   发表时间:2010-04-06  
那最好的方式应该怎么处理呢!
0 请登录后投票
   发表时间:2010-04-08  
如果能确保一些前提的话,用double也是可行的。
至少应该确认数字的精度要求在一定数量内、总位数在一定数量内。
这时候所谓的陷阱根本不是问题,完全可以用其他方式搞定。
比较时用差数小于一定值。比如人民币用0.001。
再比如说数据库指定长度而不是傻乎乎的Number/Decimal,输出加format等等。

但保证累计误差问题就麻烦了,呵呵,碰上来回加减的就知道厉害了。
比如说一系列成本按比例拆分到若干部门/业务,有些钱数很大,累计拆下来累计误差可能就够收支对不齐了。
在财务眼里这属于对他们的屠杀兼IT自杀。

再举个例子,对人民币可以用0.001以内当相等。
但有带三位小数的钱,比如说突尼斯。得改成四位小数判等。
又有钱超级不值钱数额很大的,考虑钱数上线的时候可能要按10以内算相等。
虽然说用BigDecimal类似问题也偶尔需要考虑,但总归少多了。

如果用double,等修改钱数范围的时候就知道想撞墙是什么意思了。
大家都知道,能在变更的时候把这么细节的修改涉及的所有地方都想到的是超人。
所以没明确证据表明确实是BigDecimal影响性能到不可用、且其他修改更困难之前,还是用BigDecimal吧。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics