ieee754 floating-point computer-science precision programming-fundamentals

IEEE 754 浮点数标准:深入理解计算机算术原理

为什么在编程中 0.1 + 0.2 != 0.3?了解 IEEE 754 浮点数表示法及其精度机制的底层原理。

2026-04-11

IEEE 754 浮点数标准:深入理解计算机算术原理

如果您从事过编程工作,很可能遇到过一个奇怪的现象:0.1 + 0.2 并不等于 0.3。相反,您会得到类似 0.30000000000000004 的结果。这并不是您所用编程语言的 bug,而是计算机使用 IEEE 754 标准表示实数的必然结果。

在本指南中,我们将揭开 IEEE 754 标准的神秘面纱,解释浮点数是如何存储的,并为在代码中处理精度问题提供实用建议。


什么是 IEEE 754?

IEEE 浮点算术标准 (IEEE 754) 是应用最广泛的浮点计算标准。它于 1985 年确立,定义了实数在二进制中的表示格式及其运算规则。

最常见的格式包括:

  • 单精度 (32 位):在 C/C++/Java 中对应 float
  • 双精度 (64 位):在 C/C++/Java 中对应 double,也是 JavaScript 和 Python 中的默认数字类型。

核心原理:浮点数的结构

浮点数的表示方式类似于科学计数法 ($1.23 \times 10^4$),只不过是二进制形式。它由三部分组成:

  1. 符号位 (1 位)0 表示正数,1 表示负数。
  2. 指数 (Exponent):决定数字的缩放范围。
  3. 尾数 (Mantissa/Significand):表示有效数字。

64 位双精度布局:

  • 符号位:1 位
  • 指数:11 位
  • 尾数:52 位

计算公式为: $(-1)^{sign} \times (1.mantissa) \times 2^{exponent - bias}$


为什么 $0.1 + 0.2 \neq 0.3$?

根本原因是大多数十进制小数无法在二进制中精确表示。

  • 在十进制中,如果一个分母的质因数只有 2 和 5(10 的因数),则该分数可以精确表示。
  • 在二进制中,只有当分母的质因数只有 2 时,分数才能精确表示。

$0.1$ 等于 $1/10$。由于 10 包含因数 5,它在二进制中变成了一个无限循环序列: 0.00011001100110011...

计算机必须截断这个无限序列以适应 32 位或 64 位的存储空间,从而导致了我们看到的微小误差。


特殊值

IEEE 754 还定义了几个特殊值来处理边界情况:

  • NaN (Not a Number):未定义运算的结果(如 0/0)。
  • Infinity ($\infty$):溢出或除以零的结果(如 1/0)。
  • 负零 (-0):在某些计算中与正零有所区别。

开发者最佳实践

  1. 永远不要用 == 比较浮点数:始终检查差值是否小于一个极小值 (epsilon)。
    if (Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON) { ... }
    
  2. 涉及货币时使用定点数:对于财务计算,请使用专门的库(如 decimal.js)或将数值存储为整数(例如以“分”为单位而不是“元”)。
  3. 注意数值范围:双精度可以表示非常大的数字,但随着数值增大,精度会降低。

常见问题 FAQ

问:浮点数运算是非确定性的吗? 答:通常不是。给定相同的输入和相同的舍入模式,IEEE 754 应该产生相同的结果。但是,不同的编译器或 CPU 指令(如 FMA)可能会导致细微差异。

问:什么是 "BigInt"? 答:JavaScript 中的 BigInt 用于处理任意精度的整数。它不能处理小数。对于小数,您需要 Decimal 库。

问:双精度有多少位十进制精度? 答:一个 64 位双精度浮点数大约有 15 到 17 位有效十进制数字。


相关工具

  • 单位转换器 - 在不同的度量单位之间进行精确转换。
  • JSON 格式化 - 检查数字在 JSON 数据中是如何表示的。
  • 哈希生成器 - 在每一位都至关重要的情况下验证数据完整性。