关于js浮点数计算精度不准确问题的解决办法

Posted 行果、

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于js浮点数计算精度不准确问题的解决办法相关的知识,希望对你有一定的参考价值。

今天在计算商品价格的时候再次遇到js浮点数计算出现误差的问题,以前就一直碰到这个问题,都是简单的使用tofixed方法进行处理一下,这对于一个程序员来说是及其不严谨的。因此在网上收集了一些处理浮点数精度的文章。觉得别人写的挺好了,我在简单的总结一下,以方便后续查阅。

浮点数误差产生的原因:

先看一个实例:

0.1 + 0.2 =?

0.1 + 0.2 = 0.3?

我们先来看一段 JS。

console.log( 0.1+ 0.2);

输出为 0.30000000000000004。是不是很奇葩
其实对于浮点数的四则运算,几乎所有的编程语言都会有类似精度误差的问题,只不过在 C++/C#/Java 这些语言中已经封装好了方法来避免精度的问题,而 javascript 是一门弱类型的语言,从设计思想上就没有对浮点数有个严格的数据类型,所以精度误差的问题就显得格外突出。下面就分析下为什么会有这个精度误差,以及怎样修复这个误差。

首先,我们要站在计算机的角度思考 0.1 + 0.2 这个看似小儿科的问题。我们知道,能被计算机读懂的是二进制,而不是十进制,所以我们先把 0.1 和 0.2 转换成二进制看看:

0.1 => 0.0001 1001 1001 1001…(无限循环)
0.2 => 0.0011 0011 0011 0011…(无限循环)

上面我们发现0.1和0.2转化为二进制之后,变成了一个无限循环的数字,这在现实生活中,无限循环我们可以理解,但计算机是不允许无限循环的,对于无限循环的小数,计算机会进行舍入处理。进行双精度浮点数的小数部分最多支持 52 位,所以两者相加之后得到这么一串 0.0100110011001100110011001100110011001100110011001100 因浮点数小数位的限制而截断的二进制数字,这时候,我们再把它转换为十进制,就成了 0.30000000000000004。

知道了浮点数产生的原因了,那么怎么处理这个问题呢?

方法一:指定要保留的小数位数(0.1+0.2).toFixed(1) = 0.3;这个方法toFixed是进行四舍五入的也不是很精准,对于计算金额这种严谨的问题,不推荐使用,而且不通浏览器对toFixed的计算结果也存在差异。

方法二:把需要计算的数字升级(乘以10的n次幂)成计算机能够精确识别的整数,等计算完毕再降级(除以10的n次幂),这是大部分编程语言处理精度差异的通用方法。 

 

eg:(0.1*10 + 0.2*10) / 10 == 0.3 // true

 

网上的处理方法:

 

//加法   
    Number.prototype.add = function(arg){   
        var r1,r2,m;   
        try{r1=this.toString().split(".")[1].length}catch(e){r1=0}   
        try{r2=arg.toString().split(".")[1].length}catch(e){r2=0}   
        m=Math.pow(10,Math.max(r1,r2))   
        return (this*m+arg*m)/m   
    }  
    //减法   Number.prototype.sub = function (arg){   
    return this.add(-arg);   
}   

//乘法   Number.prototype.mul = function (arg)   {   
    var m=0,s1=this.toString(),s2=arg.toString();   
    try{m+=s1.split(".")[1].length}catch(e){}   
    try{m+=s2.split(".")[1].length}catch(e){}   
    return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m)   
}   

//除法   Number.prototype.div = function (arg){   
    var t1=0,t2=0,r1,r2;   
    try{t1=this.toString().split(".")[1].length}catch(e){}   
    try{t2=arg.toString().split(".")[1].length}catch(e){}   
    with(Math){   
        r1=Number(this.toString().replace(".",""))   
        r2=Number(arg.toString().replace(".",""))   
        return (r1/r2)*pow(10,t2-t1);   
    }   
}

参考文章:http://div.io/topic/1349

             http://rockyee.iteye.com/blog/891538

            http://www.zhoulujun.cn/zhoulujun/html/theory/computBase/2016_0714_7860.html#announ

 

以上是关于关于js浮点数计算精度不准确问题的解决办法的主要内容,如果未能解决你的问题,请参考以下文章

解决“0.1 + 0.2 = 0.30000000000000004” - uniapp中JS浮点运算精度问题 - uniapp引入decimal.jsmath.js等数学库

解决“0.1 + 0.2 = 0.30000000000000004” - uniapp中JS浮点运算精度问题 - uniapp引入decimal.jsmath.js等数学库

解决“0.1 + 0.2 = 0.30000000000000004” - uniapp中JS浮点运算精度问题 - uniapp引入decimal.jsmath.js等数学库

js浮点数精度丢失问题及如何解决js中浮点数计算不精准

js float浮点数计算精度问题

解决JavaScript浮点数计算精度问题