浮点数

浮点数标准

IEEE标准754-1985定义了浮点数的存储格式、运算规则、舍入方式以及特殊值的处理(如无穷大、NaN等)。其核心思想是用科学计数法的形式来表示实数:

R=(1)s×M×2E=(1)s×(1+F)×2E\begin{aligned} R &= (-1)^s \times M \times 2^E \\ &= (-1)^s \times (1+F) \times 2^E \end{aligned}

其中:

  • s为符号位;
  • M为尾数,即有效数字部分,在1-2之间;
  • F为小数部分,在0-1之间;
  • E为指数,表示以 2 为底的幂次。

IEEE 754 定义了多种精度格式,最常用的是单精度浮点数与双精度浮点数:

  • 单精度浮点数 总共 32 位(4 字节)
    • 1 位符号位
    • 8 位指数(偏移量为 127)
    • 23 位尾数(实际精度为 24 位,因为有隐含的前导1)
  • 双精度浮点数 总共 64 位(8 字节)
    • 1 位符号位
    • 11 位指数(偏移量为 1023)
    • 52 位尾数(实际 53 位精度)

什么是“隐含首位 (implicit leading bit)”?

在标准化的浮点数表示中(非零数),尾数总是被表示成1.2345x2^{E},二进制中标准化保证了最高位总是1,因此这个1不用显式存储。这节省了 1 位空间,但这位仍然参与计算,因此尾数的实际精度比存储多 1 位。

此外,IEEE 754 还定义了许多特殊情况:

情况 指数部分 尾数部分 含义
正常数 非全0非全1 任意 正规浮点数
全为0 全为0 +0 或 -0(符号位决定)
非规约数(Denormal/Subnormal) 非全0 表示非常接近0的数,扩展下溢范围
无穷大(Infinity) 全为1 全为0 如 1.0/0.0 → +∞
NaN(Not a Number) 非全0 非法操作结果,如 0/0、√(-1)

相对精度

在浮点数表示中,相对精度是近似恒定的(在同一个指数区间内),这是浮点数优于定点数的关键之一。恒定的相对精度让浮点数系统在数值计算中具有 “比例一致性” :乘法、除法、指数放缩不会影响数值的精度层次,在算法分析时,也可以假设“每一步计算误差 ≈ ε × 结果”。

FN=23×log10223×0.36DN=52×log10252×0.316\begin{aligned} F_N &= 23 \times \log_{10}2 \approx 23 \times 0.3 \approx 6 \\ D_N &= 52 \times \log_{10}2 \approx 52 \times 0.3 \approx 16 \end{aligned}

浮点加法

计算分四步走:

  1. 对齐数字:按较小的指数移动数字
  2. 整数及尾数相加
  3. 规格化结果并检查是否上溢或下溢
  4. 若有必要,进位并再次规格化

首先考虑4位的十进制:9.999 × 101 + 1.610 × 10–1 = ?

1
2
3
4
5
   9.999  × 10^1 + 1.610 × 10^–1
= 9.999 × 10^1 + 0.016 × 10^1 // 对齐
= 10.015 × 10^1 // 整数与尾数相加
= 1.0015 × 10^2 // 规格化结果
= 1.002 × 10^2 // 进位并再次规格化

随后考虑4位的二进制:1.0002 × 2–1 + –1.1102 × 2–2 (0.5 + –0.4375) = ?

1
2
3
4
5
  1.000(2) × 2^{–1} + –1.110(2) × 2^{–2} (0.5 + –0.4375)
= 1.000(2) × 2^{–1} + –0.111(2) × 2^{–1} // 对齐
= 0.001(2) × 2^{–1} // 整数与尾数相加
= 1.000(2) × 2^{-4} // 规格化,未溢出
= 1.000(2) × 2^{-4} = 0.0625 // 无需进位与规格化

硬件实现

显然,与整数加法器相比,浮点加法器的硬件结构要复杂得多。考虑到其复杂性,在一个时钟周期内完成会花费太长时间,因此通常设计为需要几个周期才能完成计算。常用流水线来实现。

浮点加法器硬件结构图

浮点乘法

与加法相比,浮点数乘法计算分五步走:

  1. 把指数相加
  2. 整数及尾数相乘
  3. 规格化结果并检查是否上溢或下溢
  4. 若有必要,进位并再次规格化
  5. 确定符号位

首先考虑4位的十进制:1.110 × 1010 × 9.200 × 10–5 = ?

1
2
3
4
5
6
   1.110  × 10^10 × 9.200 × 10^–5
= 1.110 × 9.200 × 10^(10 - 5) // 指数相加
= 10.212 × 10^5 // 整数与尾数相乘
= 1.0212 × 10^6 // 规格化结果
= 1.021 × 10^6 // 进位并再次规格化
= +1.021 × 10^6 // 确定符号位

随后考虑4位的二进制:1.0002 × 2–1 × –1.1102 × 2–2 (0.5 × –0.4375) = ?

1
2
3
4
5
6
7
8
9
10
    1.000(2) × 2^{–1} × –1.110(2) × 2^{–2} (0.5 × –0.4375)
Unbiased: –1 + –2 = –3 // 把指数相加
Biased: (–1 + 127) + (–2 + 127)
= –3 + 254127
= –3 + 127
= 1.000(2) × 1.110(2) // 整数与尾数相乘
= 1.1102(2) × 2^{-3}
= 1.110(2) × 2^{–3} // 规格化,未溢出
= 1.110(2) × 2^{–3} // 无需进位与规格化
= -1.110(2) × 2^{–3} = –0.21875 // 确定符号位

有限状态机

数字系统设计复习笔记:第八篇

时序

给我干哪来了,这还是VLSI设计吗

数字CMOS集成电路复习笔记:第五篇 简单的时序分析例子

同步与异步

  • 如果所有的状态转换被限制在精确的时间点上周期性地发生,这些时间点由一个被称为时钟的特殊信号决定,那么这个(子)电路被称为同步运行
  • 当一个(子)电路中的部分或全部存储元素被允许独立于全局而改变它们的状态时,该电路就被称作异步运行

设计原则

同步时序设计的第一个指导原则:

  • 异步复位信号(何时进入启动状态)
  • 时钟信号(何时从一个状态进入下一个状态)
  • 信息信号(进入什么状态,产生什么输出)

这三类的信号不能混合处理。

二进制组合逻辑操作(即除反相器和缓冲器以外的逻辑门)需要被严格限制在信息信号中。此外,时钟和非同步复位由扇出树专门分配。

同步时序设计的第二个指导原则:

使时钟周期足够长,以便在下一个有效的时钟边沿指示寄存器(和其他存储设备)接受新的数据之前,所有的瞬态效应都已经消失了!

错误示例

该电路把与门直连到时钟线上去,可能门控信号会产生毛刺

功率和能耗

数字CMOS集成电路复习笔记:第三篇

活动因子

活动因子指的是电路中信号实际翻转的概率,就是翻转概率。对于完全随机的数据,P为0.5。

Pi=1Piai=PiPi\overline{P_i} = 1-P_i \\ a_i = \overline{P_i} * P_i

通过ANDs和ORs传播的数据具有较低的活动系数,根据设计而变化。通常可以估算为a约为0.1。

逻辑门的开关概率

电源门控

当块处于空闲状态时,关闭其电源以节省漏电。可以使用虚拟VDD(VDDV),使用输出隔离门防止无效的逻辑电平进入下一个块。

减少算法和架构层面的活动

在所有的设计层面上搜索不相关的开关活动并将其削减:

  • 大限度地减少整体计算工作。
  • 放宽计算精度、音频/图片/视频质量、编码增益、响应时间等要求,以换取更好的能效。
  • 限制灵活性以换取更好的能效。
  • 删减或简化控制流和操作模式。
  • 仔细优化所有字宽和存储容量。
  • 最大化保持本地的数据交换,避免片外和片间通信。
  • 避免空闲等待和轮询循环。
  • 远离具有内存刷新周期的DRAM。

性能

相对性能与CPI

引入相对性能:若A的CPU时间为B的x倍,则B相对A快x倍。

CPI=CPU Clock CyclesInstruction CountCPU Time=CPU Clock Cycles×Clock Cycle Time=Instruction Count×CPI×Clock Cycle Time=Instruction Count×CPIClock Rate\begin{aligned} \text{CPI} &= \frac{\mathrm{CPU\ Clock\ Cycles}}{\mathrm{Instruction\ Count}}\\ \\ \mathrm{CPU\ Time}&= \mathrm{CPU\ Clock\ Cycles}&\times\mathrm{Clock\ Cycle\ Time}\\ &= \mathrm{Instruction\ Count}\times \mathrm{CPI}&\times \mathrm{Clock\ Cycle\ Time}\\ &= \frac{\mathrm{Instruction\ Count}\times \mathrm{CPI}}{\mathrm{Clock\ Rate}} \end{aligned}

注意Clock Cycle Time=1Clock Rate\mathrm{Clock\ Cycle\ Time} = \dfrac{1}{\mathrm{Clock\ Rate}}

性能也有上限:阿姆达尔定律

Timproved=Taffectedimprovement factor+Tunaffected\mathrm{T_{improved}}=\frac{\mathrm{T_{affected}}}{\text{improvement factor}}+\mathrm{T_{unaffected}}

举个例子:乘法运算占据总运算100s中的80s,能否改进乘法模块,以至于把整个运算速度提高5倍?

20=80n+2020=\frac{80}{n}+20

显然是无解的。

低功耗谬论:Low Power at Idle

让系统在空闲时更省电并不等于整体能耗更低,节能的真正关键是完成工作所需的总能量(Energy to Complete a Task, ETC),而不是空闲时的功耗。因此,应当让CPU尽可能快地完成任务然后睡晕过去。

指标陷阱:MIPS as a Performance Metric

为什么不能将MIPS(Million Instructions Per Second,每秒百万条指令)作为衡量计算机性能的标准?

MIPS(Million Instructions Per Second) 表示每秒执行的指令数量,计算公式为:

MIPS=Instruction CountExecution Time×106=Clock RateCPI×106\text{MIPS} = \frac{\text{Instruction Count}}{\text{Execution Time} \times 10^6} = \frac{\text{Clock Rate}}{\text{CPI} \times 10^6}

因此,程序性能取决于 “指令数 × CPI”,MIPS 只与 CPI 有关,不反映程序实际工作量。同时,在一个CPU上,不同的程序的CPI是不同的。

举个例子:

  • 机器 A:CPI = 1,频率 = 1GHz → 1000 MIPS;
  • 机器 B:CPI = 2,频率 = 2GHz → 1000 MIPS;
  • 但机器 B 每条指令的执行时间更长(总时间也可能更慢)。

再举一个例子:

  • 程序 X(优化版)执行 1000 条复杂指令完成任务;
  • 程序 Y(低效版)执行 2000 条简单指令完成相同任务。
  • 假设两台机器均为 1GHz,且CPI 相同,则程序 Y 的 MIPS 值更高。
  • 但实际上,X 执行更快,性能更好