为什么0.1+0.2===0.3?
// 结果为false
console.log(0.1+0.2===0.3)
// 结果0.30000000000000004 而不是0.3
console.log(0.1+0.2)
计算机中数字的存储方式
在计算机中数字无论是定点数还是浮点数都是以多位二进制的方式进行存储的。
在定点数中,如果我们以8位二进制来存储数字。
对于整数来说,十进制的35会被存储为: 00100011 其代表 2^5 + 2^1 + 2^0;
对于纯小数来说,十进制的0.375会被存储为: 0.011 其代表 1/2^2 + 1/2^3 = 1/4 + 1/8 = 0.375;
对于像0.1这样的数值用二进制表示你就会发现无法整除,最后算下来会是 0.000110011…由于存储空间有限,最后计算机会舍弃后面的数值,所以我们最后就只能得到一个近似值。
JS中采用的IEEE 754的双精度标准也是一样的道理在存储空间有限的情况下,当出现这种无法整除的小数的时候就会取一个近似值,在js中如果这个近似值足够近似,那么js就会认为他就是那个值。
console.log(0.1000000000000001)
// 0.1000000000000001 (中间14个0,会打印除本身)
console.log(0.10000000000000001)
// 0.1 (中间15个0,js会认为两个值足够近似,所以输出0.1)
由于0.1转换成二进制时是无限循环的,所以在计算机中0.1只能存储成一个近似值。另外说一句,除了那些能表示成 x/2^n 的数可以被精确表示以外,其余小数都是以近似值得方式存在的。
结论
JS中的小数在计算机中存储的基本都是近似值; 索引在实际开发中应该尽量避免小数的计算.
解决办法
想办法规避掉这类小数计算时的精度问题就好了,那么最常用的方法就是将浮点数转化成整数计算。因为整数都是可以精确表示的。
0.1+0.2 => (0.1*10+0.2*10)/10
JS中将十进制数转换成二进制
- Number.toString(进制)
var num=0.1;
// 打印结果: 0.0001100110011001100110011001100110011001100110011001101
num.toString(2)
JS中将其他进制转换成十进制
- parseInt(目标数值,进制)
var num=111;
// 打印结果为7
console.log(parseInt(num,2))
关于parseInt()的面试题
// 执行结果为: 1 NaN NaN
[1,2,3].map(parseInt);
// 解析; parseInt(目标数值,进制), 进制默认是2-36之间
[1,2,3].map(function(val,key){
parseInt(val,key);
// parseInt(目标数值, 进制): 进制2-36之间
// val=1; key=0 parseInt(1,0) 0表示十进制
// val=2; key=1 parseInt(2,1)
// val=3; key=2 parseInt(3,2)
});
网友评论