java BigDecimal精确度爬坑

荆轲刺秦王

先看产品需求:

贷款总额合计:取还款明细子表所有的贷款金额之和;
已还款合计:取还款明细子表所有已还款之和;
已还款占比:自动计算,等于:(已还款合计/贷款总额合计)*100%,四舍五入取整(注:小于1%的统一取1%,大于99%小于100%的统一取99%);
剩余本息合计:取还款明细子表所有的剩余本息之和;

先上问题代码:
 

private CalculationTotalVo getCalculationTotalVo( List<RepayDetailEntity> targetList ){
        CalculationTotalVo calculationTotalVo = new CalculationTotalVo();
        BigDecimal totalLoanAmount = BigDecimal.ZERO;
        BigDecimal totalRepaymentAmount = BigDecimal.ZERO;
        if(!CollectionUtils.isEmpty(targetList)){
            for (RepayDetailEntity item : targetList){
                if(Objects.equals(item.getIsDelete(), RepayDetailEntity.NOTDELETE)){
                    totalLoanAmount = totalLoanAmount.add( item.getLoanAmount() == null ? BigDecimal.ZERO : item.getLoanAmount() );
                    totalRepaymentAmount = totalRepaymentAmount.add( item.getRepaymentAmount() == null ? BigDecimal.ZERO : item.getRepaymentAmount() );
                }
            }
        }
        // calculate rate
        calculationTotalVo.setTotalLoanAmount( totalLoanAmount.compareTo(BigDecimal.ZERO) == 0 ? null : totalLoanAmount );
        calculationTotalVo.setTotalRepaymentAmount( totalRepaymentAmount.compareTo(BigDecimal.ZERO) == 0 ? null : totalRepaymentAmount );
        calculationTotalVo.setRateRepayment( null );
        calculationTotalVo.setTotalRestPrincipalInterest( null );
        if( totalRepaymentAmount.compareTo(BigDecimal.ZERO) != 0 && totalLoanAmount.compareTo(BigDecimal.ZERO) != 0 ){
            BigDecimal rateRepayment = totalRepaymentAmount.divide(totalLoanAmount, 3, RoundingMode.DOWN).multiply( BigDecimal.valueOf(100) );
            if( rateRepayment.compareTo(BigDecimal.ZERO) > 0 && rateRepayment.compareTo(BigDecimal.valueOf(1)) < 0 ){
                rateRepayment = BigDecimal.valueOf(1);
            }else if ( rateRepayment.compareTo(BigDecimal.valueOf(99)) > 0 && rateRepayment.compareTo(BigDecimal.valueOf(100)) < 0 ){
                rateRepayment = BigDecimal.valueOf(99);
            }
            calculationTotalVo.setRateRepayment( rateRepayment );
            calculationTotalVo.setTotalRestPrincipalInterest( totalLoanAmount.subtract(totalRepaymentAmount) );
        }
        return calculationTotalVo;
    }

这段代码逻辑则是完全按照产品方案上的来,通过 已还款合计/贷款总额合计 计算得出占比。但是这里遇到的问题是 如果是 123456789/1  类似于一个特别大的数除以一个特别小的数就会导致结果为 0 

看一下改进的代码:

private CalculationTotalVo getCalculationTotalVo( List<RepayDetailEntity> targetList ){
        CalculationTotalVo calculationTotalVo = new CalculationTotalVo();
        BigDecimal totalLoanAmount = BigDecimal.ZERO;
        BigDecimal totalRepaymentAmount = BigDecimal.ZERO;
        BigDecimal rateRepayment = BigDecimal.ZERO;
        if(!CollectionUtils.isEmpty(targetList)){
            for (RepayDetailEntity item : targetList){
                if(Objects.equals(item.getIsDelete(), RepayDetailEntity.NOTDELETE)){
                    totalLoanAmount = totalLoanAmount.add( item.getLoanAmount() == null ? BigDecimal.ZERO : item.getLoanAmount() );
                    totalRepaymentAmount = totalRepaymentAmount.add( item.getRepaymentAmount() == null ? BigDecimal.ZERO : item.getRepaymentAmount() );
                }
            }
        }
        // calculate rate
        // 已还款占比:(已还款合计/贷款总额合计)*100%,四舍五入取整(注:小于1%的统一取1%,大于99%小于100%的统一取99%)
        // 这里反向计算
        calculationTotalVo.setTotalLoanAmount( totalLoanAmount.compareTo(BigDecimal.ZERO) == 0 ? null : totalLoanAmount );
        calculationTotalVo.setTotalRepaymentAmount( totalRepaymentAmount.compareTo(BigDecimal.ZERO) == 0 ? null : totalRepaymentAmount );
        calculationTotalVo.setRateRepayment( null );
        calculationTotalVo.setTotalRestPrincipalInterest( null );
        if( totalRepaymentAmount.compareTo(BigDecimal.ZERO) != 0 && totalLoanAmount.compareTo(BigDecimal.ZERO) != 0 ){
            BigDecimal rateRepaymentMin = totalLoanAmount.multiply( BigDecimal.valueOf(0.01) );
            BigDecimal rateRepaymentMax = totalLoanAmount.multiply( BigDecimal.valueOf(0.99) );

            if( rateRepaymentMin.compareTo(BigDecimal.ZERO) > 0 && totalRepaymentAmount.compareTo(rateRepaymentMin) <= 0 ){
                rateRepayment = new BigDecimal("0.01");
            }else if( totalRepaymentAmount.compareTo(rateRepaymentMax) > 0 && totalRepaymentAmount.compareTo(totalLoanAmount) < 0 ){
                rateRepayment = new BigDecimal("0.99");
            }else if( totalRepaymentAmount.compareTo(totalLoanAmount) > 0 ){
                rateRepayment = new BigDecimal("1");
            }else{
                rateRepayment = totalRepaymentAmount.divide(totalLoanAmount, 3, RoundingMode.HALF_UP);
            }
            calculationTotalVo.setRateRepayment( rateRepayment );
            calculationTotalVo.setTotalRestPrincipalInterest( totalLoanAmount.subtract(totalRepaymentAmount) );
        }
        return calculationTotalVo;
    }

前端会将占比乘以100并加上百分号,所以这里仅存小数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值