双减法精度问题
我的同事做了这个实验:
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
在内部存储为二进制的分数 – 如1/4 + 1/8 + 1/16 + ...
值0.005
– 或值1.435
– 不能以二进制forms存储为精确分数,因此double
不能存储精确值0.005
,并且减去的值不是很精确。
如果您关心精确的十进制算术,请使用BigDecimal
。
您可能还会发现这篇文章很有用。
double和float 并不是真正的数字 。
在任何范围内都有无限数量的实数,但只有有限数量的位来表示它们! 因此,对于double和float,预计会出现舍入错误。
您获得的数字是可以用浮点表示中的double表示的最接近的数字。
有关更多详细信息,您可能希望阅读本文 [警告:可能是高级别]。
您可能希望使用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(); }