问题描述
在开发过程中经常会遇到两种不同类型数据的比较。本文将以double和int类型的比较进行讨论。
首先用以下代码进行举例:
double value= 1.00;
int intValue = (int) value;
String result = value - intValue == 0 ? String.valueOf(intValue) : String.valueOf(value);
此时,当使用静态代码扫描工具时,会提示以下信息:
原因分析:
静态代码分析工具提供的分析:
Floating point math is imprecise because of the challenges of storing such values in a binary representation. Even worse, floating point math is not associative; push a float or a double through a series of simple mathematical operations and the answer will be different based on the order of those operation because of the rounding that takes place at each step.
Therefore, the use of the equality (==) and inequality (!=) operators on float or double values is almost always an error. Instead the best course is to avoid floating point comparisons altogether. When that is not possible, you should consider using one of Java’s float-handling Numbers such as BigDecimal which can properly handle floating point comparisons. A third option is to look not for equality but for whether the value is close enough. I.e. compare the absolute value of the difference between the stored value and the expected value against a margin of acceptable error. Note that this does not cover all cases (NaN and Infinity for instance).
详细分析:
由以上代码可以直接看出存在隐式类型转换。由此会引起精度问题。
由于不能直接将double
和int
类型的数据进行比较,因此我们考虑使用BigDecimal
来进行比较。
可以看到BigDecimal
存在两个方法可以比较数值,分别是compareTo()和equals()方法。先说结论,在比较两个数值时,必须使用compareTo()方法。
在源码注释中能看到 equals() 方法不像 compareTo() 方法,equals() 方法考虑到value(值)和 scale(精度)两个因素。
再做一个简单的测试:
public static void main(String[] args) {
int value = 1;
double dvalue = 1.00;
BigDecimal bd1 = new BigDecimal(value);
BigDecimal bd2 = BigDecimal.valueOf(dvalue);
BigDecimal bd3 = bd1.subtract(bd2);
boolean isE = bd1.equals(bd2);
boolean isE1 = dvalue - value == 0.0d ? true : false;
boolean isE2 = dvalue == value ? true : false;
int isE3 = bd1.compareTo(bd2);
System.out.println(bd1 + "--" + bd2 + "--" + isE);
System.out.println(bd3);
System.out.println(isE1);
System.out.println(isE2);
System.out.println(isE3);
}
测试结果如下:
1–1.0–false
0.0
true
true
0
解决方案:
通过以上测试及验证,使用BigDecimal
的compareTo()方法,可以解决double
和int
的比较问题。
double value = 1.00;
int intValue = (int) value;
BigDecimal bdIntValue = new BigDecimal(intValue);
BigDecimal bdValue = BigDecimal.valueOf(value);
String result = bdIntValue.compareTo(bdValue) == 0 ? String.valueOf(intValue) : String.valueOf(value);