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

本文介绍了在实际项目开发中如何使用Java.math.BigDecimal处理金额计算和分摊问题,避免浮点数精度损失,包括统计各年龄段用户存款时的精确求和,以及用户下单商品分摊计算的策略。作者强调了先乘后除原则和最后一件商品做减法的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

        在实际项目开发中,我们经常会遇到一些金额计算,分摊等问题,通常我们都使用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

案例3:用户下单购买了一件0.01元A商品,又购买了100000元B商品 红包优惠是99999元 总共是1.01元的实付款 现在需要计算分摊商品的实付款,按照比例分摊规则(约等于两位数,最后一件做减法的分摊)

        1)0.01*1.01/100000.01 约等于0.00 最后一件1.01-0=1.01 即A商品实付款=0.00元 B商品实付款1.01元

        上面的例子说明,当两件商品差价较大,又需要分摊新的总金额时,由于只能约等于到两位数,导致另一件商品根本没分摊到钱, 又或者先计算了占比大的商品,四舍五入后已经占满新的总金额。

         解决办法:设定最低分摊比例,计算比例一旦超过两位小数,最后四舍五入计算为0的情况,按0.01处理,且需要优先计算价格便宜的商品(按价格做排序) 上面例子:

  • 先按价格排序商品
  • 取出价格最低的A商品,最低比例分摊,为0触发最低比例分摊设值为0.01
  • 最后一件减法处理1.01-0.01 =1 即A商品实付款=0.01元 B商品实付款1.00元

        总结

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

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

        3.按四舍五入处理时,需要设置最低分摊比例,且按价格升序排序处理

《餐馆点餐管理系统——基于Java和MySQL的课程设计解析》 在信息技术日益发达的今天,餐饮行业的数字化管理已经成为一种趋势。本次课程设计的主题是“餐馆点餐管理系统”,它结合了编程语言Java和数据库管理系统MySQL,旨在帮助初学者理解如何构建一个实际的、具有基本功能的餐饮管理软件。下面,我们将深入探讨这个系统的实现细节及其所涉及的关键知识点。 我们要关注的是数据库设计。在“res_db.sql”文件中,我们可以看到数据库的结构,可能包括菜品表、订单表、顾客信息表等。在MySQL中,我们需要创建这些表格并定义相应的字段,如菜品ID、名称、价格、库存等。此外,还要设置主键、外键来保证数据的一致性和完整性。例如,菜品ID作为主键,确保每个菜品的唯一性;订单表中的顾客ID和菜品ID则作为外键,与顾客信息表和菜品表关联,形成数据间的联系。 接下来,我们来看Java部分。在这个系统中,Java主要负责前端界面的展示和后端逻辑的处理。使用Java Swing或JavaFX库可以创建用户友好的图形用户界面(GUI),让顾客能够方便地浏览菜单、下单。同时,Java还负责与MySQL数据库进行交互,通过JDBC(Java Database Connectivity)API实现数据的增删查改操作。在程序中,我们需要编写SQL语句,比如INSERT用于添加新的菜品信息,SELECT用于查询所有菜品,UPDATE用于更新菜品的价格,DELETE用于删除不再提供的菜品。 在系统设计中,我们还需要考虑一些关键功能的实现。例如,“新增菜品和价格”的功能,需要用户输入菜品信息,然后通过Java程序将这些信息存储到数据库中。在显示所有菜品的功能上,程序需要从数据库获取所有菜品数据,然后在界面上动态生成列表或者表格展示。同时,为了提高用户体验,可能还需要实现搜索和排序功能,允许用户根据菜品名称或价格进行筛选。 另外,安全性也是系统设计的重要一环。在连接数据库时,要避免SQL注入攻击,可以通过预编译的PreparedStatement对象来执行SQL命令。对于用户输入的数据,需要进行验证和过滤,防止非法字符和异常值。 这个“餐馆点餐管理系统”项目涵盖了Java编程、数据库设计与管理、用户界面设计等多个方面,是一个很好的学习实践平台。通过这个项目,初学者不仅可以提升编程技能,还能对数据库管理和软件工程有更深入的理解。在实际开发过程中,还会遇到调试、测试、优化等挑战,这些都是成长为专业开发者不可或缺的经验积累
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值