项目|金额场景计算&BigDecimal使用简记

前言

        在实际项目开发中,我们经常会遇到一些金额计算,分摊等问题,通常我们都使用java.math.BigDecimal 来完成各种计算,避免使用浮点数float,double来计算金额,以免丢失精度,以下是博主部分使用场景和使用BigDecimal简记分享。。

案例1:统计各年龄段,用户存款:实现集合的所有金额相加,结果保留两位小数

        在平常项目中,我们经常会遇到查询某个集合,在集合下计算所有价钱的总和

 public static void main(String[] args) {
        //无论如何都会出现两位小数 java.math.BigDecimal.ROUND_HALF_UP
        List<User> userList = new ArrayStack();
        userList.add(new User().setAge(30).setMoney(new BigDecimal("145")).setUsername("dzx"));
        userList.add(new User().setAge(10).setMoney(new BigDecimal("143")).setUsername("dzx"));
        userList.add(new User().setAge(10).setMoney(new BigDecimal("144")).setUsername("dzx"));
        userList.add(new User().setAge(10).setMoney(new BigDecimal("142")).setUsername("dzx"));
        System.out.println(userList.stream().map(User::getMoney).reduce(BigDecimal.ZERO,BigDecimal::add).setScale(2, ROUND_HALF_UP));
    }

        此处我们使用了stream的处理方式,更简洁的计算了总和,设置精度为2,和四舍五入,关于ROUND_HALF_UP的其他取值,可以参考java.math.BigDecimal.ROUND_HALF_UP静态方法里的取值,共有0-7序号的8种取值,经常使用ROUND_HALF_UP=4(四舍五入)、ROUND_HALF_DOWN=5(五舍六入)、ROUND_FLOOR=3(向下取整)、ROUND_CEILING=2(向上取整)

案例2:用户下单谋些商品,商品购买的支付金额不准确(包含了各种优惠),需要重新分摊计算每件商品金额,分摊的算法就是通过每件商品的支付金额占比,计算出具体每件商品的实付金额

        通常我们需要分摊,总会出现除不尽,或者精度问题,为此我们要保证总的数不能少,为了减少精度等问题,就要采用最后一件做减法的方式,这样就能保证最后分摊金额的准确性。以图中为例,用户下单购买了三件商品,订单总实付为100.1,支付为233,由于各种原因(平台各种优惠,银行满减,红包等活动)经常导致支付金额与实付金额不等,那么就要重新计算各商品的实付金额

在这里插入图片描述

ps:图中计算结果都为四舍五入,保留小数两位,计算器计算的结果,非程序

        三件商品,其中商品1:支付3,那么就需要计算她的实付金额,首先需要计算这件商品原支付金额的占比,再通过这个比例计算实付金额,商品2同理,到商品3则要采用最后一件做减法的方式,否则会造成总的实付金额会不等的情况。具体计算以商品1为例,实付金额为:3/233*100.1=1.29,按照这样的逻辑编写代码

     public static void main(String[] args) {
        //先除再乘
        BigDecimal result1 = new BigDecimal("3")
                .divide(new BigDecimal("233"),2,ROUND_HALF_UP)
                .multiply(new BigDecimal("100.1")).setScale(2,ROUND_HALF_UP);
        System.out.println("先除再乘,输出:"+result1);
    }
先除再乘,输出:1.00

        我们会发现程序实际计算结果,和程序计算结果有偏差,中间的偏差是哪里来的呢?答案是除法来的,我们在平常计算的时候,除以200的时候已经做了精度处理,因为我们不可能算的尽,因此我们的做法都是先乘后除,乘法为什么就不会有这个问题,因为乘法通常都是有限的数,非无穷的数,我们乘法可以避免进度丢失,因此我们实际计算的时候,需要调整计算公式,由3/233*100.1调整为3*100.1/200,具体代码如下:

      public static void main(String[] args) {
        //先乘再除
        BigDecimal result2 = new BigDecimal("3")
                .multiply(new BigDecimal("100.1"))
                .divide(new BigDecimal("233"),2,ROUND_HALF_UP).setScale(2,ROUND_HALF_UP);
        System.out.println("先乘再除,输出:"+result2);
    }
先乘再除,输出:1.29

        这样我们会避免了除法除不尽带来的精度丢失问题,实际结果应该为1.29

        总结

         1.金额计算中,避免先除后乘精度丢失,应先乘后除

         2.金额分摊中,应该使用最后一件用减法的方式,分摊

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值