跳到主要内容

浮点数运算

· 阅读需 3 分钟

现象

在浮点数运算时会出现下面的情况:

0.1 + 0.2 === 0.3 // false
0.5 - 0.4 === 0.1 // false
0.5 - 0.25 === 0.25 // true

原因

首先这不是 JS 的设计缺陷,浮点数精度问题在几乎所有采用 IEEE 754 标准的编程语言(C#、Ruby、Go、Python)中都存在。

浮点数是使用 IEEE 754 标准来表示和存储的。这个标准在表示一些分数时会产生精度问题,因为它使用的是二进制浮点格式,而并非所有的十进制小数都能精确地转换为二进制小数

由于二进制浮点数转换规则,导致了精度缺失的问题

转换规则

参考十进制浮点数的一种拆分思路: $$ 314 = 3 10^2 + 1 10^1 + 4 * 10^0 $$

$$ 3.14 = 3 10^0 + 1 10^{-1} + 4 * 10^{-2} $$

推导出二进制浮点数转十进制的规则:每一位数字分别乘以 2 的若干次幂(小数点前从 0 开始,小数点后从 -1 开始)的积再累加 $$ 101 = 1 2^2 + 02^1 +1*2^0 = 5 $$

$$ 1.101 = 1 2^0 + 1 2^{-1} + 0 2^{-2} + 1 2^{-3} = 1.625 $$

根据以上转换规则,我们会发现任何二进制的浮点数转为十进制后,最后一位一定是 5

也就是说只有最后一位是 5 的十进制浮点数,才有可能转换出有限位数的二进制浮点数

0.1 和 0.3 转为二进制都是无限的位数,相加导致精确丢失,从而影响计算结果

解决

将浮点数转为字符串,写一个十进制的规则来解决浮点数的运算,当然也可以使用第三方库

  • JS 中的十进制与二进制转换方法
// 十转二
const num = 314
num.toString(2)
// 二转十
parseInt('100111010', 2)