V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
dangyuluo
V2EX  ›  问与答

处理金钱的时候,对于浮点的舍入误差你们是怎么处理的呢?

  •  
  •   dangyuluo · 2020-01-12 13:17:55 +08:00 · 6016 次点击
    这是一个创建于 1784 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前情提要:

    浮点运算结果不准确算不算是 bug ?任何人都不想得到不准确的结果吧 https://v2ex.com/t/637166#reply54


    假设有 10 块钱需要给三个人平均分配,精确到分。如果纯粹是四舍五入的话,每个人都会得到 3.33 元。这时候剩下的 1 分钱应该怎么处理呢?

    我不是做这行的,单纯只是好奇。

    39 条回复    2020-01-13 16:10:04 +08:00
    Xbluer
        1
    Xbluer  
       2020-01-12 13:24:20 +08:00   ❤️ 2
    最后一个人得款是总额减去其他人得款。
    eason1874
        2
    eason1874  
       2020-01-12 13:24:43 +08:00
    不会处理的可以把那 0.01 转给我,把余数都给我,就没有余数了。
    azh7138m
        3
    azh7138m  
       2020-01-12 13:25:15 +08:00 via Android
    不是 bug,因为它是浮点数。
    怎么处理看 PM 心情了。
    ipwx
        4
    ipwx  
       2020-01-12 13:28:45 +08:00 via Android
    用 decimal 不用 float,流行的语言基本标准库都有。
    loading
        5
    loading  
       2020-01-12 13:30:25 +08:00
    金融计算有专门的库,不会有误差。

    记得有个方案是,把金额按 1000 倍存的。你的 3.33 元,在数据库是 3330
    dangyuluo
        6
    dangyuluo  
    OP
       2020-01-12 13:31:21 +08:00
    @ipwx decimal 并不解决求和的问题啊。
    loading
        7
    loading  
       2020-01-12 13:31:46 +08:00
    对于你这个分钱问题,似乎是有处理方式的,记不起来了。
    ipwx
        8
    ipwx  
       2020-01-12 13:37:18 +08:00 via Android
    @dangyuluo 那就用 fraction,Python 标准库就有。
    andy101wong
        9
    andy101wong  
       2020-01-12 13:38:21 +08:00 via Android   ❤️ 2
    现实怎么处理就怎么处理, 计算机解决不了 3.3333..... ,现实也做不到 10 元钱三等分啊。
    delectate
        10
    delectate  
       2020-01-12 13:41:25 +08:00
    小数点后取两位数,不进行任何四舍五入。
    总金额再减去每份求和,得到差额,加入其中某一份即可。

    这也是大多数电商、支付平台分期的算法。
    dangyuluo
        11
    dangyuluo  
    OP
       2020-01-12 13:44:47 +08:00
    @andy101wong 哈哈哈,我光想着技术怎么处理了,忽略了现实的问题
    Mavious
        12
    Mavious  
       2020-01-12 15:10:42 +08:00
    某金融平台,很直接,不搞四舍五入,直接砍小数。
    比如应分配 13.33333 元,只给你 13.33 ,应得 16.598 元,只给你 15.59 ,小数点后第三位直接砍掉,不进位。
    至于多出的那一分钱,嗯哼,当然是平台拿走啦,轮不到用户的。
    ershierdu
        13
    ershierdu  
       2020-01-12 15:30:44 +08:00 via iPhone
    看标题我还以为是说用 float 存金额…
    hhyyd
        14
    hhyyd  
       2020-01-12 15:39:22 +08:00
    我们现在做的是,个人分 10 块,3.33 ,3.33 ,10-3.33-3.33 ,减法是没有误差的。也不会因为 0.01 而影响用户体验
    tfdetang
        15
    tfdetang  
       2020-01-12 15:47:24 +08:00
    怎么根据我所知,金融行业通行的标准做法是 四舍六入五成双。
    imn1
        16
    imn1  
       2020-01-12 16:56:59 +08:00
    不用电脑你说 10 块钱 3 个人怎么平分?

    电脑只是工具……不如上街问问那些“智能机器人”这个问题,看看是什么答案,会不会不同机器人有不同的答案
    wccc
        17
    wccc  
       2020-01-12 20:41:28 +08:00
    入库六位,百分比计算,加到最后
    ziseyinzi
        18
    ziseyinzi  
       2020-01-12 22:52:32 +08:00 via Android   ❤️ 6
    某次淘宝买一个一元包邮的东西,发现可以花呗免息分期。变成了 0.33 元 x3 期,省了一分
    des
        19
    des  
       2020-01-12 23:06:59 +08:00
    发现这个问题,然后去补了一下知识,下面是我总结的,不一定完全对
    1、不能用浮点存小数是以讹传讹
    2、不同场景有不同处理,平分一般是加到最后一个人
    3、银行还是四舍五入用的最多,主要还是接受的人最多
    4、银行会定期对账,这些舍入应该都是在可接受的范围内的
    5、银行也在大把的用浮点数。最重要的一点是,误差可控,就比如计算复利
    6、钱其实精度要求还算是低的,麻烦的有很多,比如金价
    7、误差其实只在进制转换时发生(这个我也不是很确定)

    如果有哪里说的不对,希望有人能帮忙指正一下
    n121
        20
    n121  
       2020-01-13 00:13:19 +08:00
    @ziseyinzi 照理说这种情况最后一期应该扣 0.34 才对呀
    czhfrank
        21
    czhfrank  
       2020-01-13 02:59:11 +08:00 via iPhone
    除法出问题是你分钱的时候的问题,不是记账的问题,记账只记加减,从一个人口袋到另一个人口袋。这问题跟计算机更是八竿子打不着
    NewTab12138
        22
    NewTab12138  
       2020-01-13 09:09:14 +08:00
    为什么不以分为单位来算,而使用元为单位
    KyonLi
        23
    KyonLi  
       2020-01-13 09:36:25 +08:00
    @NewTab12138 一千分平均分给三人不还是一样的问题
    hc181533609
        24
    hc181533609  
       2020-01-13 09:48:06 +08:00
    @KyonLi 看最小的单位呗 分还是厘
    hc181533609
        25
    hc181533609  
       2020-01-13 09:49:06 +08:00
    @KyonLi 不好意思 回错人了
    fancy111
        26
    fancy111  
       2020-01-13 10:01:19 +08:00
    程序设计的时候就没设计所谓平分的状态,10 元给三人的时候肯定设计的是有一个多一点余数的。
    而且本身 10 元就不可能平分给三个人吧。
    ccgoing10
        27
    ccgoing10  
       2020-01-13 10:03:08 +08:00
    ebs 里面,如果有分摊客户都会要求最后一个倒减
    jzbax1230
        28
    jzbax1230  
       2020-01-13 10:05:27 +08:00
    如果按比例乘,肯定会员 0.01 的精度问题 最后一笔减出来
    wensonsmith
        29
    wensonsmith  
       2020-01-13 10:12:30 +08:00
    银行家舍入, 四舍六入五取偶。

    PHP 有 https://github.com/moneyphp/money
    racecoder00
        30
    racecoder00  
       2020-01-13 10:27:50 +08:00
    Java 银行家舍入:RoundingMode.HAIL_EVEN
    zxcjqyy
        31
    zxcjqyy  
       2020-01-13 10:52:56 +08:00
    我刚看淘宝某品牌手机 4199.00 元,花呗分期免手续费分 3 期,1399.67 元。
    计算器算得 4199/3=1399.666666..元,四舍五入了
    jjianwen68
        32
    jjianwen68  
       2020-01-13 10:56:18 +08:00
    余数当然留给自家公司了
    mxT52CRuqR6o5
        33
    mxT52CRuqR6o5  
       2020-01-13 11:12:18 +08:00 via Android
    @andy101wong 对的,这个问题和浮点数和计算机根本没关系
    Hilong
        34
    Hilong  
       2020-01-13 11:14:34 +08:00 via Android
    说起这个,很早期的银行结算小数点四位后的好像就直接丢弃,有个人发现了,把这个转到了自己的账号,挣了几百上千万后被发现了
    samlee123
        35
    samlee123  
       2020-01-13 11:54:21 +08:00
    @Hilong 有一部电影 有这个桥段
    pupboss
        36
    pupboss  
       2020-01-13 12:17:34 +08:00
    @zxcjqyy 你说的应该是商品页面,实际生成还款账单的时候还是最后一期用减法
    opengps
        37
    opengps  
       2020-01-13 12:32:49 +08:00
    第一个或者最后一个用来处理余数问题,一向如此
    mcfog
        38
    mcfog  
       2020-01-13 14:14:00 +08:00
    平分: 不用总量 /份数,而是用“剩余量 /剩余份数”,就能控制误差在最多一分,算等额本息还款等场景类似,相当于把每次舍入造成的误差积累起来摊在下面一份,而不是全堆在最后或者最开头

    舍入:银行家算法 (四舍六入五成双)
    muhairen
        39
    muhairen  
       2020-01-13 16:10:04 +08:00
    @Hilong 攻壳机动队就有啊
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2727 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 12:35 · PVG 20:35 · LAX 04:35 · JFK 07:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.