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.010101010101...20.010101010101\ldots_20.010101010101...2(无限循环)
1/5 0.0011001100110011...20.0011001100110011\ldots_20.0011001100110011...2
1/10 0.00011001100110011...20.00011001100110011\ldots_20.00011001100110011...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 向零截断且可能溢出。
相关推荐
Li_RuiQi12 小时前
DAgger方法演进_独立学习笔记
笔记·学习·计算机视觉
Li_RuiQi16 小时前
DAgger与交互式模仿学习_ACT学习笔记
笔记·学习
He BianGu17 小时前
【笔记】C# 中BindingFlags的详细作用
笔记·c#
AI视觉网奇17 小时前
turtle 入门教程笔记
笔记
跨知易知识产权17 小时前
美国专利确权是什么,和专利诉讼有什么不一样?
笔记
杨逢昌工厂6S管理17 小时前
126-杨逢昌6S三环体系:越做越乱的现场熵增机理与基准化治理——一线现场诊断笔记
经验分享·笔记·职场和发展·学习方法
悟道书生17 小时前
若依 RBAC 权限控制学习笔记
java·网络·笔记·sql·学习·vue
陈哈哈111118 小时前
折腾了半天,总算把 Vim 9.2 装明白了
笔记
陈哈哈111118 小时前
折腾了半天,总算把 OpenGL 的开发环境给装明白了
笔记
深圳老胡19 小时前
STM32F103 硬件 SPI 与软件 IO 模拟 SPI 最高速度差异详解
笔记·stm32·单片机·代码规范·1024程序员节