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

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

作者: 小蜗牛22 | 来源:发表于2018-06-06 17:34 被阅读0次

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

    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的浮点精度问题和科学计数法转换

          本文链接:https://www.haomeiwen.com/subject/nhpujftx.html