这是本人系列《底层的世界——计算机组成原理》的第二章——数的世界,用于记录分享和期末复习,欢迎讨论!

引言:在计算机的世界里,所有数据最终都以二进制的0和1存储。整数的表示相对简单,但当我们需要处理小数时,问题就变得复杂起来——计算机硬件本身并不认识”小数点”这个符号。为了解决小数的表示与运算问题,人类先后发明了定点数和浮点数两种方案。它们诞生于不同的时代背景,有着截然不同的设计哲学,至今仍在各自的领域发挥着重要作用。

计算机世界的”小数点”

小数,生活中非常常见。特别是我染上ds后深深的体会到了:今日吞5毛,明日吞3角,然后得一昔安寝——小数,对我这种穷逼来说,非常重要。
但是小数这个概念,根本就不存在于计算机的世界,为了表示数,秃头的老辈子们发明了定点数和浮点数。

一、定点数:小数点——约吗?

什么是定点数?(定点数的定义与背景)

只有整数怎么办?其中一种表示小数的方法就是把小数定下来。

定点数是计算机发展早期的产物。在20世纪中叶,计算机硬件极为简陋,运算单元只能处理整数运算,没有专门的浮点运算硬件。为了表示小数,工程师们想出了一个朴素的办法:人为约定小数点在二进制数位中的固定位置,这样就可以用整数运算来间接处理小数。

小数点:“约吗?”

例如:十进制的 78.125
整数部分:78使用二进制表示为:100 1110
小数部分:0.125使用二进制表示为:.001
所以合起来使用100 1110.001 表示十进制的78.125
为什么不是78.91,因为91转2进制除不尽

神秘的表示方式:Q格式

拓展内容,初学者可以不看

定点数最常用的表示方法是Q格式(Q notation),其核心思想是将一个整数”放大”一定倍数来表示小数。

标准格式:Qm.n
注解:

  • m:整数部分的位数(不包含符号位)
  • n:小数部分的位数
  • 总位数 = m + n + 1(额外1位是符号位)

例如,最常见的Q15格式(16位有符号数):

  • 1位符号位 + 0位整数位 + 15位小数位
  • 数值范围:-1 ≤ x < 0.9999695
  • 精度:2⁻¹⁵ ≈ 0.0000305

残疾人转换公式:

  • 浮点数 → 定点数:$Q = F × 2^n$ 其中Q为整数
  • 定点数 → 浮点数:$F = Q × 2^{-n}$

举个例子,用Q15表示0.5:
0.5 × 2¹⁵ = 16384 转二进制为100 0000 0000 0000

符号位 数值
0 100 0000 0000 0000

定点数的优缺点

优点:

  • 运算速度快:本质是整数运算,无需额外硬件支持
  • 精度均匀:整个数值范围内精度保持一致,没有精度漂移
  • 实现简单:硬件电路复杂度低,功耗小
  • 结果确定:没有舍入误差的累积问题(在不溢出的前提下)

缺点:

  • 数值范围小:同样位数下,能表示的数值范围远小于浮点数
    • 32位Q16.15格式:最大值约为2¹⁶ = 65536
    • 32位浮点数:最大值约为3.4×10³⁸
  • 灵活性差:小数点位置一旦确定就不能更改,需要程序员手动定标
  • 容易溢出:运算过程中如果数值超出范围,需要手动处理溢出
  • 开发难度高:需要程序员自行管理小数点位置和缩放比例

这种方案的好处是硬件实现极其简单,只需要整数加法器和移位器就能完成所有运算。早期的单片机、DSP(数字信号处理器)大多采用定点架构,正是因为其成本低、功耗小、速度快。但是随着时间的推移,人们需要更精确的小数运算,这种情况下另一个魔丸要出世了……

浮点数:老牧师的科学计数法

魔丸出世

随着计算机应用向科学计算领域拓展,定点数的局限性越来越明显。物理学家需要表示电子质量(9×10⁻²⁸克),天文学家需要计算恒星距离(数以光年计),这些数值跨度极大,定点数根本无法覆盖。

为了解决”极大”和”极小”数的表示问题,科学家借鉴了十进制科学计数法的思想——用
$$ N = (-1)^S \times (1 + M) \times 2^{(E - \text{bias})} $$
的形式表示数值,让小数点的位置随指数变化而”浮动”,这就是浮点数名称的由来。
先别吓晕,我会给你解释一下这一坨到底是什么的,我们先从十进制开始:

普通十进制数 科学计数法表示 说明
12300 $1.23 \times 10^4$ 小数点左移4位
0.00456 $4.56 \times 10^{-3}$ 小数点右移3位
-789000 $-7.89 \times 10^5$ 负数保持符号在尾数前
9.8 $9.8 \times 10^0$ 1~10之间的数指数为0

可以看到十进制科学计数法的表示如下:
$$ N = a \times 10^n $$

  • a:尾数,满足 $1 \le |a| < 10$
  • n:指数,整数,代表小数点移动的位数

那么理解二进制科学计数法也就容易了:
$$ N = M \times 2^E $$

  • M:尾数
  • E:指数,整数,代表小数点移动的位数

但是有个问题,在表示科学计数法的时候,我们规定尾数满足 $1 \le |a| < 10$,意思说不规定我们会有许多猎奇的表示方法,比如说用$0.0000001 \times 10^{1000000}$表示1,这你能受的了吗?
于是我们规定M必须是1.x开始,这个叫做浮点数的规格化,在公式中就能表示成
(1 + M)。
我们要能表示正负数,又引入了-1的指数S,控制S的值就能控制整个数的正负。
完全体如下:
$$ N = (-1)^S \times (1 + M) \times 2^E $$

为了统一,1985年,IEEE(电气和电子工程师协会)发布了IEEE 754标准,统一了浮点数的表示格式,成为至今通用的工业标准。

IEEE 754标准

IEEE 754浮点数由三部分组成:符号位、指数位、尾数位。

通用公式:
$$ N = (-1)^S \times (1 + M) \times 2^{(E - \text{bias})} $$

单精度浮点数(float,32位)

符号位(S) 指数位(E) 尾数位(M)
1位(0=正,1=负) 8位(偏移量为127) 23位 (隐含整数部分的1)

隐含整数部分:规格化的二进制浮点数,尾数的最高位总是1。因此这个1可以不用存储,节省了1位空间,实际精度比存储位数多1位。

数值范围:

  • 最大值:≈ 3.4 × 10³⁸
  • 最小值(绝对值):≈ 1.2 × 10⁻³⁸

双精度浮点数(double,64位)

组成部分 位数 位置 说明
符号位(S) 1位 第63位 0=正,1=负
指数位(E) 11位 第62-52位 偏移量为1023
尾数位(M) 52位 第51-0位 隐含整数部分的1

隐含整数部分:规格化的二进制浮点数,尾数的最高位总是1。因此这个1可以不用存储,节省了1位空间,实际精度比存储位数多1位。

数值范围:

  • 最大值:≈ 1.8 × 10³⁰⁸
  • 最小值(绝对值):≈ 2.2 × 10⁻³⁰⁸

浮点数的优缺点

优点:

  • 数值范围极大:同样位数下,范围远超定点数,适合科学计算
  • 使用方便:程序员无需关心小数点位置,编译器自动处理
  • 标准化程度高:IEEE 754是通用标准,跨平台一致性好
  • 支持特殊值:可以表示无穷大、NaN(非数值)等特殊状态

缺点:

  • 精度不均匀:数值越大,精度越低。靠近0的地方精度很高,远离0的地方精度稀疏这点要格外注意
  • 运算速度慢:需要专门的浮点运算单元(FPU),硬件复杂度高
  • 存在舍入误差:很多十进制小数(如0.1)无法用二进制精确表示
  • 运算有损耗:多次运算后误差会累积,不能直接用”==”比较两个浮点数

对比

对比维度 定点数 浮点数
小数点位置 固定不变 随指数浮动
数值范围 小 极大
精度分布 均匀一致 近密远疏
运算速度 快(整数运算) 慢(需FPU)
硬件成本 低 高
开发难度 高(手动定标) 低(自动处理)
典型应用 嵌入式、DSP、音频处理 科学计算、图形渲染、通用编程

现实中的应用

定点数的主战场

  • 嵌入式系统:MCU、单片机等资源受限的设备
  • 数字信号处理:音频编解码、滤波、FFT等实时信号处理
  • FPGA/ASIC设计:硬件电路中定点运算更省资源
  • 工业控制:对确定性要求高,不允许误差累积

浮点数的天下

  • 科学计算:物理模拟、气象预报、航天工程
  • 计算机图形学:3D渲染、坐标变换、光照计算
  • 通用软件开发:业务系统、数据分析、人工智能
  • 金融计算(注意:高精度金融场景通常用十进制定点或BCD码)

总结

定点数和浮点数并非谁取代谁的关系,而是针对不同需求的两种设计取舍:

  • 定点数是”空间换时间”的极致——用有限的数值范围换取更快的运算速度、更低的硬件成本和均匀的精度。它诞生于资源匮乏的年代,却在嵌入式、DSP等领域历久弥新。

  • 浮点数是”时间换空间”的智慧——用更复杂的运算逻辑换取近乎无限的数值范围和使用上的便利性。它是科学计算的基石,也是现代通用计算机的标配。

理解这两种数值表示方式,不仅能帮我们写出更高效的代码,更能体会到计算机科学中”权衡”与”折中”的设计哲学——没有完美的方案,只有最适合场景的选择。


小思考:为什么0.1 + 0.2 在JavaScript和Python中不等于0.3?这正是浮点数二进制表示的经典问题,答案就藏在IEEE 754的尾数精度里。
这个问题同样也是数学中0.9无限循环等于1的原因。