划分BigDecimal时,结果可能是非终止的。因此,您必须提供MathContext或RoundingMode / scale作为除法运算的一部分。但是,根据算术中的操作顺序,精度的损失会导致差异。
使用BigDecimals时,如何避免由于精度损失导致的差异(例如下面显示的示例)?很想知道别人如何处理这类问题。
示例:
BigDecimal v1 = new BigDecimal("29.14");
BigDecimal v2 = new BigDecimal("12");
BigDecimal v3 = new BigDecimal("75");
System.out.println(v1.divide(v2, MathContext.DECIMAL64).multiply(v3).setScale(2, RoundingMode.HALF_UP));
// Prints: 182.12
System.out.println(v1.multiply(v3).divide(v2, MathContext.DECIMAL64).setScale(2, RoundingMode.HALF_UP));
// Prints: 182.13
在上面的示例中,根据操作顺序,结果会发生变化。
在测试之前遇到这个例子之前,我从来没有考虑过BigDecimal操作的顺序是个问题。现在,我陷入了这种困境:)
答案 0 :(得分:1)
这是浮点算术的常见问题,无论是二进制还是十进制:除法可能不准确。因此,当你必须进行乘法和除法时,如果你先进行除法并且结果不准确,那么当你稍后进行乘法时,你会乘以第一个结果的误差。
在您的示例中,确切的结果是182.125,它位于要舍入到182.13的边框中。当你首先进行除法时,29.14 / 12的确切结果是2.428333 ...
使用DECIMAL64的16位数字,它舍入为2.428333333333333,当它乘以75时,它给出182.12499999999997,它将四舍五入为182.12
那么可以在这里做些什么:
a/b*c/d
,您应该计算(a*c)/(b*d)
但无论如何,只要你没有确切的结果,你就有可能得到舍入误差,这是浮点计算所固有的。