js浮点数/大数相加

1. 浮点数相加

console.log(0.1 + 0.2); //0.30000000000000004
console.log(0.1 + 0.2 === 0.3); //false

原因在于 js的 Number 是IEEE 754标准的64-bits的双精度数值,这是一种二进制表示法,可以精确地表示分数,比如1/2,1/8,1/1024。但是,二进制浮点数表示法并不能精确的表示类似0.1这样的简单的数字,会有舍入误差。

由于采用二进制,JavaScript 也不能有限表示 1/10、1/2 等这样的分数。在二进制中,1/10(0.1)被表示为 0.00110011001100110011…… 注意 0011 是无限重复的,这是舍入误差造成的,所以对于 0.1 + 0.2 这样的运算,操作数会先被转成二进制,然后再计算:

0.1 => 0.0001 1001 1001 1001…(无限循环)
0.2 => 0.0011 0011 0011 0011…(无限循环)

双精度浮点数的小数部分最多支持 52 位,所以两者相加之后得到这么一串0.0100110011001100110011001100110011001100…因浮点数小数位的限制而截断的二进制数字,这时候,再把它转换为十进制,就成了0.30000000000000004。

对于保证浮点数计算的正确性,有两种常见方式。

  • 是先升幂再降幂:
function add(num1, num2){
  let r1, r2, m;
  r1 = (''+num1).split('.')[1].length;
  r2 = (''+num2).split('.')[1].length;

  m = Math.pow(10,Math.max(r1,r2));
  return (num1 * m + num2 * m) / m;
}
console.log(add(0.1,0.2)); //0.3
console.log(add(0.15,0.2256)); //0.3756

2. 大数相加

同样的问题不仅出现在浮点数相加的情况下,在大数相加也会出现误差:

function sum(a, b) {
  return Number(a) + Number(b)
}
console.log(sum(11111111111111111, 11111111111111111))   //  22222222222222224

还是因为 js的 Number 是IEEE 754标准的64-bits的双精度数值,就是说在 js中规定安全整数的范围是-2^53 ~ 2^53,所以大于 9007199254740991 的数进制转换会存在精度问题。

那我们怎么处理js中不在这个范围内的大数相加呢:基本的思路是以字符串的形式按位来相加,即我们平时计算加法一样,个位与个位相加,超过十就进一位的思路。首先要将两个数的长度用零补齐,比如“123”和“8”,补齐结果两个数各为“123”和“008”。

function BigAdd(a, b) {
  var carry = 0,
    length = Math.max(a.length, b.length),
    result = [];
  var aArr = a.toString().split(''),
    bArr = b.toString().split('');
  var distance = aArr.length - bArr.length;
  // 补全0
  for(var i=0; i0) {
      bArr.unshift('0')
    } else {
      aArr.unshift('0')
    }
  }

  for(var j=0; j= 10 ? [temp, carry] = [temp-10, 1] : carry = 0;
    result.push(temp);
  }
  // 把最后的进位加上去
  result.push(carry);
  return result.reverse().join('').replace(/^0+/, '');
}

console.log(BigAdd('9007199254740993', '111238'));  //  9007199254752116

更简洁的一版:

function sumStrings(a,b){
  var res = '',
    c = 0;
  a = a.split('');
  b = b.split('');
  while (a.length || b.length || c){
    c += ~~a.pop() + ~~b.pop();
    //  将结果拼接
    res = c % 10 + res;
    c = c>9;
  }
  return res.replace(/^0+/,'');
}
console.log(sumStrings('9007199254740993', '111'));  //  9007199254741104

其中的“~~”其实是一种利用符号进行的类型转换,转换成数字类型:

~~true == 1
~~false == 0
~~"" == 0
~~[] == 0
~~undefined ==0
~~!undefined == 1
~~null == 0
~~!null == 1

转自:
https://www.cnblogs.com/kindofblue/p/4672129.html

你可能感兴趣的:(JavaScript,算法)