美文网首页前端二三事程序员
javaScript 中 toFixed() 精度问题及解决方案

javaScript 中 toFixed() 精度问题及解决方案

作者: Cheuk_Lee | 来源:发表于2018-01-11 12:55 被阅读170次

    昨天工作中发现了一个问题,是后端计算的成交价和前端计算的成交价有时候会有一分钱的差异,后来发现是由于 toFixed 的方法存在差异。

    在 C# 中的取舍方法使用的是银行家舍入法,也就是四舍六入五取偶(又称四舍六入五留双)。在 javaScript 中 Number.prototype.toFixed()的方法在四舍和六入上没什么争议,而当判断位为5的时候就显得有点奇怪。

    银行家舍入法

    据说,大部分的编程软件都使用的是这种方法,也算是一种国际标准。 所谓银行家舍入法,其实质是一种四舍六入五取偶(又称四舍六入五留双)法。其规则是:当舍去位的数值小于5时,直接舍去该位;当舍去位的数值大于等于6时,在舍去该位的同时向前位进一;当舍去位的数值等于5时,如果前位数值为奇,则在舍去该位的同时向前位进一,如果前位数值为偶,则直接舍去该位。

    以下是各个浏览器中测试 toFixed() 的结果:

    Chrome:

    Chrome 下的 toFixed

    FireFox:

    FF 下的 toFixed

    IE:

    IE 下的 toFixed

    可以看出在不同浏览器中,toFixed方法都给出了不同的结果,让人摸不到头脑。

    于是我查询了 ECMA 里Number.prototype.toFixed() 的规范,如下:

     ECMA-262 Number.prototype.toFixed()

    拿 0.15 和 10.15 举个栗子。

    (0.15).toFixed(1)

    num = 0.15; f = 1;

    根据步骤 10.a :

    2 ÷ 10^f - num        // 0.05000000000000002

    1 ÷ 10^f - num        // -0.04999999999999999

    取最接近 0 的值,得 (0.15).toFixed(1) 返回 0.1。

    (10.15).toFixed(1)

    num = 10.15; f = 1;

    根据步骤 10.a :

    102 ÷ 10^f - num        //  0.049999999999998934

    101 ÷ 10^f - num        // -0.05000000000000071

    取最接近 0 的值,得 (10.15).toFixed(1) 返回 10.2。

    归根到底就是浮点数精度的锅。


    找到原因后,我想到了两种解决方案:

    使用Math.round()

    用这个方法可以实现传统的四舍五入。

    通过 Math.round() 来实现传统四舍五入


    重写Number.prototype.toFixed()

    这个方法则是更加公平的四舍六入五取偶。

    重写 Number.prototype.toFixed()

    重写后的结果:

    重写后在 Chrome 上的结果

    相关文章

      网友评论

        本文标题:javaScript 中 toFixed() 精度问题及解决方案

        本文链接:https://www.haomeiwen.com/subject/jrpznxtx.html