我的同事做了这个实验。
public class DoubleDemo {
public static void main(String[] args) {
double a = 1.435;
double b = 1.43;
double c = a - b;
System.out.println(c);
}
}
对于这个一级操作,我以为会有这样的输出。
0.005
但出乎意料的是,结果是:
0.0050000000000001155
为什么这么简单的操作,double会失败?而且如果double不是这个工作的数据类型,我应该用什么?
double
在内部存储为一个分数 二进制 -- 譬如 1/4 + 1/8 + 1/16 + ...
价值 0.005
-- 或数值 1.435
--不能作为二进制中的精确分数来存储,所以 double
无法存储确切的数值 0.005
,而且减去的值也不太精确。
如果你关心精确的十进制运算,使用 BigDecimal
.
你也可以找到 本文 有用的阅读。
double和float是 不完全是实数.
在任何范围内有无限数量的实数,但表示它们的位数是有限的! 由于这个原因,双数和浮点数会出现四舍五入的错误。
你得到的数字是最接近的数字,可以用浮点表示的双数来表示。
要了解更多细节,你可能想阅读 本文 [警告:可能是高级别的]。
你可能想使用 BigDecimal
以获得精确的小数[但当你试图获得 1/3
].
double
和 float
算术永远不会完全正确,因为 "引擎盖下 "发生的四舍五入。
本质上,双数和浮点数可以有无限量的小数,但在内存中,它们必须用一些真实的位数来表示。因此,当你进行这种小数运算时,会发生一个四舍五入的过程,如果你把所有的小数都考虑在内,往往会有很小的偏差。
正如前面所建议的,如果你需要完全精确的数值,那么使用 BigDecimal
的存储方式不同。这里是API
//just try to make a quick example to make b to have the same precision as a has, by using BigDecimal
private double getDesiredPrecision(Double a, Double b){
String[] splitter = a.toString().split("\\.");
splitter[0].length(); // Before Decimal Count
int numDecimals = splitter[1].length(); //After Decimal Count
BigDecimal bBigDecimal = new BigDecimal(b);
bBigDecimal = bBigDecimal.setScale(numDecimals,BigDecimal.ROUND_HALF_EVEN);
return bBigDecimal.doubleValue();
}