首页 > 代码库 > 关于js浮点数计算精度不准确问题的解决办法

关于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浮点数计算精度不准确问题的解决办法