关于JS四舍五入的探究
事情起因:近期在工作过程中,有需求需要在前端对一系列计算结果进行四舍五入运算,然而根据以往经验,直接使用了 toFixed()
方法直接处理。后经测试,并不是我们日常所理解的“四舍五入”
网上有些文章说 toFixed 使用的是 [银行家舍入],其实并不准确,不过这里也学习对比一下(https://baike.baidu.com/item/%E9%93%B6%E8%A1%8C%E5%AE%B6%E8%88%8D%E5%85%A5/4781630?fr=aladdin “银行家舍入”)
简单的说,就是:四舍六入五考虑,五后非空就进一,五后为空看奇偶,五前为偶应舍去,五前为奇要进一
但是实际应用中发现,其实并不是这样的, 像W3Cschool文档说明就是不准确的了 w3school toFixed() 方法
下图是使用 lodash.round()
方法与toFixed()
方法做的对比,可以发现 toFixed()
的计算结果既不是我们日常理解的四舍五入,也不是上文说的银行家舍入,如:
入参 | 判断 | 期望结果 | 实际结果 | 是否符合银行家舍入 |
---|---|---|---|---|
78.835 | 5后为空,5前为奇应进一 | 78.84 | 78.83 | 不符合 |
78.845 | 5后为空,5前为偶应舍去 | 78.84 | 78.84 | 符合 |
开始打算自己写一个四舍五入方法来处理,思路很简单
一个数乘以 10的X次方(X为要保留的小数位),然后使用
Math.round()
四舍五入取整,然后结果再除以10的X次方(X为要保留的小数位)
function myRound(val,decimal = 0) {
const multiple = Math.pow(10, decimal);
return Math.round(val * multiple) / multiple;
}
console.log(myRound(78.835,2));
然后发现结果还是不对,其实这个问题的根本原因还是因为JS浮点类型精度问题
经典js问题: 详解js中0.1+0.2!=0.3
console.log(78.835 * 100); // 输出 7883.499999999999
// 此时再使用 Math.round() 得到的只能是 7883
如图上图发现,使用 lodash.round()
方法 ,是可以达到我们日常理解的四舍五入效果的,故查阅一下 Lodash 的源码 Lodash round(),发现其是使用科学计数法
的方法来该表小数点的位置的,这样的好处就是不会造成失精问题。
console.log(Number("78.835e2")); // 输出 7883.5
// 此时再使用 Math.round() 得到的就是 7884
如此便能正确的四舍五入了。