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