JS中toFixed(2)精度问题的原因以及解决办法

 更新时间:2024年04月29日 11:51:54   作者:喝一杯维C  
最近发现JS当中toFixed()方法存在一些问题,所以这里给大家总结下,这篇文章主要给大家介绍了关于JS中toFixed(2)精度问题的原因以及解决办法,文中通过代码介绍的非常详细,需要的朋友可以参考下

toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。例如将数据Num保留2位小数,则表示为:toFixed(Num);但是其四舍五入的规则与数学中的规则不同,使用的是银行家舍入规则,银行家舍入:所谓银行家舍入法,其实质是一种四舍六入五取偶(又称四舍六入五留双)法。具体规则如下:简单来说就是:四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。

经测试发现,在chorme下面,并没有完全遵守这个规则,尤其是5的后面没有数字的时候,不是这么判断的,如下:

var b = 1.335

b.toFixed(2)

"1.33"

var b = 1.345

b.toFixed(2)

"1.34"

var b = 1.355

b.toFixed(2)

"1.35"

var b = 1.365

b.toFixed(2)

"1.36"

var b = 1.375

b.toFixed(2)

"1.38"

var b = 1.385

b.toFixed(2)

"1.39"

可以发现在chorme下没有完全去遵循这个规律,或许它有自己的算法,但是毕竟它没有遵循通用的银行家算法,所以tofixed这个方法在涉及到金钱计算的业务中还是少用.

总而言之:不论引入toFixed解决浮点数计算精度缺失的问题也好,它有没有使用银行家舍入法也罢,都是为了解决精度的问题,但是又离不开二进制浮点数的环境,但至少他帮助我们找到了问题所在,从而让我们有解决方法。

一开始的办法是把要四舍五入的后一位单独拎出来单独判断。

解决方法:

通过重写toFixed方法:

Number.prototype.toFixed = function (n) {
let result = number.toString();
const arr = result.split('.');
const integer = arr[0];
const decimal = arr[1];
result = integer + '.' + decimal.substr(0, n);
const last = decimal.substr(n, 1);

// 四舍五入,转换为整数再处理,避免浮点数精度的损失

if (parseInt(last, 10) >= 5) {
const x = Math.pow(10, n);
result = ((parseFloat(result) * x) + 1) / x;
result = result.toFixed(n);
}
return result;
}

然后又发现计算机二进制编码导致的精度问题,详见上一篇博客。

自己debugger,发现页面中的js进了死循环。很明显问题出在toFixed中回调了toFixed,结果没有走出来,继续debugger,又有了惊人的发现。以下是控制台测试:

console.log(2.115 * 100) // 211.50000000000003
console.log(2.0115 * 1000) // 2011.4999999999998

既然你一直进入循环,我就手动把你拉出来。

result = (Math.round((parseFloat(result)) * x) + 1) / x;

最终完整的重写toFixed的方法

// toFixed兼容方法
Number.prototype.toFixed = function (n) {
    if (n > 20 || n < 0) {
        throw new RangeError('toFixed() digits argument must be between 0 and 20');
    }
    const number = this;
    if (isNaN(number) || number >= Math.pow(10, 21)) {
        return number.toString();
    }
    if (typeof (n) == 'undefined' || n == 0) {
        return (Math.round(number)).toString();
    }
    let result = number.toString();
    const arr = result.split('.');
    // 整数的情况
    if (arr.length < 2) {
        result += '.';
        for (let i = 0; i < n; i += 1) {
            result += '0';
        }
        return result;
    }
    const integer = arr[0];
    const decimal = arr[1];
    if (decimal.length == n) {
        return result;
    }
    if (decimal.length < n) {
        for (let i = 0; i < n - decimal.length; i += 1) {
            result += '0';
        }
        return result;
    }
    result = integer + '.' + decimal.substr(0, n);
    const last = decimal.substr(n, 1);
    // 四舍五入,转换为整数再处理,避免浮点数精度的损失
    if (parseInt(last, 10) >= 5) {
        const x = Math.pow(10, n);
        result = (Math.round((parseFloat(result) * x)) + 1) / x;
        result = result.toFixed(n);
    }
    return result;
}

总结 

到此这篇关于JS中toFixed(2)精度问题的原因以及解决办法的文章就介绍到这了,更多相关js toFixed(2)精度问题解决内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JavaScript分秒倒计时器实现方法

    JavaScript分秒倒计时器实现方法

    这篇文章主要介绍了JavaScript分秒倒计时器实现方法,可实现按照毫秒倒计时的效果,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02
  • 浅析javascript中的事件代理

    浅析javascript中的事件代理

    这篇文章主要介绍了浅析javascript中的事件代理,由一道面试题讲起,感兴趣的小伙伴们可以参考一下
    2015-11-11
  • canvas雪花效果核心代码分享

    canvas雪花效果核心代码分享

    本文主要分享了canvas实现雪花效果的核心代码,具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • JavaScript基础入门之错误捕获机制

    JavaScript基础入门之错误捕获机制

    初级开发人员往往很少使用js的抛出和捕获异常,但抛出和捕获异常往往是非常必要的,这篇文章主要给大家介绍了关于JavaScript基础入门之错误捕获机制的相关资料,需要的朋友可以参考下
    2021-08-08
  • 使用JavaScript实现检测网页是否为空闲状态

    使用JavaScript实现检测网页是否为空闲状态

    最近开发项目时,常碰到“用户在一定时间内无任何操作时,跳转到某个页面”的需求,所以本文就来使用JavaScript实现这一要求,需要的可以参考下
    2024-03-03
  • js无提示关闭浏览器窗口的两种方法分析

    js无提示关闭浏览器窗口的两种方法分析

    这篇文章主要介绍了js无提示关闭浏览器窗口的两种方法分析,需要的朋友可以参考下
    2016-11-11
  • js检测iframe是否加载完成的方法

    js检测iframe是否加载完成的方法

    这篇文章主要介绍了js检测iframe是否加载完成的方法,涉及JavaScript针对框架页面控件值的判断与页面加载的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • Echarts饼图样式之添加内圈阴影达到立体效果

    Echarts饼图样式之添加内圈阴影达到立体效果

    饼图主要是通过扇形的弧度表现不同类目的数据在总和中的占比,它的数据格式比柱状图更简单,这篇文章主要给大家介绍了关于Echarts饼图样式之添加内圈阴影达到立体效果的相关资料,文中还介绍了echarts饼图外部阴影设置的方法,需要的朋友可以参考下
    2024-02-02
  • 基于JS2Image实现圣诞树代码

    基于JS2Image实现圣诞树代码

    马上圣诞节了,作为一名程序猿,如何体现自己独特的过节风格,如何在朋友圈发一张专属自己的祝福照片我觉得很有必要,你们说是不是
    2015-12-12
  • js实现弹出框的拖拽效果实例代码详解

    js实现弹出框的拖拽效果实例代码详解

    本文通过实例代码给大家介绍了js实现弹出框的拖拽效果,代码简单易懂,非常不错,具有一定的参考借鉴价值 ,需要的朋友可以参考下
    2019-04-04

最新评论