Java的Bigdecimal.divide和舍入

时间:2014-10-19 16:47:39

标签: java bigdecimal

在工作中,我们在尝试将大数除以1000时发现了一个问题。这个数字来自数据库。

说我有这个方法:

private static BigDecimal divideBy1000(BigDecimal dividendo) {
    if (dividendo == null) return null;

    return dividendo.divide(BigDecimal.valueOf(1000), RoundingMode.HALF_UP);
}

当我拨打以下电话时

divideBy1000(new BigDecimal("176100000"))

我收到176100的预期值。但如果我尝试下面的行

divideBy1000(new BigDecimal("1761e+5"))

我收到值200000.为什么会这样?这两个数字是相同的,具有不同的表示,最新的是我从数据库收到的。我知道,不知何故,JVM将数字1761除以1000,在最后四舍五入并填充0。

避免这种行为的最佳方法是什么?请记住,原始号码不受我控制。

6 个答案:

答案 0 :(得分:21)

如javadoc中所述,BigDecimal由整数值和比例定义。

  

因此,BigDecimal表示的数字的值   (unscaledValue×10 ^( - scale))。

因此BigDecimal("1761e+5")的比例为-5,BigDecimal(176100000)的比例为0。

两个BigDecimal的划分分别使用-5和0比例来完成,因为在划分时未指定比例。 divide documentation解释了结果不同的原因。

  

<强> divide

public BigDecimal divide(BigDecimal divisor)
     

返回BigDecimal,其值为(this / divisor),其首选比例为(this.scale() - divisor.scale());如果无法表示确切的商(因为它具有非终止的十进制扩展),则抛出ArithmeticException

     

<强>参数:

     

divisor - 分割此BigDecimal的值。

     

<强>返回:

this / divisor
     

<强>抛出:

     

ArithmeticException - 如果确切的商没有终止十进制扩展

     

<强>时间:

     

1.5

如果在分割时指定比例,例如dividendo.divide(BigDecimal.valueOf(1000), 0, RoundingMode.HALF_UP)您将获得相同的结果。

答案 1 :(得分:6)

表达式new BigDecimal("176100000")new BigDecimal("1761e+5") 不等于BigDecimal跟踪价值和精确度。

BigDecimal("176100000")有9位精度,在内部表示为BigInteger("176100000"),乘以1. BigDecimal("1761e+5")有4位精度,内部表示为BigInteger("1761") ,乘以100000.

当您将BigDecimal除以一个值时,结果会考虑精度的数字,导致看似相等的值的输出不同。

答案 2 :(得分:1)

使用BigDecimal进行部门划分。

dividendo.divide(divisor,2,RoundingMode.CEILING)//00.00 nothing for up and nothing for down

此操作的精度为两位小数。

答案 3 :(得分:0)

是的,这就是你正在尝试的问题。如果我可以,在你只有指数的情况下,你应该施放它们然后使用你的方法。看看我建议的那段代码:

long  longValue = Double.valueOf("1761e+5").longValue();
BigDecimal value= new BigDecimal(longValue);

在将这些字符串转换为新的BigDecimal并返回此BigDecimal值的方法中使用它。然后,您可以将这些返回值与divideBy1000一起使用。这应该可以清除您遇到的任何问题。

如果您有很多这些,那么您还可以将这些BigDecimal存储在像列表这样的数据结构中。然后使用foreach循环,在其中应用divideBy1000,每个新值将存储在不同的列表中。然后,您只需访问此列表即可获得新的值集!

希望有所帮助:)

答案 4 :(得分:0)

尝试使用round()

private static BigDecimal divideBy1000(BigDecimal dividendo) {
    if (dividendo == null) return null;

    return dividendo.divide(BigDecimal.valueOf(1000)).round(new MathContext(4, RoundingMode.HALF_UP));
}

 public static void main(String []args){
    BigDecimal bigD = new BigDecimal("1761e5");
    BigDecimal bigDr = divideBy1000(bigD);
    System.out.println(bigDr);
 }

new MathContext(4, RoundingMode.HALF_UP))行将分区返回到4个位置。

这会产生:

1.761E+5

这是你想要的。 (:

答案 5 :(得分:0)

任何时候你将BigDecimal乘以10的幂,在这种情况下你乘以10 -3 ,你可以使用dividendo.scaleByPowerOfTen(power)只修改BigDecimal的比例对象和侧面步骤任何舍入问题,或者至少将它们移动到以后的计算中。

此处的其他答案涵盖了除以任何数字的更一般情况。