前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >被辞退了,因为小数点计算错误

被辞退了,因为小数点计算错误

作者头像
林老师带你学编程
发布2023-12-28 08:54:53
1130
发布2023-12-28 08:54:53
举报
文章被收录于专栏:强仔仔强仔仔

故事背景

今天我一个同事跟我吐槽,说他朋友因为程序问题,被公司辞退了,而且还没有任何补偿。我一听马上问,是删库跑路了嘛,这么严重。他说比这个还严重,说因为BigDecimal小数点四舍五入出现问题,导致订单金额偏低,公司损失了十几万美金,而且因为发现的晚,订单都已经发货了,钱要不回来了,造成很大的影响。虽然他朋友是公司老员工,但是发生这么大的事情,也只能引咎辞职了,而且因为个人问题导致公司权益受损,公司有权辞退,并且不进行任何赔偿。

我听完这个事情,久久无法回神,对众多小公司而言,因为用户量不高,服务宕机一段时间,其实不会直接造成非常大的影响(滴滴这种独角兽除外),而金额计算错误导致的问题,大多数都是非常致命的错误,目前金额计算一般都采用BigDecimal来进行运算,但是如果BigDecimal不会用或者没用好,也是会造成严重的线上问题。 为了引以为戒,博主特意整理了BigDecimal的易错场景,来培训团队成员,让大家引以为戒,可以用好BigDecimal,计算好金额,保住自己的饭碗。

易错点一:BigDecimal构造参数导致精度丢失问题

BigDecimal decimal = new BigDecimal(0.01); 打印实际值:0.01000000000000000020816681711721685132943093776702880859375 建议使用:BigDecimal.valueOf()方法赋值,比如: BigDecimal decimal1 = BigDecimal.valueOf(0.01); 同时,如果在高并发或者大量对象创建场景时,也不建议使用new BigDecimal方式创建对象,否则会影响性能,同样推荐BigDecimal.valueOf方式创建对象。

知识点:所以推荐使用BigDecimal.valueOf来赋值,确保金额数据的精度正确。

易错点二:正确使用两个BigDecimal对象的大小比较

num1.equals(num2) 或者 num1.compareTo(num2) 都是比较两个数的大小,但是它们有区别: equals会先比较值,再比较精度;而compareTo直接比较值,不会比较精度。 BigDecimal decimal2 = new BigDecimal("0.01"); BigDecimal decimal3 = new BigDecimal("0.010"); //false,因为精度不一样 decimal2.equals(decimal3); //true, 只比较数值,不会比较精度 decimal2.compareTo(decimal3)==0;

知识点:所以要根据业务正确选择比较大小方法,确保业务逻辑的正确性。

易错点三:做除法运算时,必须设定精度和选择正确的舍入模式

BigDecimal d1 = BigDecimal.valueOf(1.00); BigDecimal d2 = BigDecimal.valueOf(3.00); BigDecimal d3 = d1.divide(d2);

上述代码执行后,会直接抛出异常:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. 正确写法: // 精度设置为2位,选择向远离零的方向四舍五入 BigDecimal d3 = d1.divide(d2, 2, RoundingMode.HALF_UP); BigDecimal舍入模式:

  • RoundingMode.UP:向远离零的方向舍入
  • RoundingMode.DOWN:向靠近零的方向舍入
  • RoundingMode.CEILING:向正无穷方向舍入
  • RoundingMode.FLOOR:向负无穷方向舍入
  • RoundingMode.HALF_UP:向远离零的方向四舍五入
  • RoundingMode.HALF_DOWN:向靠近零的方向四舍五入
  • RoundingMode.HALF_EVEN:银行家舍入法,遵循IEEE 754标准

知识点:所以做除法运算时,务必设定精确位数,避免系统异常崩溃。并且正确理解舍入模式的含义,有助于满足业务的需求。

易错点四:BigDecimal对象一旦设值不可修改原则问题

BigDecimal使用setScale方法设置精度时,原对象不会被修改,需要用新对象去接收。 BigDecimal num = new BigDecimal("1.2345"); // num变量并没有变化,还是4位小数; num.setScale(2, RoundingMode.HALF_UP); // result 才是四舍五入后并保持2位小数点。 BigDecimal result = num.setScale(2, RoundingMode.HALF_UP);

知识点:我们要理解不可变的特性,不要出现理解上的歧义,导致业务出现问题。

复盘反思

BigDecimal只是Java功能中小到不能再小的功能点,但是却有这么多的注意事项。写了这么多年代码之后,我可以明显的感觉到,初级开发和高级开发有着非常明显区别,特别是对待程序严谨性上,经验越多的程序员,可以想到更多的异常场景,从而保证最后的开发质量。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-12-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 易错点一:BigDecimal构造参数导致精度丢失问题
  • 易错点二:正确使用两个BigDecimal对象的大小比较
  • 易错点三:做除法运算时,必须设定精度和选择正确的舍入模式
  • 易错点四:BigDecimal对象一旦设值不可修改原则问题
  • 复盘反思
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档