继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

前端— toFixed() 的精度问题

业余奶茶品鉴师
关注TA
已关注
手记 8
粉丝 50
获赞 88

之前的项目里涉及到了金额的计算,要求保留两位小数或4位小数,一直是采用原生的Number对象的原型对象上的toFixed()方法来计算的。直到有一天测试提了Bug,反复验证后发现,用 tofixed 来保留n位小数在某种情况下确实会出精度问题,真叫人头大 (ÒωÓױ)!!!

下面进行测试

let num = 1.234
num.toFixed(2) //1.23 正确

let num = 1.235
num.toFixed(2) //1.24 正确

let num = 1.236
num.toFixed(2) //1.24 正确

let num = 0.234
num.toFixed(2) //0.23 正确

let num = 0.235
num.toFixed(2) //0.23 错误 X

let num = 0.236
num.toFixed(2) //0.24 正确

也就是说,当num < 0 ,且需要判断是否进位的那位是5时,这一位会错误的没有进上。这只是通过现象归纳的bug原因,归根结底还是二进制浮点数的精度不够导致的。

可以用 $toFixed(num,n) 方法来代替num.toFixed(n) :

< ps. 暂时还没发现问题,灰常滴好用 >

$tofixed (num, n) {
    var symbol = 1
    if (num < 0) {
        // 符号为负
        symbol = -1
        num *= -1
    }
    var num2 = (Math.round(num * Math.pow(10, n)) 
    / Math.pow(10, n) + Math.pow(10, -(n + 1)))
    .toString().slice(0, -1)
    return parseFloat(num2 * symbol).toFixed(n)
}

有什么问题,欢迎大家指出。

打开App,阅读手记
3人推荐
发表评论
随时随地看视频慕课网APP

热门评论

.toFixed() 是用银行家舍入算法实现的,并非精度问题

四舍六入五考虑,五后非空就进一,五后为空看奇偶,五前为偶应舍去,五前为奇要进一

只不过 JS 是5前奇数舍去,偶数进一

你对比一下,你的是不是还是有小问题的

$tofixed (0.235, 20)
"0.23000000000000000999"

var num = 0.235
num.toFixed(20)
"0.23499999999999998668"


查看全部评论