javascript 实现大数相加支持小数精度高保真,返回String

javascript 实现大数相加支持小数精度高保真,返回String

javascript能表示的最大数值是Number.MAX_VALUE,即1.7976931348623157e+308,这个数值虽然能够正确表示出来,但是存在一个精度丢失的问题
实际上javascript会丢弃大于9007199254740992后的位数,导致精度丢失。这里借用互联网的一幅图,从图中可以明确的表示javascript一系列的上限下限

Number.add = function(a, b) {
    a = String(a).replace(/[^0-9.]/, '');
    b = String(b).replace(/[^0-9.]/, '');
    var _aArr = a.split('.'),
      _bArr = b.split('.'),
      res1 = _add(_aArr[1], _bArr[1], 0, true);
    return _add(_aArr[0], _bArr[0], String(res1.carry)).res + '.' + res1.res || 0

    function _add(a, b, carry, xs) {
      var resObj = {
        res: '0',
        carry: 0
      }
      if ((!a && !b) || (!Number(a) && !Number(b))) {
        resObj.res = carry ? _add(resObj.res, String(carry)).res : resObj.res;
        return resObj
      } else if (!a || !b) {
        resObj.res = a || b;
        resObj.res = carry ? _add(resObj.res, String(carry)).res : resObj.res;
        return resObj
      } else if (!Number(a) || !Number(b)) {
        resObj.res = Number(a) ? a : b;
        resObj.res = carry ? _add(resObj.res, String(carry)).res : resObj.res;
        return resObj
      };
      var len = Math.max(String(a).length, String(b).length);
      // 如果 位数小于 19 直接相加提高执行效率
      if (len < 18) {
        if (len > a.length) {
          a = Number(a) * Math.pow(10, len - a.length)
        }
        if (len > b.length) {
          b = Number(b) * Math.pow(10, len - b.length)
        }
        resObj.res = String(Number(a) + Number(b));
        resObj.res = (carry ? _add(resObj.res, String(carry)).res : resObj.res);
        resObj.carry = resObj.res.length - len;
        resObj.res = resObj.res.slice(-len)
        return resObj
      } else {

        var arrA = ('0' + a).split(''), //将数字转成字符串并反转
          arrB = ('0' + b).split(''),
          distance = a.length - b.length, //计算两个数值字符串的长度差;
          _carry  =  0, // 进位
          resArr = [], //结果数组
          res = '';
        if (len > a.length) {
          //长度不够用0补齐, 考虑进位多加一个0 小数向后补0 整数向前补0
          arrA = xs ? arrA.concat(Array(len - a.length).fill('0')) : Array(len - a.length).fill('0').concat(arrA)
        }
        if (len > b.length) {
          //长度不够用0补齐, 考虑进位多加一个0 小数向后补0 整数向前补0
          arrB = xs ? arrB.concat(Array(len - a.length).fill('0')) : Array(len - b.length).fill('0').concat(arrB)
        }
        //从数组的第一位开始向前遍历,把两个数组对应位置的数值字符串转成整形后相加,
        //carry表示相加后的进位,比如最后一位相加是7+6=13,这里进位carry是1
        //在遍历的时候每次都加上上次相加后的carry进位
        for (var i = len; i > -1; i--) {
          var temp = Number(arrA[i] || '0') + Number(arrB[i] || '0') + _carry;
          if (temp >= 10) {
            _carry = 1;
            resArr.push(temp - 10);
          } else {
            _carry = 0;
            resArr.push(temp);
          }
        }
        resObj.res = resArr.reverse().join('').replace(/^0/, '');
        resObj.res = carry ? _add(resObj.res, String(carry)).res : resObj.res;
        resObj.carry = resObj.res.length - len;
        resObj.res = xs ? resObj.res.slice(-len) : resObj.res;
        return resObj
      }
    }
  }
  • [ 参考] http://www.plqblog.com/views/article.php?id=29

你可能感兴趣的:(Javascript,大数字,精度,精度丢失)