JS 的 toFixed 方法到底是怎么取值的 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
a494836960
V2EX    Javascript

JS 的 toFixed 方法到底是怎么取值的

  •  
  •   a494836960 2019-06-05 11:35:17 +08:00 6093 次点击
    这是一个创建于 2371 天前的主题,其中的信息可能已经有所发展或是发生改变。

    文档上说的是 四舍五入 为什么 52.635 就是 52.63 呢

    52.635.toFixed(2) // "52.63" 47.365.toFixed(2) // "47.37" 
    28 条回复    2019-09-26 14:11:39 +08:00
    kile
        1
    kile  
       2019-06-05 11:47:04 +08:00   3
    入了就入了,舍了就舍了,想入就入,想舍就舍

    我是 JS,我为我自己带盐
    liuy1994g
        2
    liuy1994g  
       2019-06-05 11:51:25 +08:00 via Android
    偶进奇不进?
    luzemin
        3
    luzemin  
       2019-06-05 11:55:31 +08:00
    每个语言都有这个问题,C#为例,也是奇进偶舍。https://www.cnblogs.com/lztkdr/p/MathRoundToEven.html
    huawin03
        4
    huawin03  
       2019-06-05 11:56:31 +08:00
    按道理应该是四舍五入,这个可能是浮点数精度问题
    Caballarii
        5
    Caballarii  
       2019-06-05 11:56:39 +08:00
    重写 Number.prototype.toFixed
    xiangyuecn
        6
    xiangyuecn  
       2019-06-05 11:58:21 +08:00
    Math.round(52.635*100)/100

    (52.635+0.000001).toFixed(2)

    坑死人不偿命

    9007199254740992+1 = 多少

    9007199254740995+1 = 多少
    wakiki
        7
    wakiki  
       2019-06-05 12:28:38 +08:00 via iPhone
    ECMAScript 的 Spec 上没有说是四舍五入啊♂
    runze
        8
    runze  
       2019-06-05 12:34:21 +08:00
    Number.prototype.toFixed 并没有说是四舍五入,想要四舍五入请用 Math.round
    zhy0216
        9
    zhy0216  
       2019-06-05 12:38:04 +08:00 via Android
    学习了 今天刚用到这个函数 竟然有这个坑。。。
    wakiki
        10
    wakiki  
       2019-06-05 12:44:03 +08:00 via iPhone   1
    Let n be an integer for which the exact mathematical value of n ÷ 10f - x is as close to zero as possible. If there are two such n, pick the larger n.
    主要因为是 52.635 存为 52.634998..,对应的 n 是 5263,所以得到 53.63 ,47.365 存为 47.365001678....,所以 n 是 4737,得到 47.37
    helllllloworld
        11
    helllllloworld  
       2019-06-05 13:02:23 +08:00
    这种事情,当然是去看 Spec 最靠谱了啊
    dangyuluo
        12
    dangyuluo  
       2019-06-05 13:11:02 +08:00   4
    52.635 的 IEEE754 实值为 52.634998321533203125,自然四舍五入成 52.63
    a494836960
        13
    a494836960  
    OP
       2019-06-05 13:22:08 +08:00
    @wakiki 说得对。。。 我之前看的是 w3school
    jucelin
        14
    jucelin  
       2019-06-05 13:33:47 +08:00   1
    使用的是银行家舍入规则:
    四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。

    https://www.jb51.net/article/126804.htm
    MinonHeart
        15
    MinonHeart  
       2019-06-05 14:37:50 +08:00   1
    Math.fround(52.635); // 52.6349983215332
    Math.fround(47.365); // 47.3650016784668
    marcong95
        16
    marcong95  
       2019-06-05 14:40:33 +08:00
    这不是坑,Banker Rounding 了解一下。需要四舍五入请使用(x, n) => Math.floor((x * 10 ** n) + 0.5) / (10 ** n)

    楼上说坑的,请重温 JS 语法甚至计算机编程基础……基础不打好别怪语言,各种语言的取整算法都有这个问题。
    xiangyuecn
        17
    xiangyuecn  
       2019-06-05 15:15:54 +08:00
    @marcong95 就算这是是标准。但需要特定值才能触发非预期的结果就是坑呀,我来给他安一个自定义名字:标准坑

    如果没有被坑过,我相信像我这种刚入门的小白哪会留意这些标准事实。只会表示明明测试的好好的,就是不知道为什么线上偶尔会产生不一致的数据,最后发现是 toFixed 的锅:52.635.toFixed(2) != "52.64"

    埋雷好方法:需要特定值才能触发非预期的结果,测试过程难发现,有利提升自己存在价值
    66beta
        18
    66beta  
       2019-06-05 15:19:51 +08:00 via Android
    讨论了这么多规范,难道不该考虑下业务上是希望四舍五入吗?
    version
        19
    version  
       2019-06-05 15:46:22 +08:00
    js 计算金额问题.就需要看业务需要了.看老板的取舍了
    当要对接其他语言的时候也需要相互沟通.按分还是按元.按 int 还是按浮点来传值. 来换算再计算还是其它.支付都对接第三方.基本基础可以.不会存在太大问题..
    而且金额最好是多转转 number 不然写着写着就是 字符串相加了.那就是出大事了.还有边界问题限制下就好.不然测试哪天给你测试的金额是恐怖的
    四舍五入或者去尾.可以用 require('lodash') 这个库
    wakiki
        20
    wakiki  
       2019-06-05 16:01:12 +08:00   11
    别被上面说的“ Banker Rounding ”误导,Spec 里也没说用着这个,只是输出结果看起来类似,面试答了这个就尴尬了。
    Spec 里说的是:

    Let n be an integer for which the exact mathematical value of n ÷ 10f - x is as close to zero as possible. If there are two such n, pick the larger n

    对于 52.635:
    5263/100 - 52.635 = -0.0049999999999954525
    5264/100 - 52.635 = 0.005000000000002558
    最接近 0 的是 5263/100 - 52.635 的结果,所以结果是 52.63
    根本原因是数字表示方式的精度问题啊啊啊啊啊啊啊啊啊啊
    xiangyuecn
        21
    xiangyuecn  
       2019-06-05 16:13:38 +08:00
    @wakiki #20 完美的解释了: (52.635+0.00000000000001).toFixed(2) 是正确的,在多一个 0 就不确了。
    cifermail
        22
    cifermail  
       2019-06-05 16:26:40 +08:00
    这是因为精度问题,不是真正的四舍五入,解决 toFixed 四舍五入陷阱, https://www.boatsky.com/blog/32
    xieweizhi007
        23
    xieweizhi007  
       2019-06-05 16:28:15 +08:00
    @wakiki 好认真的回答, 赞一个。
    20498860
        24
    20498860  
       2019-06-05 17:57:54 +08:00
    看到 3 楼我去研究了半个小时 toFixed 和银行家舍入。。回来看到 20 楼发现不是银行家舍入。。我佛了
    MinonHeart
        25
    MinonHeart  
       2019-06-05 18:39:49 +08:00
    @xiangyuecn js 浮点数不能用 == 比较,通常是差值和 Number.EPSILON 比较,高精度应该用 decimal,BigInt
    Fule
        26
    Fule  
       2019-06-06 08:26:17 +08:00
    本来想说 JS 奇葩,但是 C# 里下面的代码得到的结果和 JS 的一样……

    ```
    float a = 52.635f;
    double b = Math.Round(a,2);
    Console.WriteLine(b);
    ```
    flowfire
        27
    flowfire  
       2019-07-30 11:04:25 +08:00
    四舍六入五成双
    leopoldgod
        28
    leopoldgod  
       2019-09-26 14:11:39 +08:00
    网上很多人人云亦云,说 toFixed 是银行家舍入,其实并不是,自己试一下就知道了。五前为偶要舍去的反例:(10.1250).toFixed(2)//10.13 ,五前为奇要进一的反例:(10.2150).toFixed(2)//10.21 。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3086 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 32ms UTC 00:34 PVG 08:34 LAX 16:34 JFK 19:34
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86