HNU2026-计算机系统-笔记 7 浮点数

7 浮点数

浮点运算是衡量超算性能的主要指标。浮点数本质上就是科学计数法形式的二进制实数。

01 二进制小数

小数与科学计数法

小数由整数部分与小数部分组成,可以用位权公式表达:

718.415=7×102+1×101+8×100+4×10−1+1×10−2+5×10−3718.415 = 7 \times 10^2 + 1 \times 10^1 + 8 \times 10^0 + 4 \times 10^{-1} + 1 \times 10^{-2} + 5 \times 10^{-3}718.415=7×102+1×101+8×100+4×10−1+1×10−2+5×10−3

科学计数法将一个数表示为 a×10na \times 10^na×10n 的形式,其中 1≤∣a∣<101 \leq |a| < 101≤∣a∣<10,nnn 为整数。

二进制小数的表示

二进制小数点右侧的每一位表示 2 的负幂:

∑k=−jibk×2k\sum_{k=-j}^{i} b_k \times 2^kk=−j∑ibk×2k

位置 权值
b−1b_{-1}b−1(小数点右第 1 位) 2−1=1/22^{-1} = 1/22−1=1/2
b−2b_{-2}b−2(小数点右第 2 位) 2−2=1/42^{-2} = 1/42−2=1/4
b−3b_{-3}b−3(小数点右第 3 位) 2−3=1/82^{-3} = 1/82−3=1/8
b−jb_{-j}b−j(小数点右第 jjj 位) 2−j2^{-j}2−j

示例 :1011.1012=8+2+1+0.5+0.125=11.6251011.101_2 = 8 + 2 + 1 + 0.5 + 0.125 = 11.6251011.1012=8+2+1+0.5+0.125=11.625

快速转换窍门 :小数部分写成分数,分母为 2k2^k2k(kkk 为小数位数),分子为小数部分二进制的值。例如 .1012=5/8=0.625.101_2 = 5/8 = 0.625.1012=5/8=0.625

二进制小数举例

十进制 二进制
5 3/4 101.112101.11_2101.112
2 7/8 10.111210.111_210.1112
1 13/16 1.110121.1101_21.11012

规律

  • 小数点右移一位 = 乘 2;左移一位 = 除 2
  • 0.111111...20.111111\ldots_20.111111...2 表示刚好小于 1.0 的数(即 1.0−ε1.0 - \varepsilon1.0−ε)

二进制小数的表示限制

二进制小数只能精确表示形如 x/2kx / 2^kx/2k 的数,其他值只能近似表示:

十进制值 二进制表示
1/3 0.0101010101[01]...20.0101010101[01]\ldots_20.0101010101[01]...2(无限循环)
1/5 0.001100110011[0011]...20.001100110011[0011]\ldots_20.001100110011[0011]...2
1/10 0.0001100110011[0011]...20.0001100110011[0011]\ldots_20.0001100110011[0011]...2

这就是为什么在计算机中 0.1 + 0.2 ≠ 0.3------十进制的 0.1 在二进制中是无限循环小数,存储时必然被截断。

02 IEEE 浮点数标准

IEEE 754 标准

IEEE 754 标准于 1985 年建立(之前每个计算机制造商使用自己的浮点规则),现在被所有主流 CPU 支持。该标准面向数字运算的精确性,支持舍入、溢出等操作,定义在一组小而一致的规则上。

浮点数的数学形式

V=(−1)s×M×2EV = (-1)^s \times M \times 2^EV=(−1)s×M×2E

  • 符号位 s (Sign):决定正数还是负数,数值 0 的符号位特殊处理
  • 尾数 M (Significand) :一个二进制小数,通常在 [1.0,2.0)[1.0, 2.0)[1.0,2.0) 范围内
  • 阶码 E (Exponent):表示 2 的幂

在二进制编码中,浮点数分为三个字段:

字段 含义
s(1 位) 符号位
exp(若干位) 阶码字段
frac(若干位) 尾数字段

浮点数类型

精度 总位数 符号 阶码 (exp) 尾数 (frac)
单精度 (float) 32 bits 1 8 bits 23 bits
双精度 (double) 64 bits 1 11 bits 52 bits
扩展精度 (Intel only) 80 bits 1 15 bits 63 或 64 bits

三种表示类别

根据阶码字段 exp 的取值,浮点数分为三种类别:

复制代码
阶码 exp
├── 全 0(000...0)       → 非规格化数
├── 非全 0 且非全 1       → 规格化数
└── 全 1(111...1)       → 特殊值
    ├── frac = 000...0   → ±∞
    └── frac ≠ 000...0   → NaN
类别 1:规格化值(Normalized)

判断条件:exp 不为全 0 且不为全 1

  • 阶码 :采用偏置(biased)表示
    • E=Exp−BiasE = Exp - BiasE=Exp−Bias
    • ExpExpExp 是 exp 字段的无符号值
    • Bias=2k−1−1Bias = 2^{k-1} - 1Bias=2k−1−1,其中 kkk 为阶码位数(单精度 Bias = 127,双精度 Bias = 1023)
  • 尾数 :M=(1.xxx...x)2M = (1.xxx\ldots x)_2M=(1.xxx...x)2
    • 整数部分隐含为 1(不需要存储),frac 字段存储小数部分
    • 最小值:frac 全 0 时 M=1.0M = 1.0M=1.0
    • 最大值:frac 全 1 时 M=2.0−εM = 2.0 - \varepsilonM=2.0−ε

规格化值示例:float F = 15213.0

  1. 1521310=111011011011012=1.11011011011012×21315213_{10} = 11101101101101_2 = 1.1101101101101_2 \times 2^{13}1521310=111011011011012=1.11011011011012×213
  2. 尾数:M=1.11011011011012M = 1.1101101101101_2M=1.11011011011012,frac = 11011011011010000000000
  3. 阶码:E=13E = 13E=13,Exp=E+Bias=13+127=140=100011002Exp = E + Bias = 13 + 127 = 140 = 10001100_2Exp=E+Bias=13+127=140=100011002
  4. 最终编码:0 | 10001100 | 11011011011010000000000
类别 2:非规格化值(Denormalized)

判断条件:exp = 000...0(阶码全 0)

  • 阶码 :E=1−BiasE = 1 - BiasE=1−Bias(注意不是 0−Bias0 - Bias0−Bias,这是为了让非规格化值与规格化值之间平滑过渡)
  • 尾数 :M=(0.xxx...x)2M = (0.xxx\ldots x)_2M=(0.xxx...x)2(隐含整数部分为 0,而不是 1)

两种特殊情况:

  • exp = 0, frac = 0:表示 0(符号位决定 +0 或 -0)
  • exp = 0, frac ≠ 0:表示非常接近 0.0 的数
类别 3:特殊值

判断条件:exp = 111...1(阶码全 1)

  • 情况 1 :exp 全 1,frac = 0 → 表示无穷大 (+∞+\infty+∞ 或 −∞-\infty−∞),可用来表示溢出结果,如 1.0/+0.0=+∞1.0 / +0.0 = +\infty1.0/+0.0=+∞,1.0/−0.0=−∞1.0 / -0.0 = -\infty1.0/−0.0=−∞
  • 情况 2 :exp 全 1,frac ≠ 0 → 表示 NaN (Not a Number),用来表示无法定义的运算结果,如 −1\sqrt{-1}−1 、∞−∞\infty - \infty∞−∞、∞×0\infty \times 0∞×0

03 示例与性质

8 位浮点数完整示例

以一个 8 位微型浮点格式为例:1 位符号 + 4 位阶码 + 3 位尾数,Bias = 23−1=72^3 - 1 = 723−1=7。

非规格化数 (exp = 0000,E=1−7=−6E = 1 - 7 = -6E=1−7=−6):

编码 E M 说明
0 0000 000 -6 0/8 0
0 0000 001 -6 1/8 1/512 最小非规格化正数
0 0000 010 -6 2/8 2/512
...
0 0000 111 -6 7/8 7/512 最大非规格化数

规格化数(exp 非全 0 非全 1):

编码 E M 说明
0 0001 000 -6 8/8 8/512 最小规格化数
0 0001 001 -6 9/8 9/512
...
0 0110 110 -1 14/8 14/16
0 0110 111 -1 15/8 15/16 从下最靠近 1
0 0111 000 0 8/8 1
0 0111 001 0 9/8 9/8 从上最靠近 1
...
0 1110 111 7 15/8 240 最大规格化数
0 1111 000 --- --- +∞+\infty+∞ 正无穷

注意最大非规格化数(7/512)到最小规格化数(8/512)之间的平滑过渡 ------这正是非规格化数使用 E=1−BiasE = 1 - BiasE=1−Bias 而非 0−Bias0 - Bias0−Bias 的设计目的。

浮点数取值分布特征

  • 浮点数在数轴上的分布是不均匀的:越靠近 0,可表示的数越密集;越远离 0,间距越大
  • 非规格化数(Denormalized)集中在 0 附近,规格化数(Normalized)覆盖更大范围

浮点数属性(单精度 / 双精度)

描述 单精度 (float) 双精度 (double)
最小非规格化正数 ≈1.4×10−45\approx 1.4 \times 10^{-45}≈1.4×10−45 ≈4.9×10−324\approx 4.9 \times 10^{-324}≈4.9×10−324
最大非规格化正数 ≈1.18×10−38\approx 1.18 \times 10^{-38}≈1.18×10−38 ≈2.2×10−308\approx 2.2 \times 10^{-308}≈2.2×10−308
最小规格化正数 ≈1.18×10−38\approx 1.18 \times 10^{-38}≈1.18×10−38 ≈2.2×10−308\approx 2.2 \times 10^{-308}≈2.2×10−308
1 1.01.01.0 1.01.01.0
最大规格化正数 ≈3.4×1038\approx 3.4 \times 10^{38}≈3.4×1038 ≈1.8×10308\approx 1.8 \times 10^{308}≈1.8×10308

04 舍入与运算

浮点运算的基本思路

浮点加法和乘法的基本策略是:

  1. 先按精确数学运算计算出精确结果
  2. 再通过 " 舍入 " 将结果拟合到浮点格式能表示的最近值

x+fy=Round(x+y)x +_f y = Round(x + y)x+fy=Round(x+y)
x×fy=Round(x×y)x \times_f y = Round(x \times y)x×fy=Round(x×y)

浮点运算溢出

由于浮点数使用有限位数的二进制(单精度 32 位,双精度 64 位),运算时也会出现溢出。Ariane 5 火箭事故(1996 年)就是因为软件工程师没有考虑浮点数溢出问题,导致火箭发射后仅 37 秒解体爆炸,价值 5 亿美元的通信卫星付之一炬。

四种舍入方式

舍入方式 $1.40 $1.60 $1.50 $2.50 -$1.50
向零舍入 (Towards zero) $1 $1 $1 $2 -$1
向下舍入 (Round down, −∞-\infty−∞) $1 $1 $1 $2 -$2
向上舍入 (Round up, +∞+\infty+∞) $2 $2 $2 $3 -$1
向偶数舍入 (Nearest Even)(默认) $1 $2 $2 $2 -$2

向偶数舍入能找到最接近的匹配值,且在中间值时不会产生统计偏差(其他三种用于计算上界和下界)。

向偶数舍入(Round to Nearest Even)

这是 IEEE 754 的默认舍入方案。规则是:中间值(恰好在两个可表示值正中间)应当向偶数方向舍入。

十进制示例(舍入到百分位):

  • 1.2349999 → 1.23(不到中间值,向下)
  • 1.2350001 → 1.24(超过中间值,向上)
  • 1.2350000 → 1.24(中间值,4 是偶数,向上凑偶)
  • 1.2450000 → 1.24(中间值,4 是偶数,向下凑偶)

二进制舍入

在二进制中:

  • " 偶数 " 是指末位为 0
  • " 中间值 " 是指舍入位右边恰好是 100...02100\ldots 0_2100...02 的形式

示例(舍入到小数点右边两位,即精度为 1/4):

原值 二进制 舍入后 结果 操作
2 3/32 10.00011210.00011_210.000112 10.00210.00_210.002 2 不到中间值,向下
2 3/16 10.00110210.00110_210.001102 10.01210.01_210.012 2 1/4 超过中间值,向上
2 7/8 10.11100210.11100_210.111002 11.00211.00_211.002 3 中间值,向上凑偶
2 5/8 10.10100210.10100_210.101002 10.10210.10_210.102 2 1/2 中间值,向下凑偶

浮点数乘法

(−1)s1M1⋅2E1×(−1)s2M2⋅2E2=(−1)sM⋅2E(-1)^{s_1} M_1 \cdot 2^{E_1} \times (-1)^{s_2} M_2 \cdot 2^{E_2} = (-1)^s M \cdot 2^E(−1)s1M1⋅2E1×(−1)s2M2⋅2E2=(−1)sM⋅2E

精确结果:

  • 符号位:s=s1⊕s2s = s_1 \oplus s_2s=s1⊕s2(异或)
  • 尾数:M=M1×M2M = M_1 \times M_2M=M1×M2
  • 阶码:E=E1+E2E = E_1 + E_2E=E1+E2

调整步骤:

  • 如果 M≥2M \geq 2M≥2,将 MMM 右移一位,E=E+1E = E + 1E=E+1
  • 如果 EEE 超出可表示范围,则溢出
  • 将 MMM 舍入到 frac 的位数范围

浮点数加法

加法的四个步骤:

  1. 对阶 :小阶向大阶对齐------将阶码小的那个数的尾数右移 ∣ΔE∣|\Delta E|∣ΔE∣ 位,同时阶码加上 ∣ΔE∣|\Delta E|∣ΔE∣(值不变但精度变差)
  2. 尾数相加:对两个对阶后的浮点数执行尾数加法
  3. 规格化并舍入 :如果结果尾数不是规格化形式(1.xxx1.xxx1.xxx),需要调整并舍入
  4. 判断溢出:根据阶码判断是否超出可表示范围

浮点加法的数学特性

与阿贝尔群比较:

  • 有交换性 :a+b=b+aa + b = b + aa+b=b+a
  • 没有结合性 (由于舍入):(3.14+1e10)−1e10=0(3.14 + 1\text{e}10) - 1\text{e}10 = 0(3.14+1e10)−1e10=0,而 3.14+(1e10−1e10)=3.143.14 + (1\text{e}10 - 1\text{e}10) = 3.143.14+(1e10−1e10)=3.14
  • 单调性 :a≥b⇒a+c≥b+ca \geq b \Rightarrow a + c \geq b + ca≥b⇒a+c≥b+c(除了涉及 infinities 和 NaN 的情况)

浮点乘法的数学特性

  • 可交换 :a×b=b×aa \times b = b \times aa×b=b×a
  • 不可结合 :a×b×c≠a×(b×c)a \times b \times c \neq a \times (b \times c)a×b×c=a×(b×c)
  • 不具备分配性 :a×(b+c)≠a×b+a×ca \times (b + c) \neq a \times b + a \times ca×(b+c)=a×b+a×c
  • 单调性 :a≥ba \geq ba≥b 且 c≥0⇒a×c≥b×cc \geq 0 \Rightarrow a \times c \geq b \times cc≥0⇒a×c≥b×c(除了 infinities 和 NaN)

05 C 语言中的浮点数

两种浮点类型

类型 精度 位数
float 单精度 32 bits
double 双精度 64 bits

类型转换规则

在 int、float、double 之间转换时,位级表示会改变:

转换方向 行为
double/float → int 向零舍入;对于无法表示或超出范围的值,行为未定义
int → double 能够保留精确值(因为 double 有 52 位尾数,足以表示 32 位 int)
int → float 数字不会溢出,但可能被舍入(float 只有 23 位尾数,不足以精确表示所有 32 位 int)

浮点数谜题

给定 int x; float f; double d;(假设 d 和 f 都不是 NaN),判断以下表达式是否总为真:

表达式 结论 原因
x == (int)(float)x 不一定 float 只有 23 位尾数,大 int 值转 float 会丢失精度
x == (int)(double)x 总为真 double 有 52 位尾数,能精确表示任何 32 位 int
f == (float)(double)f 总为真 double 精度高于 float,不会丢失信息
d == (float)d 不一定 double 转 float 会丢失精度
f == -(-f) 总为真 取负只翻转符号位,两次翻转恢复原值
2/3 == 2/3.0 不成立 左边是整数除法结果 0,右边是浮点除法结果 0.666...
d * d >= 0.0 总为真 平方结果非负(即使溢出到 +∞+\infty+∞ 也 ≥0\geq 0≥0)
(d+f)-d == f 不一定 浮点加法没有结合性,舍入可能导致精度丢失

本节小结

  1. 二进制小数 :小数点右侧每一位代表 2−1,2−2,...2^{-1}, 2^{-2}, \ldots2−1,2−2,...;只能精确表示 x/2kx/2^kx/2k 形式的数,1/3、1/5、1/10 等在二进制中都是无限循环。
  2. IEEE 754 标准 :浮点数 = (−1)s×M×2E(-1)^s \times M \times 2^E(−1)s×M×2E,由符号位、阶码、尾数三个字段编码。单精度 32 位(1+8+23),双精度 64 位(1+11+52)。
  3. 三种类别 :规格化值(阶码非全 0 非全 1,隐含前导 1)、非规格化值(阶码全 0,隐含前导 0,用于表示极小值和 0)、特殊值(阶码全 1,表示 ±∞\pm\infty±∞ 或 NaN)。
  4. 舍入:默认向偶数舍入(Round to Nearest Even),中间值向偶数方向凑,避免统计偏差。
  5. 浮点运算特性 :加法和乘法都满足交换律,但不满足结合律和分配律------这是舍入导致的根本性质,编程时必须注意运算顺序。
  6. C 语言转换:int → double 精确;int → float 可能舍入;float/double → int 向零截断且可能溢出。
相关推荐
九思十安1 小时前
HNU2026-计算机系统-笔记 4 汇编初步
汇编·笔记
FakeEnd1 小时前
Unity开发笔记6
笔记·unity·游戏引擎
Hello_Embed2 小时前
libmodbus 源码分析
笔记·stm32·单片机·嵌入式·ai编程
05候补工程师2 小时前
【408考研】数据结构核心笔记:单链表与栈操作精髓总结
数据结构·笔记·考研·链表·c#
kdxiaojie2 小时前
U-Boot分析【学习笔记】(7)
linux·笔记·学习
Huanzhi_Lin2 小时前
skynet笔记
笔记·lua·skynet·actor·actor模型
爱看大明王朝156610 小时前
磁件学习-磁性元器件的极限计算
笔记·学习
问心无愧051310 小时前
ctf show web入门 40
笔记
@蓝莓果粒茶12 小时前
【Unity笔记】保姆级AssetBundle详解(含代码+避坑指南)
笔记·游戏·unity