【发布时间】:2018-07-19 07:03:15
【问题描述】:
除以 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 操作的顺序是一个问题。现在,我陷入了两难境地:)
【问题讨论】:
-
BigDecimal 没有精度损失,不确定的数字是这样的除法不能精确的数字,并以接近结果的周期结束,例如 1 / 3 导致 0.333333...
-
我认为一个好的方法不是四舍五入,而是简单地削减一些
-
@MarcosVasconcelos 问题是你不能做
BigInteger.divide来获得例如的确切值。 1/3。您必须指定在哪里截断,导致不可避免的精度损失。 -
我认为我们没有解决此类问题的工具,但发现乘法而不是除法不会产生此类错误: BigDecimal o = new BigDecimal("2"); BigDecimal t = new BigDecimal("0.3333"); BigDecimal t2 = new BigDecimal("3"); /* System.out.println(o.divide(t2)); */ //RuntimeException System.out.println(o.multiply(t)); // 有效
-
将您的除法精度设置为比您最终想要的高约 5-6 位。我认为需要更多的“额外数字”,但事实证明,5-6 位数字通常就足够了。最后,缩小到所需的精度。请注意,只有除法才是问题。
标签: java precision bigdecimal