我们都知道Java提供了两个高精度计算的类:BigInteger和BigDeciaml。虽然它们大体上属于“包装器类”的范畴,但两者都没有对应的基本类型。BigDeciaml支持任意精度的定点数。例如,可以用它进行精确的货币计算。(以上摘自Java编程思想第4版)
最近的项目使用BigDeciaml,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
public static BigDecimal rate(BigDecimal originPrice,BigDecimal betweenCurrencyRate,BigDecimal toCurrencyRate){
return originPrice.multiply(betweenCurrencyRate).divide(toCurrencyRate); }
BigDecimal chaoIn = exchangeRate.getChaoIn(); BigDecimal cNYChaoIn = exchangeRateCNY.getChaoIn();
adultPrice = RateExchangeUtil.rate(adultPrice,chaoIn,cNYChaoIn); childPrice = RateExchangeUtil.rate(childRetail.multiply(new BigDecimal(childNum)),chaoIn,cNYChaoIn);
hotelTotalPrice = hotelTotalPrice.add(childPrice).add(adultPrice);
|
在使用BigDecimal做运算的时候,出现了下面的异常:
1
| Non-terminating decimal expansion; no exact representable decimal result.
|
后来通过搜索得知,通过BigDecimal的divide方法进行除法时当不整除,出现无限循环小数时,就会抛出上面的异常。
我们应该使用divide的重载方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| BigDecimal.divide(BigDecimal divisor, int scale, RoundingMode roundingMode) ;
scale为小数位数;
roundingMode为小数模式; ROUND_CEILING 如果 BigDecimal 是正的,则做 ROUND_UP 操作;如果为负,则做 ROUND_DOWN 操作。 ROUND_DOWN 从不在舍弃(即截断)的小数之前增加数字。 ROUND_FLOOR 如果 BigDecimal 为正,则作 ROUND_UP ;如果为负,则作 ROUND_DOWN 。 ROUND_HALF_DOWN 若舍弃部分> .5,则作 ROUND_UP;否则,作 ROUND_DOWN 。 ROUND_HALF_EVEN 如果舍弃部分左边的数字为奇数,则作 ROUND_HALF_UP ;如果它为偶数,则作 ROUND_HALF_DOWN 。 ROUND_HALF_UP 若舍弃部分>=.5,则作 ROUND_UP ;否则,作 ROUND_DOWN 。 ROUND_UNNECESSARY 该“伪舍入模式”实际是指明所要求的操作必须是精确的,,因此不需要舍入操作。 ROUND_UP 总是在非 0 舍弃小数(即截断)之前增加数字。
|
最后修正rate方法中的问题,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
public static BigDecimal rate(BigDecimal originPrice,BigDecimal betweenCurrencyRate,BigDecimal toCurrencyRate){
return originPrice.multiply(betweenCurrencyRate).divide(toCurrencyRate,4,BigDecimal.ROUND_HALF_UP); }
|