zlx362211854 / daily-study

每日一个知识点总结,以issue的形式体现
10 stars 6 forks source link

124. 为什么 0.1+0.2 !== 0.3 ? #181

Open goldEli opened 4 years ago

goldEli commented 4 years ago

0.1+0.2 === 0.3 // false

goldEli commented 4 years ago

由于计算机只认识二进制,所以在进行计算时,计算机需要把十进制转换成二进制。

计算机根据已知对照表,采用拼凑法对十进制进行转换。

整数二进制对照表 十进制 二进制
1 1
2 10
4 100
8 1000
16 10000
32 100000

小数二进制对照表

十进制 二进制
0.5 0.1
0.25 0.01
0.125 0.001
0.0625 0.0001
0.03125 0.00001

举几个例子试试:

转换8:

通过对照表得到1000。

转换7:

没有直接对应的,会在表中找比7小,且相邻的4,7-4=3,剩下的3也没有对应的,找到2,3-2=1,剩下的1可在表上直接找到。

所以

7 = 4 + 2 + 1 = 100 + 10 + 1 = 111

转换0.625:

同上可以分解为 0.5 + 0.125

0.625 = 0.5 + 0.125 = 0.1 + 0.01 = 0.11

最后我们来看看0.1 + 0.2 为什么不等于 0.3:

0.1 和 0.2 在对照表中都不能拼凑出来,所以 0.2只能拼出近似值:

0.2 = 1/8 + 1/16 + 1/128 + 1/256 + 1/512
= 0.201171875

如果不用拼凑法,用不断乘2的算法去计算 0.2 的二进制,是个无线循环的二进制,由于 IEEE 754 双精度。六十四位中符号位占一位,整数位占十一位,其余五十二位都为小数位。只能对0.2的二进制进行四舍五入,最终导致结果失真

计算中为了避免失真的问题,可以先转成整数计算后再转成小数。也可以用 js 原生的解决办法。

parseFloat(0.1+0.2).toFixed(10)
zlx362211854 commented 4 years ago

0.1+0.2为什么不等于0.3? 从数学上来说,肯定是相等的,但是我们要知道,计算机中的数字表示是不一样的,计算机中的数字,是由二进制表示的。

小数十进制转二进制 

我们知道,十进制1转化成二进制是1,2是10, 3是11 ... 那么小数的十进制如何转化成二进制呢?参考十进制的小数怎么转换成二进制,例如0.125转化成二进制就是0.001

js中的双精度浮点数

js中,数字是由双精度64位浮点数来存储的,什么叫双精度浮点数?我们把一个数字拆分开来看:

符号占一位 指数占11位 尾数占52位

总结来说,0.1转化成二进制,是一个无限循环的数,0.2同样也是一个无限循环的数,所以在计算机中,而且他们的尾数超过了52位,就无法精确的计算出来结果。所以0.1+0.2是两个无限循环的二进制数在进行加法运算,所以得出来的结果,当然不等于0.3了。