两个层面,解决结算(财务)系统小数精度问题

7 评论 11146 浏览 44 收藏 4 分钟

本文笔者将从两个层面,讲述:在做财务系统时遇到的关于小数精度的问题,该如何解决?

最近在做财务系统中遇到一个关于小数精度的问题:

我们知道计算机在订单结算信息的时候,是通过单条订单计算结算金额,然后整体汇总再给出结果。这样才能支持业务上需要从不同时间维度汇总数据的要求(每3天一结算,每7天一结算,每月一结算等)。但是,作为一个正常用户,我们并不会这么去计算,我们采用的是先汇总商品价格再计算结算金额的方法,如下方展示:

结算公式: 应结算金额 = 商品价格-商品价格*佣金比例

计算机: 计算订单1的应结算金额J1,计算订单2的应结算金额J2,计算订单3的应结算金额J3,然后汇总。

人工计算:计算订单1,订单2,订单3的商品价格汇总,再按照总的商品价格计算应结算金额。

我们刚开始对计算机计算的每一个J1,J2,J3都采取四舍五入的方法,发现最后和人工核对时算出的结果是不一样的,会有精度上的误差。计算机汇总的结果可能是4.56,而人工算的是4.57,那么怎么办呢?

要从两个层面解决这个问题

1. 系统层面

  1. 改造计算系统的规则,舍弃2位小时的方式改为采用4位小数的方式计算具体金额。
  2. 更改数据修约的规则,舍弃四舍五入的方法,改为采用四舍六入五成双法,关于四舍六入五成双法在后面给出说明。

2. 展现层面

  1. 在后台展现4位精度。
  2. 在用户余额等和外部系统有资金交互的地方只展示2位小数,采用向下取整的方法(4.5667取4.56)保证系统不会多付钱给用户。

通过以上方法,我们保证了整个财务系统精度符合业务要求,能够正常运作。

四舍六入五成双法

1. 含义

对于位数很多的近似数,当有效位数确定后,其后面多余的数字应该舍去,只保留有效数字最末一位。这种修约(舍入)规则是“四舍六入五成双”,也即“4舍6入5凑偶”。

这里“四”是指≤4 时舍去,”六”是指≥6时进上,”五”指的是根据5后面的数字来定,当5后有数时,舍5入1;当5后无有效数字时,需要分两种情况来讲:

  1. 5前为奇数,舍5入1;
  2. 5前为偶数,舍5不进(0是偶数)。

2. 为什么要这样做?

从统计学的角度,“四舍六入五成双”比“四舍五入”要科学,在大量运算时,它使舍入后的结果误差的均值趋于零,而不是像四舍五入那样逢五就入,导致结果偏向大数,使得误差产生积累进而产生系统误差,“四舍六入五成双”使测量结果受到舍入误差的影响降到最低。

 

本文由@shinian 原创发布于人人都是产品经理,未经许可,禁止转载

题图来自Unsplash, 基于CC0协议

更多精彩内容,请关注人人都是产品经理微信公众号或下载App
海报
评论
评论请登录
  1. 这种情况一般通知公司的技术人员,这是技术人员代码的bug。在Java里一般价格是long类型的但是在页面显示是double类型的,价格从double转为long会损失精度,但是代码是能修复这种bug的。

    回复
  2. 您好,看了您的文章很有收获,可以加微信进一步沟通吗,我的微信号15933556182

    来自北京 回复
  3. 你好,是余额会保留4位小数吗,还是分别保存4位和2位两种,如果保存4位,对账及平衡检查会对不上吧。这块怎么处理

    来自北京 回复
  4. 好硬核,用处不大

    来自广东 回复
  5. 感觉用处不大,遇到5的情况很少,问题还是没解决

    来自新疆 回复
  6. 不用了,百度百科里找到了

    来自天津 回复
  7. 5凑偶那还是有点不明白,能拿几个数举例吗?

    来自天津 回复