定点数与浮点数表示(IEEE 754 标准)

定点数与浮点数表示(IEEE 754 标准)

🎯 学习目标

  • 理解定点数的基本思想(为浮点做铺垫)
  • 掌握 IEEE 754 单精度(32位)浮点数的结构
  • 能手动将十进制小数转换为 IEEE 754 格式
  • 理解 为什么 0.1 + 0.2 != 0.3
  • 了解特殊值:无穷大(∞)、NaN、非规格化数

一、为什么需要浮点数?

整数可用补码完美表示,但现实中有大量小数

  • 科学计算:3.1415926
  • 金融:99.99
  • 图形:坐标 (1.5, -2.3)

如果用固定小数点位置(比如始终保留2位小数),叫 定点数(Fixed-Point)

  • 优点:硬件简单,运算快
  • 缺点:范围小、精度固定(无法同时表示 0.0000011000000.0

【Q&A】为什么定点数无法同时表示极小数和极大数?
因为定点数的小数点位置在硬件中是固定的。例如,若用32位表示,你必须预先分配多少位给整数部分、多少位给小数部分。

  • 表示 1000000.0 需要约20位整数部分;
  • 表示 0.000001 需要约20位小数部分;
    但总共只有32位,无法兼顾。
    浮点数通过“阶码”动态调整尺度,用同一格式覆盖极大范围和高精度。

→ 所以需要 浮点数(Floating-Point)小数点位置可以“浮动”,类似科学计数法!


二、科学计数法 → 浮点数思想

十进制科学计数法:
123.45 = 1.2345 × 10²

二进制科学计数法:
5.75₁₀ = 101.11₂ = 1.0111 × 2²

浮点数就是把一个数拆成三部分:
数值 = (-1)^S × (1.M) × 2^(E - Bias)

  • S:符号位(0正,1负)
  • M:尾数(Mantissa / Fraction),表示有效数字
  • E:阶码(Exponent),表示指数(带偏移)

✅ 这就是 IEEE 754 标准的核心!


三、IEEE 754 单精度(32位)格式

位段 长度 含义
S(符号) 1 位 0 = 正,1 = 负
E(阶码) 8 位 存储 指数 + 偏移量(Bias)
M(尾数) 23 位 存储小数部分(隐含前导1

💡 偏移量(Bias):单精度用 127,所以实际指数 = E - 127

🌟 关键技巧:隐含前导1(Hidden Bit)

  • 规格化数(Normalized)的二进制形式总是 1.xxxxx
  • 所以 IEEE 754 不存这个“1”,只存小数部分 xxxxx,省1位,提高精度!

【Q&A】单精度是否等于“1位整数 + 多位小数 + 偏移”?
是的!更准确地说:
单精度将实数表示为 二进制科学计数法 (-1)^S × 1.M × 2^E,然后:

  • 符号 S 存 1 位;
  • 尾数只存 M(23位小数部分),前导 1. 是隐含的;
  • 阶码存 E + 127(8位无符号整数)
    这三部分组成32位,实现高效、统一的浮点表示。

四、动手:十进制 → IEEE 754(单精度)

例:+5.75

  1. 转二进制:101.11
  2. 规格化:1.0111 × 2² → M = 0111..., E真实 = 2
  3. 阶码存储:2 + 127 = 129 → 1000 0001
  4. 组合: 0 10000001 01110000000000000000000

五、为什么 0.1 + 0.2 != 0.3

  • 0.1₁₀ = 0.0001100110011...₂(无限循环)
  • IEEE 754 只能存 23位尾数 → 必须截断/舍入
  • 内存中存的是 近似值 ≈ 0.10000000149…
  • 两个近似值相加 ≠ 0.3 的近似值

✅ 在 Python 中:

1
2
3
4
>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False

💡 启示:永远不要用 == 比较浮点数!应使用 abs(a - b) < epsilon


六、IEEE 754 单精度(32位)

部分 位数 说明
S 1 符号位(0 = 正,1 = 负)
E 8 阶码(Exponent),偏置值 Bias = 127
M 23 尾数(Mantissa/Fraction),隐含前导 1

💡 小知识:实际数值计算公式为
$
(-1)^S \times (1.M) \times 2^{E - 127}
$
其中 1.M 表示二进制小数(如 1.101)。

示例:将十进制数 5.0 转换为 IEEE 754 单精度

  1. 转二进制:
    $ 5.0_{10} = 101.0_2 = 1.01_2 \times 2^2 $

  2. 确定各字段:

    • S = 0(正数)
    • E = 2 + 127 = 129 → 二进制 10000001
    • M = 01 后补零至 23 位 → 01000000000000000000000
  3. 最终 32 位表示:

1
2
3
0 10000001 01000000000000000000000
↑ ↑ ↑
S E(8位) M(23位)

七、双精度(64位)简介

部分 位数 说明
S 1 符号
E 11 阶码(Bias = 1023)
M 52 尾数(隐含前导1)

精度:≈15 ~ 17 位十进制
范围:≈ ±10³⁰⁸
编程语言中 double 类型即为此格式