在工作中,我们在尝试将大数除以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。
避免这种行为的最佳方法是什么?请记住,原始号码不受我控制。
答案 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的比例对象和侧面步骤任何舍入问题,或者至少将它们移动到以后的计算中。
此处的其他答案涵盖了除以任何数字的更一般情况。