每天进步一点点——js的浮点精度问题和科学计数法转换

最近项目中用到了浮点的乘法运算,遇到了两个问题,一个是运算的结果出现了误差,另一个问题是运算结果出现了科学计数法,需要将科学计数法转换成普通数字。下面我们一一来处理。

1、js浮点数做数学运算的时候出现误差

我们都知道在计算机中所有的运算都是以二进制的形式进行的,所以浮点数在进行数学运算的时候也会先转换成二进制,但是浮点数转换成二进制的时候可能会有无限位,而IEEE 754 标准的 64 位双精度浮点数的小数部分最多支持 53 位二进制位,所以二进制表示的浮点数本身就有误差,数学运算之后同样存在误差。
那么,怎样消除这种误差呢?目前通用的方式是:

//乘法
function accMul(arg1,arg2) {
      var m=0,s1=arg1.toString(),s2=arg2.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);
}

原理就是将浮点数转化正整数,运算之后再转化成浮点数。下边这边文章有非常详细的讲解:JavaScript 浮点数运算的精度问题。

2、科学计数法转换成普通数字

JavaScript在以下情景会自动将数值转换为科学计数法:
(1)小数点前的数字个数大于等于22位;
(2)小数点前边是0,小数点后十分位(包含十分位)之后连续零的个数大于等于6个。
但是,我并不想以科学技术法的形式展示给用户,于是找到了以下这个函数,并且做了逐行分析:

:function scientificToNumber(num) {
        if(/\d+\.?\d*e[\+\-]*\d+/i.test(num)) {    //正则匹配科学计数法的数字
          var zero = '0',                                    //
            parts = String(num).toLowerCase().split('e'), //拆分成系数和指数
            e = parts.pop(),//存储指数
            l = Math.abs(e), //取绝对值,l-1就是0的个数
            sign = e/l,          //判断正负
            coeff_array = parts[0].split('.');   //将系数按照小数点拆分
          if(sign === -1) {           //如果是小数
            num = zero + '.' + new Array(l).join(zero) + coeff_array.join('');   //拼接字符串,如果是小数,拼接0和小数点
          } else {
            var dec = coeff_array[1];  
            if(dec) l = l - dec.length;  //如果是整数,将整数除第一位之外的非零数字计入位数,相应的减少0的个数
            num = coeff_array.join('') + new Array(l+1).join(zero);    //拼接字符串,如果是整数,不需要拼接小数点
          }
        }
        return num;
      }

通过这两个方法可以解决项目中遇到的两个问题,验证有效,在此记录。

你可能感兴趣的:(每天进步一点点——js的浮点精度问题和科学计数法转换)