从0.1 + 0.2 !== 0.3到0.2 + 0.3 === 0.5的遐想

406 阅读1分钟

原因

因为计算机只能识别二进制数,0.1和0.2转化成二进制时会得到一个无限循环的小数。JS的数字遵循IEEE754标准(常被称谓浮点数),且使用双精度格式。由于的精度问题需要0舍1入,所以得到的结果会存在精度丢失,所以不等于0.3。

比较方法

正确的比较方法是Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON

发现

有趣的发现,0.2+0.3是等于0.5,0.1+0.4也是等于0.5。巧的是0.5转化为二进制数是0.1,没有精度丢失得问题。那么暂时可得到结论,当两个小数相加得到的实际结果没有精度丢失问题时,那么这两个小数相加后不会发生精度丢失。

没有丢失精度的推论

  • 小数转二进制: 每次小数乘2取整数位,依次拿到结果迭代,直至小数为0,例如0.2,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.001100110011…

0.2转二进制 0.0011001100110011...
0.3转二进制 0.0100110011001100...
不难看出0.2的11与0.3的00存在位置互补,当0舍1入时相同精度正好只有一个数会进1,此时互补相消得到0.1