问题描述
在使用浮点型数据时,通常需要考虑到浮点数的误差问题,有些看似相等的操作,实际上计算机执行起来可能并不是我们想象中的样子。
比如:判断两个Double类型的数据相等该怎么写?
刚学编程时,我想应该是这样:
double x = 0.3;
double y = 0.3;
System.out.println(x == y);
确实也没错
但是当换成 x=0.1+0.2 时,就出问题了,请看JPG
可以看到,当x的值换成 0.1 + 0.2 时,结果就不符合我们预期了,这里就涉及到了浮点数计算当中存在的精度误差问题。
使用包装类的equals也是同理,可以看到,0.1+0.2的计算结果并不是0.3,一串0后边多出来的就是浮点数计算的误差,这是问题的关键。
注:包装类对象为引用数据类型,equals方法比较的是引用对象内的值。
问题分析
包装类的equals方法默认比较的是值的精确性,而不是近似性。因此,在比较两个Double对象的值时,可能会受到浮点数计算的精度问题的影响。
这里的a和b都是Double对象,通过equals方法比较它们的值,结果为false,这是因为0.1+0.2的结果在double类型下实际上是一个近似值0.30000000000000004,而不是精确的0.3,所以值比较不相等。
问题解决
在遇到这种我们认为是相等,但却由于浮点数误差而造成的不等时,我们就需要通过别的办法来处理这个计算误差,使它们的结果变为相等。
常见的办法是通过比较两数之差的绝对值是否小于某一个很小的数(自定义),让它们的比较允许有一个很小的误差,符合误差范围时,即判断它们相等,以这种方式来处理浮点数计算误差。
//基本数据类型
double x = 0.1 + 0.2;
double y = 0.3;
double z = 0.3;
System.out.println(x == y);
System.out.println(y == z);
System.out.println("========");
//包装类
//比较两个Double类型的值
Double a = 0.1 + 0.2;
Double b = 0.3;
System.out.println("a="+a+",b="+b);
// 方法一:使用equals方法判断
if (a.equals(b)) {
System.out.println("a 等于 b");
} else {
System.out.println("a 不等于 b");
}
System.out.println("========");
// 方法二:比较差的绝对值是否小于一个很小的数
double epsilon = 0.0000001; // 定义一个很小的数,即误差范围
if (Math.abs(a - b) < epsilon) {
System.out.println("误差范围内,a 等于 b");
} else {
System.out.println("a 不等于 b");
}
小结
浮点型数据比较方式:
(1)"==":使用于基本数据类型,用于判断两个值是否相等,作用于浮点型数据时,可能会存在误差。使用在包装类引用数据时,比较的是地址。
(2)"equals":使用与包装类对象的值比较,比较的是两个对象的精确值,当出现精度误差时,认为二者不等。
(3)"Math.abs(a - b) < epsilon":比较绝对值误差:可使用于包装类也可使用于基本数据类型,定义一个误差范围,计算差值的绝对值,判断二者是否近似相等。