快捷搜索:

0.1 + 0.2 不是等于 0.3的原因,以及处理方法

原因

js中的数字

JavaScript的Number类型为类型。

那么一个Number的二进制的形态为

    第0位:符号位,0表示正数,1表示负数(s) 第1位到第11位:储存指数部分(e) 第12位到第63位:储存小数部分(即有效数字)f
JS中Number的最大安全整数为(2^52 -1) = 4503599627370495 是一个16位的整数,因此当我们赋值大于安全整数的一个Number给一个变量的时候,那么到输出的时候就会得到的值和我们赋予的值不同,

二进制的转换

由于JavaScript的Number类型为类型,因此当JS要表示一个数字的时候需要进行二进制的转换

整数转二进制

除2 (取余)

例如 21 得 10101 如果计算机是8位 16位 32位 64位 不够的就往前补0

21 /2 ----------余  1
10/2  ----------余  0
5/2   ----------余  1
2/2   ----------余  0
1/2   ----------余  1

负整数转二进制

先是将对应的正整数转换成二进制后,对二进制取反(0-1对调),然后对结果再加一

例子 -21 得 01011

21 的二进制表示为: 10101
取反:  01010
加一 : 01011
二进制中 0+1 = 1 ; 1+0 = 1; 1+1 = 10 就相当于进一位

十进制(小数)转二进制

乘2(取整)

例如 0.125 得0.001

0.125×2=0.25 ---> 0

0.25×2=0.5 ---> 0

0.5×2=1.0 ---> 1

例如:0.1 得 0.000110.... 答案是一个无线的小数

0.1 * 2 = 0.2  --->  0
    0.2 * 2 = 0.4  --->  0
    0.4 * 2 = 0.8  --->  0
    0.8 * 2 = 1.6  --->  1
    0.6 * 2 = 1.2  --->  1
    0.2 * 2 = 0.4  --->  0
    .....

因此

0.1 -> 0.0001100110011001...(无限循环) 0.2 -> 0.0011001100110011...(无限循环)

但是由于IEEE 754尾数位数限制,需要将后面多余的位截掉,截取后精度发生了一些变化,然后在(二进制的相加对阶运算)2个都有精度变化的0.1+0.2就很不幸运的成为了0.30000000000000004....

但是由于我们前面有提到尾数f的固定长度是52位,是4503599627370495 是一个16位的整数,所以JS会有一个类似 toPrecision(16) 来做精度运算,0.30000000000000004....就被截取为了0.30000000000000004,所以0.1+0.2!===0.3,

总结原因就是:精度损失可能出现在进制转化和对阶运算过程中

解决方法

console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);
经验分享 程序员 微信小程序 职场和发展