推荐关注
› Meteor
› JSLint - a JavaScript code quality tool
› jsFiddle
› D3.js
› WebStorm
推荐书目
› JavaScript 权威指南第 5 版
› Closure: The Definitive Guide
drymonfidelia

避免 Math.ceil(1.1 * 100) == 111 的最佳实践是什么?用户支付金额不对不能入账,排查了半天才发现 JS 这个逆天设计,好像别的语言也有这样的

  •  1
     
  •   drymonfidelia · Sep 28, 2024 · 8736 views
    This topic created in 773 days ago, the information mentioned may be changed or developed.
    42 replies  •  2024-10-08 16:29:07 +08:00
    rrfeng
    rrfeng
    Sep 28, 2024 via Android❤️6
    1
    基础没学好,回去重修。

    ---
    解决方法就是钱永远别用小数。
    AoEiuV020JP
    AoEiuV020JP
    Sep 28, 2024❤️2
    2
    第一反应精度丢失问题,转念想怎么会差这么多, 仔细一看,ceil ,你确定这不是设计如此有人贪这差值吗,
    Coelacanthus
    Coelacanthus
    Sep 28, 2024
    3
    计算金融不要用二进制浮点数,二进制浮点数的设计就没法精确表示十进制有理数。用十进制浮点数或者定点数,因为金融业务很少用到分以下,用定点数的比较多。十进制浮点数的支持状态也不太好。
    TomVista
    TomVista
    Sep 28, 2024
    4
    biginit
    icyalala
    icyalala
    Sep 28, 2024❤️2
    5
    "1.1" 是十进制,当这个值转为数字的时候是无限循环小数 1.0001100110011001100110011...
    舍入后就是 1.0001100110011001100110011001100110011001100110011010, 注意最后一位是向上舍入的。
    所以最开始从 "1.1" 这个字符串解析到数字的时候就已经不准确了。

    属实是计算机基础不扎实。
    pinocc012
    pinocc012
    Sep 28, 2024
    6
    内部数据应该用分为单位的整数吧,显示的时候转换
    c8c
    c8c
    Sep 28, 2024
    7
    `npm install decimal.js`
    xiangyuecn
    xiangyuecn
    Sep 28, 2024❤️1
    8
    既然用了浮点数 ceil ,哪就不得不得不掏出祖传的 0.30000000000000004.com 了

    php -r var_dump(ceil(1.1*100));
    //float(111)
    chobitssp
    chobitssp
    Sep 28, 2024
    9
    bignumber.js
    QingXuJiaZhi
    QingXuJiaZhi
    Sep 28, 2024
    10
    凡是涉及金额,都不能简单计算。

    一个金额,一个日期,这两个是很典型新手误区,表面上看起来没什么,实际上都藏着大坑。
    haolongsun
    haolongsun
    Sep 28, 2024
    11
    金额永远别用浮点数 用 decimal
    haolongsun
    haolongsun
    Sep 28, 2024
    12
    二进制只能近似存储小数,详细重新学习 IEEE754 ,还有以前面试区分培训和科班第一个就让说 IEEE754 ,不知道的一定是培训出来的,因为培训班不会说什么浮点数底层怎么实现,而是会说金额不让用 double ,科班必定知道,计组第一章就是吧
    importmeta
    importmeta
    Sep 28, 2024
    13
    只用数据库计算
    fiveStarLaoliang
    fiveStarLaoliang
    Sep 28, 2024
    14
    string 或者整形存储,计算时得注意精度丢失问题
    iOCZS
    iOCZS
    Sep 28, 2024❤️2
    15
    " JS 这个逆天设计",很野的说法
    msg7086
    msg7086
    Sep 28, 2024❤️1
    16
    与其说语言的逆天设计,不如说只知道给金额用浮点数的程序员比较逆天吧。
    IvanLi127
    IvanLi127
    Sep 28, 2024
    17
    这个不是常见的面试题么,没见过嘛?

    改用 Decimal.js 吧。https://www.npmjs.com/package/decimal.js/v/10.4.3

    其他语言也有类似的库,推荐直接用这种方案来做计算。
    masterclock
    masterclock
    Sep 28, 2024❤️3
    18
    https://github.com/kdeldycke/awesome-falsehood
    建议任何程序员写代码前都读一遍

    涉及金额,只设计人民币,可以考虑 decimal ,最好是专门的类型
    est
    est
    Sep 28, 2024
    19
    测了下 1.1 * 100 == 110.00000000000001 向上取整所以是 111 没问题啊。。。

    问题在于 LZ 你为啥要向上取整啊。。round 不行么。
    drymonfidelia
    drymonfidelia
    OP
    Sep 28, 2024
    20
    @est 因为商品价格 100 美元,税 10%,业务需求是向上取整到整数
    AV1
    AV1
    Sep 28, 2024
    21
    浮点运算你换什么语言都一样。
    涉及财务、金融的计算,*不能用浮点数*,要用*定点数*,这应该是程序员的常识、共识。
    ntedshen
    ntedshen
    Sep 28, 2024❤️1
    22
    “业务需求是向上取整到整数”?
    简单,
    Math.ceil(Math.round(1.1*10000)/100)
    然后下一届码农:md 屎山+1 (狗头
    drymonfidelia
    drymonfidelia
    OP
    Sep 28, 2024❤️1
    23
    @ntedshen 我真的改成了这样 (狗头
    mingl0280
    mingl0280
    Sep 29, 2024
    24
    涉及钱币为什么要用浮点数?
    rogerer
    rogerer
    Sep 29, 2024
    25
    @DOLLOR 但其实 Excel 里的财务函数也是用的浮点数,他们要求用户通过舍入函数自行控制精度。
    geelaw
    geelaw
    Sep 29, 2024 via iPhone
    26
    @drymonfidelia #20 正确的做法是金额存成 cPrice = 10000 美分,税计算为 ((cPrice * 10000 * bpTaxRate - 1) / 10000 + 1) 美分,其中 bpTaxRate 是税率的基点数(万分之几)。这里假设 cPrice 是非负数(销售),处理退款更麻烦。
    geelaw
    geelaw
    Sep 29, 2024 via iPhone
    27
    @geelaw #26 ugh 税是

    (cPrice * bpTaxRate - 1) / 10000 + 1

    脑子糊了
    whileFalse
    whileFalse
    Sep 29, 2024 via Android
    28
    lz 培训班的,鉴定完毕
    lovestudykid
    lovestudykid
    Sep 29, 2024
    29
    计算机就业状况还是太好了
    lithiumii
    lithiumii
    Sep 29, 2024 via Android
    30
    ceil 是上取整,你就算是不懂浮点数,用四舍五入这个 bug 也会少很多
    lee88688
    lee88688
    Sep 29, 2024
    31
    #22 的做法其实是正确的,不算什么屎山。使用二进制浮点数表示十进制浮点数在一定有效位数下可以认为是正确的,这个有效位数在 64 位浮点数下大概是 12 位。
    在这些位数下转换成整数,然后将整数和小数部分取出来做处理完全没问题,楼主只需要写一些注释,后续人理解没问题的。
    lee88688
    lee88688
    Sep 29, 2024
    32
    多说一句,这种是将浮点数进行最终处理和简单时的做法。因为这些误差在累积计算的时候可能会让偏差越来越大,因此计算的时候还是使用浮点数需要做额外的处理,最好还是使用十进制的库计算或者用 bigint 转化为整数计算。
    ahu
    ahu
    Sep 29, 2024
    33
    如 #8 所说,去看看这个网站:

    location.href = 'http://' + (.1 + .2) + '.com';
    Curtion
    Curtion
    Sep 29, 2024
    34
    这是 IEEE754 的问题,金额相关不要用浮点数,要么使用 Decimal ,要么浮点数拆开成两个整数分开存储
    mdn
    mdn
    Sep 29, 2024
    35
    采用 IEEE 754 浮点数运算的标准的语言 都会出现这个问题,包括 JavaScript Java Python 等
    建议使用数学库进行运算
    lyxxxh2
    lyxxxh2
    Sep 29, 2024❤️1
    36
    你不该说逆天设计,不是找喷吗。
    对金额敏感,用数学库,big.js 之类。
    wu67
    wu67
    Sep 29, 2024
    37
    npm install mathjs -S
    EndlessMemory
    EndlessMemory
    Sep 29, 2024
    38
    0.1+0.2==0.3 ?
    sastar
    sastar
    Sep 29, 2024
    39
    判断 0.1+0.2==0.3 的正确用法应该是 abs(0.1+0.2-0.3)<0.000001 ,具体在小数点后多少位取决于你对精度的要求
    winglight2016
    winglight2016
    Sep 29, 2024❤️1
    40
    有点不理解 lz 这个代码是前端还是后端?如果是后端,从数据库设计开始就肯定用整数保存金额啊,包括银行也是这样。

    如果是前端,那根本就不该去做计税这个操作——正确的设计是把用户输入全部发送到后端去计算。
    thtznet
    thtznet
    Sep 30, 2024
    41
    拿 JS 这种前端语言计算金额?还拿去对账?逆天考量。
    zhhbstudio
    zhhbstudio
    Oct 8, 2024
    42
    @xiangyuecn #8 好东西,收藏了,哈哈哈
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   3005 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 90ms · UTC 00:46 · PVG 08:46 · LAX 16:46 · JFK 19:46
    ♥ Do have faith in what you're doing.