一篇搞懂 为啥js精度问题频出

米阳 2023-9-19 246 9/19

首先要知道JavaScript 并非唯一会出现浮点数精度丢失的语言,​所有遵循 IEEE 754 标准的编程语言在二进制浮点运算中都会面临精度问题。例如,Python、Java 等语言在浮点运算时同样可能因二进制表示特性导致精度丢失。但 JavaScript 的精度问题更常被提及,原因如下:

python
print(0.1 + 0.2)  # 输出 0.30000000000000004

java
System.out.println(0.1 + 0.2); // 输出 0.30000000000000004

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

单数值类型

  • JavaScript 只有一种数值类型 Number,即 ​64 位双精度浮点数​(IEEE 754)。
  • 其他语言(如 Java)提供多种数值类型:
    • 整数类型​(如 intlong):精确表示整数。
    • 高精度小数类型​(如 BigDecimaldecimal):避免浮点误差。
    • 浮点类型​(如 floatdouble):与 JavaScript 类似,但开发者可主动选择。
import java.math.BigDecimal;
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
System.out.println(a.add(b)); // 输出精确的 0.3

弱类型与隐式转换

  • JavaScript 是弱类型语言,开发者无需声明变量类型,容易误将浮点数用于需要精确计算的场景(如金融计算)。
  • 其他强类型语言(如 Java)强制声明类型,开发者更可能选择高精度类型

前端场景的高频使用

  • JavaScript 在前端开发中常处理用户输入、金额计算等场景,精度问题容易被用户感知。
  • 后端语言(如 Python、Java)的精度问题更多出现在内部计算中,可能通过类型选择或库规避。

如何解决 JavaScript 的精度问题

虽然 JavaScript 没有内置的任意精度小数类型,但可通过以下方法规避误差:

  1. 整数运算代替小数运算

    将小数放大为整数运算,再缩小回小数:

    // 计算 0.1 + 0.2
    const result = (0.1 * 10 + 0.2 * 10) / 10; // 0.3
  2. 使用高精度库 decimal.jsbig.js

    //decimal.js
    import { Decimal } from 'decimal.js';
    const a = new Decimal('0.1');
    const b = new Decimal('0.2');
    console.log(a.add(b).toString()); // 输出 "0.3"
    
    //big.js
    import { Big } from 'big.js';
    const a = new Big('0.1');
    const b = new Big('0.2');
    console.log(a.plus(b).toString()); // 输出 "0.3"

     

  3. 限制小数位数

    使用 toFixed() 或 toPrecision() 控制显示位数(注意:底层存储仍不精确):

    console.log((0.1 + 0.2).toFixed(2)); // 输出 "0.30"

 

总结

  • 精度丢失是二进制浮点数的固有缺陷,所有遵循 IEEE 754 的语言都会遇到。
  • JavaScript 因单数值类型、弱类型特性及前端场景的高频使用,问题更易暴露。
  • 推荐通过整数运算、高精度库或后端类型选择(如 decimal)可规避问题。

 

 

 

 

 

- THE END -
Tag:

米阳

3月24日10:09

最后修改:2025年3月24日
0