面试题:为什么 JavaScript 中 0.1 + 0.2 !== 0.3,如何让其相等?

这是一个经典的 JavaScript 浮点数精度问题。

一、为什么 0.1 + 0.2 !== 0.3

根本原因:二进制浮点数的精度限制

JavaScript 使用 IEEE 754 标准的 64 位双精度浮点数来表示数字。这种格式无法精确表示某些十进制小数(如 0.10.2),因为它们在二进制中是无限循环小数。

  • 0.1(十进制)在二进制中是 0.0001100110011...(无限循环)
  • 0.2(十进制)在二进制中是 0.001100110011...(无限循环)

由于计算机内存有限,这些无限循环的小数必须被截断或舍入,导致微小的精度损失。

实际计算结果:

console.log(0.1 + 0.2); 
// 输出:0.30000000000000004

console.log(0.1 + 0.2 === 0.3);
// 输出:false

0.1 + 0.2 的结果并不是精确的 0.3,而是略大于 0.30.30000000000000004


二、如何让 0.1 + 0.2 等于 0.3

方法 1:使用 Number.EPSILON 进行近似比较(推荐)

Number.EPSILON 表示 JavaScript 中可以表示的最小差值(约为 2.22e-16)。我们可以利用它来判断两个浮点数是否“足够接近”。

function isEqual(a, b) {
  return Math.abs(a - b) < Number.EPSILON;
}

isEqual(0.1 + 0.2, 0.3); // true

⚠️ 注意:Number.EPSILON 非常小,适用于大多数情况,但在涉及较大数字时可能需要调整容差。

方法 2:转换为整数进行计算

将小数乘以 10 的幂次,转换为整数运算,再除回去。

const result = (0.1 * 10 + 0.2 * 10) / 10; // (1 + 2) / 10 = 0.3
console.log(result === 0.3); // true

适用于已知小数位数的场景(如货币计算,以“分”为单位)。

方法 3:使用 toFixed() 并转换回数字

const result = parseFloat((0.1 + 0.2).toFixed(10));
console.log(result === 0.3); // true
  • toFixed(n) 将数字转换为指定小数位数的字符串。
  • parseFloat() 将其转回数字,并舍入到指定精度。

⚠️ 注意:toFixed() 返回字符串,需用 parseFloat()Number() 转回。

方法 4:使用专门的库

对于高精度计算,建议使用专门的库:

  • decimal.js
  • big.js
  • bignumber.js
// 使用 decimal.js 示例
const Decimal = require('decimal.js');
const a = new Decimal(0.1);
const b = new Decimal(0.2);
const sum = a.plus(b);
console.log(sum.equals(0.3)); // true

这些库使用十进制算术,避免了二进制浮点数的精度问题。


三、总结

问题解答
为什么 0.1 + 0.2 !== 0.3因为 0.10.2 在二进制中无法精确表示,导致计算时有微小的精度损失。
如何解决?使用 Number.EPSILON 进行近似比较(✅ 推荐)转换为整数运算使用 toFixed() + parseFloat()使用高精度计算库(如 decimal.js

核心思想:JavaScript 的浮点数精度问题是语言底层机制决定的,无法完全避免。在涉及小数计算时,应避免直接使用 === 比较,而是采用近似比较整数化策略。

THE END
喜欢就支持一下吧
点赞10 分享