河畔的风

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

不精准原因:

下面我们来说一下浮点数运算产生误差的原因:(拿0.1+0.2=0.30000000000000004进行举例)

首先,我们要站在计算机的角度思考 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.0100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 ,因浮点数小数位的限制而截断的二进制数字,这时候,我们再把它转换为十进制,就成了 0.30000000000000004。

 例如

0.0515.toFixed(3)
'0.051'
0.0815.toFixed(3)
'0.082'

很明显 最后一位都应该是2 但是由于精度丢失的问题 导致数据最终不正确

解决方法

(function(prototype) {
    prototype.toSuperFixed = function (d) { 
        var s=this+""; 
        if(!d)d=0; 
        if(s.indexOf(".")==-1)s+="."; 
        s+=new Array(d+1).join("0"); 
        if(new RegExp("^(-|\\+)?(\\d+(\\.\\d{0,"+(d+1)+"})?)\\d*$").test(s)){
           var c="0"+RegExp.$2,pm=RegExp.$1,a=RegExp.$3.length,b=true;
           if(a==d+2){
               a=c.match(/\d/g); 
               if(parseInt(a[a.length-1])>4){
                   for(var i=a.length-2;i>=0;i--){
                       a[i]=parseInt(a[i])+1;
                       if(a[i]==10){
                           a[i]=0;
                           b=i!=1;
                       }else break;
                   }
               }
               c=a.join("").replace(new RegExp("(\\d+)(\\d{"+d+"})\\d$"),"$1.$2");

           }if(b)c=c.substr(1); 
           return (pm+c).replace(/\.$/,"");
      }return this+"";

   };
}(Number.prototype));

 

posted on 2023-08-03 15:04  河畔的风  阅读(96)  评论(0编辑  收藏  举报