文章目录
- [一、定点数(Fixed-Point Number)](#一、定点数(Fixed-Point Number))
- [二、浮点数(Floating-Point Number)](#二、浮点数(Floating-Point Number))
- 浮点数与定点数的对比
定点数和浮点数是计算机中表示数值的两种主要方式,它们在精度、范围和运算效率上有显著差异。
一、定点数(Fixed-Point Number)
定义
定点数是计算机中表示实数(即带小数部分的数字)的一种方法。它的核心思想是约定小数点在二进制数中的位置是固定不变的。
定点数就是将整数运算电路直接用于小数运算的一种高效方式。
定点数的表示方法
定点数的格式通常描述为 Qm.n 或 Fx.m.n,其中:
m: 表示整数部分的位数(包括可能的符号位)。
n: 表示小数部分的位数。
总位数: m + n。
最常见的形式如下:
定点整数
小数点位置:固定在数字的最右边。
表示范围:只能表示整数。
例子:8位无符号定点整数,范围是 0 到 255。本质上就是普通的整数。
定点小数
小数点位置:固定在数字的最左边(紧跟在符号位之后)。
表示范围:只能表示小于1的纯小数。
例子:8位定点小数(1位符号位,7位小数位),能表示的范围大约是 -1 到 1。
带整数和小数的定点数(最常见)
小数点位置:固定在数字中间的某个位置。
例子:一个 Q8.8 格式的16位定点数,意思是高8位是整数部分(其中最高位通常是符号位),低8位是小数部分。
特点
1、表示范围有限
数值范围由整数和小数部分的位数决定。例如,8位定点数(Q3.4)范围为:-8.0 到 7.9375(二进制补码表示)。
2、精度固定
小数位数固定,运算时不会丢失精度(但可能溢出)。
3、运算效率高
硬件实现简单,适合嵌入式系统或对速度要求高的场景(如数字信号处理)。
4、无指数部分
仅通过整数和小数部分表示数值,无阶码(指数)和尾数的分离结构。
示例
Q2.3格式(总5位,2位整数,3位小数):
二进制 101.011 = 1×2¹ + 0×2⁰ + 1×2⁻¹ + 0×2⁻² + 1×2⁻³ = 2 + 0.5 + 0.125 = 2.625
范围:-4.0 到 3.875(补码表示)。
定点数的运算
定点数的运算基于整数运算,但需要手动处理小数点。
1. 加减法
规则:小数点必须对齐。只有相同格式(即 n 相同)的定点数才能直接相加减。
操作:直接将两个数的整数表示 V1 和 V2 相加。
结果:结果的格式仍然是与操作数相同的 Qm.n。
例子:2.5 (Q12.3 的 20) + 1.0 (Q12.3 的 8) = 20 + 8 = 28。 28 / 8 = 3.5。
2. 乘法
规则:乘法会导致小数位数变化。
操作:直接将两个数的整数表示 V1 和 V2 相乘。
结果分析:
V result = V1×V2=(R1×2 ^ n)×(R2×2 ^ n)=(R1×R2)×2 ^ 2n
此时,Vresult 代表的是实际值R1 * R2 * 2 ^ 2n。也就是说,中间结果的"小数点"偏移到了 2 ^ n位后。
修正:为了将结果存回原始的 Qm.n 格式,我们需要将乘积结果右移 n 位。
例子:2.5 (20) * 2.0 (16) = 320。
320 对应的是(2.5 * 2.0)* 2 ^ (2 * 3) = 5 * 64 = 320
要得到 Q12.3 格式的 5.0,我们需要右移 3 位: 320 >> 3 = 40。
验证:40 / 8 = 5.0。
3. 除法
规则:除法同样会改变小数位数。
操作:为了得到 Qm.n 格式的商,需要先将被除数左移 n 位,然后再除以除数。
V result = (V1<<n)/V2
定点数的优缺点
优点
1、速度快:定点数运算直接使用CPU的整数算术逻辑单元(ALU),不涉及浮点运算单元(FPU)。在没有FPU的低端微控制器(MCU)或早期游戏中,这是巨大的性能优势。
2、精度确定:定点数的精度在整个数值范围内是均匀的。而浮点数的精度会随着数值的增大而降低(大数加小数可能没变化)。
3、确定性:定点运算在不同平台上的结果完全一致(因为就是整数运算)。浮点数由于精度和舍入模式的差异,在不同硬件上可能会有细微差别。
4、成本和功耗低:实现定点运算所需的逻辑门电路比浮点运算少得多。
缺点
1、动态范围小:容易溢出或下溢。例如,用16位定点数很难同时表示一个非常大的数(如星系距离)和一个非常小的数(如原子直径)。
2、编程复杂度高:程序员必须时刻跟踪小数点的位置,手动处理乘法后的移位操作,防止溢出。
3、精度损失:在转换格式或进行除法时,可能会因为截断而产生误差。
应用场景
1、嵌入式系统:许多8位或32位的微控制器(如ARM Cortex-M系列的一些型号)没有硬件FPU,使用定点数是处理小数的唯一高效方式。
2、数字信号处理(DSP):音频编解码、调制解调、图像滤波等算法大量使用定点数,因为它们对实时性要求极高,且精度可控。
3、金融计算:某些金融系统要求精确到分,且运算结果必须完全确定,以避免法律纠纷。定点数(或直接用整数表示"分")是比浮点数更安全的选择。
4、旧式游戏机和早期3D游戏:在3D图形加速卡普及之前,许多游戏(如《毁灭战士》)的3D渲染逻辑完全依赖定点数来实现透视变换。
二、浮点数(Floating-Point Number)
定义
浮点数(Floating-point number)是计算机中表示实数(即包含小数部分的数)的一种重要方式。与之前介绍的定点数不同,浮点数的小数点位置是"浮动"的,这使得它能够以固定的位数表示极大和极小的数值,同时保持较高的精度。
浮点数采用科学计数法,通过符号位、阶码(指数)和尾数(有效数字)表示数值,小数点位置可浮动。例如,IEEE 754标准。
为什么需要浮点数?
定点数虽然简单高效,但存在一个根本性的缺陷:动态范围小。用16位定点数,你无法同时表示一个原子的直径 (10 ^ (-10米))和一个星系的距离(10 ^ 20米)。
为了覆盖如此巨大的范围,我们需要一种类似于科学记数法的表示方法:
数值=尾数 ×(基数 ^ 指数)
特点
1、表示范围大
阶码决定范围,尾数决定精度。例如,32位单精度浮点数范围约 ±3.4×10³⁸。
2、精度动态调整
尾数位数固定,但有效数字位数随数值大小变化(大数精度低,小数精度高)。
3、运算复杂度高
需处理阶码对齐、尾数运算和规格化,硬件开销大。
4、存在舍入误差
尾数位数有限,可能丢失精度(如0.1无法精确表示)。
例如,阿伏伽德罗常数6.022 * (10 ^ 23),光速3.0 * (10 * 8)m/s。在计算机中,我们使用二进制科学记数法,这就是浮点数的核心思想。
IEEE 754标准
目前几乎所有计算机都采用 IEEE 754 浮点数标准。它定义了多种精度格式,最常用的是:
1、单精度(32位):通常称为 float。
2、双精度(64位):通常称为 double。
基本格式
一个 IEEE 754 浮点数由三个字段组成(以单精度为例,双精度类似但位数不同):
| 字段 | 单精度位数 | 双精度位数 | 说明 |
|---|---|---|---|
| 符号位 (S) | 1 | 1 | 0 表示正数,1 表示负数 |
| 指数位 (E) | 8 | 11 | 使用移码(偏移量)表示 |
| 尾数位 (M) | 23 | 52 | 存储规格化后的小数部分(隐含整数位1) |
计算公式(以单精度为例):
数值 = (-1 ^ S)* (1.M) * (2 ^ (E - 127))
指数偏移量(bias)为 127(双精度为 1023)。
尾数 M 是一个小数部分,隐含的整数部分总是 1(规格化数的情况)。
规格化数
当指数位不全为0且不全为1时,我们称这个数为规格化数。此时尾数部分隐含一个整数位"1",因此实际有效位数为 24 位(单精度)。这保证了精度最大化。
例如,单精度浮点数 0 01111100 01000000000000000000000:
符号 S = 0
指数 E = 124 → 实际指数 = 124 - 127 = -3
尾数 M = 0.01(二进制) = 0.25(十进制)
数值 = 1.25 * (2 ^ -3)= 0.15625
非规格化数
当指数位全为0时,我们进入非规格化数(或称次正规数)区域。此时隐含的整数位变为0,公式为:
数值 = (-1 ^ S)* (0.M) * (2 ^ - 126)
非规格化数主要用于表示接近0的极小数值,实现逐渐下溢,避免突然下溢到0。
特殊值
IEEE 754 还定义了几个特殊值的表示
无穷大:指数全1,尾数全0。符号位表示正无穷或负无穷。用于溢出等情况。
NaN(Not a Number):指数全1,尾数非0。用于表示无效运算结果,如 0/0、√(-1)(根号-1)等。
浮点数的范围与精度(单精度为例)
最大正规格化数:约3.4×(10 ^ 38)( 2 ^ (128 − 127) × ( 2 − 2 ^ (− 23) )
最小正规格化数:约1.2×(10 ^ -38)( 2 ^ (1 − 127) × 1.0)
最小正非规格化数:约 1.2×(10 ^ -45)( 2 ^ -149)
精度:大约 7 位十进制有效数字(因为2 ^ -23 ≈ 1.2×(10^-7)
双精度的范围约(10 ^ -308)到(10 ^ 308),精度约 15-16 位十进制有效数字。
浮点数的优缺点
优点
动态范围极大:能同时表示极大和极小的数。
相对精度固定:有效数字位数基本固定,数值的相对误差大致均匀。
标准化:IEEE 754 保证了跨平台的一致性(除了一些细节如舍入)。
缺点
精度不均匀:数值越大,绝对误差越大。例如,100000000 附近的两个浮点数之间的间隔可能大于1,导致无法表示所有整数。
运算复杂:硬件实现复杂,功耗和面积大于整数运算单元。
存在舍入误差:许多十进制小数无法精确表示(如 0.1),导致累积误差。
比较时需小心:由于误差,直接判断两个浮点数相等(a == b)往往不可靠。
实际应用中的注意事项
1、避免直接比较相等:应使用容差比较,如 fabs(a - b) < epsilon。
2、警惕大数吃小数:当非常大和非常小的数相加时,小数可能被"吃掉"而丢失。例如,1e20 + 1.0 在单精度下结果仍然是 1e20。
3、累积误差:长循环或迭代计算时,误差可能积累到不可接受的程度。可考虑使用更高精度或改变算法。
4、不要用浮点数表示精确值:如货币金额,应使用整数(分)或定点数。
5、了解编译器和硬件的浮点行为:一些编译优化可能改变运算顺序,导致结果变化(如 -ffast-math 选项)。
示例:
试试在 Python 中运行:
c
>>> 0.1 + 0.2
0.30000000000000004
应用场景
浮点数广泛应用于科学计算、图形处理、人工智能等几乎所有需要处理非整数的领域。
浮点数与定点数的对比
| 特性 | 浮点数 | 定点数 |
|---|---|---|
| 表示范围 | 极大 | 有限,由位宽决定 |
| 精度分布 | 相对精度均匀,绝对精度随数值增大而降低 | 绝对精度均匀(最小刻度固定) |
| 硬件复杂度 | 高(需要 FPU) | 低(可用整数 ALU) |
| 运算速度 | 相对较慢(尤其在没有 FPU 的系统中) | 极快 |
| 功耗/成本 | 高 | 低 |
| 确定性 | 受舍入模式影响,不同平台可能有微小差异 | 完全确定,与整数运算一致 |
| 典型应用 | 科学计算、图形学、AI、通用软件 | 嵌入式系统、DSP、金融(需要精确小数) |