多多读书
638 字
3 分钟
JavaScript 使用 toFixed() 四舍五入失效了?

你有没有遇到过这种情况:在 JavaScript 中使用toFixed()方法对小数进行四舍五入,结果却不如预期?别担心,你不是一个人!让我们一起来看看这个常见问题,并学习如何解决它。

1. 问题案例#

在 JavaScript 中,我们经常使用toFixed()方法来格式化数字,保留指定的小数位数。然而,有时候我们会发现toFixed()的四舍五入结果并不符合预期。让我们看一个例子:

console.log((1.335).toFixed(2)) // 输出: "1.33"

在这个例子中,我们期望1.335四舍五入到两位小数应该是1.34,但实际输出却是1.33。这就是toFixed()四舍五入失效的一个典型案例。

2. 问题原因#

这个问题的根本原因在于 JavaScript 使用 IEEE 754 标准来表示数字,具体采用双精度浮点数格式。在 JavaScript 中,所有的数字都是以 64 位浮点数(即双精度浮点数)的形式存储的。这种存储方式可能导致一些精度问题。

在我们的例子中,1.335实际上在内部被表示为一个略小于1.335的数。当toFixed()尝试四舍五入时,它实际上是对这个略小的数进行操作,因此得到了1.33而不是1.34

3. 解决方案#

解决这个问题的方法有几种,下面介绍两种常用的方法:

3.1 使用 Math.round()配合乘除法#

我们可以先将数字乘以一个足够大的 10 的幂,然后使用Math.round()进行四舍五入,最后再除回去。这种方法可以避免toFixed()的精度问题。

function roundToFixed(num, decimalPlaces) {
  const factor = Math.pow(10, decimalPlaces)
  return (Math.round(num * factor) / factor).toFixed(decimalPlaces)
}

console.log(roundToFixed(1.335, 2)) // 输出: "1.34"

3.2 使用 Number.EPSILON 进行微调#

另一种方法是使用Number.EPSILON(表示 1 与大于 1 的最小浮点数之间的差值)来进行微调,然后再使用toFixed()

function roundToFixed(num, decimalPlaces) {
  return (Math.round((num + Number.EPSILON) * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPlaces)).toFixed(
    decimalPlaces
  )
}

console.log(roundToFixed(1.335, 2)) // 输出: "1.34"

4. 结论#

toFixed()方法的四舍五入失效问题源于 JavaScript 浮点数的内部表示方式。通过使用上述解决方案,我们可以在大多数情况下得到符合预期的四舍五入结果。然而,在处理金融等对精度要求极高的场景时,建议使用专门的 decimal 库来处理数字,以确保计算的准确性。

记住,在 JavaScript 中处理小数时要格外小心,始终要考虑到可能存在的精度问题。

JavaScript 使用 toFixed() 四舍五入失效了?
https://fuwari.vercel.app/posts/20240725/
作者
我也困了
发布于
2024-07-25
许可协议
CC BY-NC-SA 4.0