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

2019 年 6 月 5 日
 a494836960

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

52.635.toFixed(2)  // "52.63"
47.365.toFixed(2)  // "47.37"
6247 次点击
所在节点    JavaScript
28 条回复
kile
2019 年 6 月 5 日
入了就入了,舍了就舍了,想入就入,想舍就舍

我是 JS,我为我自己带盐
liuy1994g
2019 年 6 月 5 日
偶进奇不进?
luzemin
2019 年 6 月 5 日
每个语言都有这个问题,C#为例,也是奇进偶舍。https://www.cnblogs.com/lztkdr/p/MathRoundToEven.html
huawin03
2019 年 6 月 5 日
按道理应该是四舍五入,这个可能是浮点数精度问题
Caballarii
2019 年 6 月 5 日
重写 Number.prototype.toFixed
xiangyuecn
2019 年 6 月 5 日
Math.round(52.635*100)/100

(52.635+0.000001).toFixed(2)

坑死人不偿命

9007199254740992+1 = 多少

9007199254740995+1 = 多少
wakiki
2019 年 6 月 5 日
ECMAScript 的 Spec 上没有说是四舍五入啊🤷‍♂️
runze
2019 年 6 月 5 日
Number.prototype.toFixed 并没有说是四舍五入,想要四舍五入请用 Math.round
zhy0216
2019 年 6 月 5 日
学习了 今天刚用到这个函数 竟然有这个坑。。。
wakiki
2019 年 6 月 5 日
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
2019 年 6 月 5 日
这种事情,当然是去看 Spec 最靠谱了啊
dangyuluo
2019 年 6 月 5 日
52.635 的 IEEE754 实值为 52.634998321533203125,自然四舍五入成 52.63
a494836960
2019 年 6 月 5 日
@wakiki 说得对。。。 我之前看的是 w3school
jucelin
2019 年 6 月 5 日
使用的是银行家舍入规则:
四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。

https://www.jb51.net/article/126804.htm
MinonHeart
2019 年 6 月 5 日
Math.fround(52.635); // 52.6349983215332
Math.fround(47.365); // 47.3650016784668
marcong95
2019 年 6 月 5 日
这不是坑,Banker Rounding 了解一下。需要四舍五入请使用(x, n) => Math.floor((x * 10 ** n) + 0.5) / (10 ** n)

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

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

埋雷好方法:需要特定值才能触发非预期的结果,测试过程难发现,有利提升自己存在价值😜
66beta
2019 年 6 月 5 日
讨论了这么多规范,难道不该考虑下业务上是希望四舍五入吗?
version
2019 年 6 月 5 日
js 计算金额问题.就需要看业务需要了.看老板的取舍了
当要对接其他语言的时候也需要相互沟通.按分还是按元.按 int 还是按浮点来传值. 来换算再计算还是其它.支付都对接第三方.基本基础可以.不会存在太大问题..
而且金额最好是多转转 number 不然写着写着就是 字符串相加了.那就是出大事了.还有边界问题限制下就好.不然测试哪天给你测试的金额是恐怖的
四舍五入或者去尾.可以用 require('lodash') 这个库
wakiki
2019 年 6 月 5 日
别被上面说的“ 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
根本原因是数字表示方式的精度问题啊啊啊啊啊啊啊啊啊啊

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://study.congcong.us/t/571061

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX