xiasf
  • 1.9k

金融系统为什么只保留两位小数,如果产生多余两位小数位的金额怎么办?

突然发现个问题,我们生活中的金融系统最多只有两位小数位,比如12.37,精确到分,但是当两位小数和非整数计算时也会得出三位小数啊,比如银行的日率,肯定会有计算得出三位小数或者更多小数位的,但是为什么我们只看得到两位小数的余额呢,多出的小数位不也是钱吗,被省略了吗,怎么省略的呢。感觉这个问题有点意思。

我的猜想:

实际上只要我们金融系统只是用两位小数,当产生超过两位小数时,后面的小数位都不要了,直接不要,而不是满五进一,如果进一,就造成多给用户钱了,哪怕是多给0.001元,这在整个系统中的损失也是巨大的,所以当出现两位以上的小数时,只能直接省去后面的小数位,哪怕是0.239也要省去0.009,这个0.009元的损失只能让用户承担。

比如银行的系统,支付宝,这些都是两位小数位的,我们一般余额字段都是使用decimal(10,2),保留两位小数位,我突然想到这个问题,好纠结,不知道是不是我想的那样。

比如支付宝使用积分,购物券抵扣同时下多个订单时,那个抵扣的钱好像就是根据订单金额的比例拆分到每个订单下面去了,这样就出现小数了,但是那个小数也是两位,我没仔细注意过,不知道多个订单的抵扣加起来是不是等于下单时抵扣的钱。

如果是我想的那样,那这样我感觉很多时候我们肯定损失了好多钱了?我原本想多保留几位小数就可以解决这个问题,可是感觉可能还会有无穷的小数,还是不太可能,难道就只能让用户损失钱吗,哪怕只是那么一点点。

希望大神指点一下,搞得我好迷惑,目前项目中正遇到了这类问题。

谢谢!

阅读 15k
评论 2016-11-18 提问
    18 个回答

    用小数存?
    最好整数存分。decimal(10,2)也可以。

    比2位小数更高的货币精度没有任何意义。货币是离散量,而不是连续量,它的单位就是分。法律里(CNY/RMB)不存在比分更小的货币单位,每次货币计算都不应该出现比分更小的单位。存分才合法。

    并且存储系统规范不同,多位小数一不小心或将来升级,必有重大bug。

    乘除法导致的6位小数?

    任何对离散量的计算,都应该想办法用算法变成整数,用减法代替除法,如截尾法,银行家算法等。

    例如,对100块分三期付款,不应该每次减去1/3导致精度错误,而是应该执行三次分别减去33、33、34。

    例如,对102块先优惠1.8折优惠券,再优惠1.6折优惠券,不应该用102-1021.6-1021.8得到小数,而是应该用102乘1.8*1.6以四舍六入五取偶(银行家舍入)的分。因为使用优惠券不是向客户打钱,而是减免货款。

    例如,提问里说的购物券抵扣钱,假设拿100块购物券,抵扣3单金额分别为20、30、50,不应该按订单金额拆分,最好在总额里汇总——财务里的借贷/出账入账概念。如果非得拆分,则只能对100做减法,先减去20块钱单的,再减去30块钱单的,最后剩下的都是50那一单的。

    再次强调,RMB货币是以分为最小单位的离散量,分是货币的基本单位,不可拆分。正如人不可拆分出1.7个人。务必是序列的概念。

    货币系统的可靠性,多靠财务规则完成,如果不放心,多设计一个对账系统。

    评论 赞赏