第 3 章 计算机算术 (Arithmetic for Computers)
核心结论
-
整数加减法:二进制加法器串行进位;溢出靠符号位进位与最高位进位的异或检测。
-
整数乘法:移位-加法器(Shift-and-Add);LEGv8
MUL/MULH(高低位分开)。 -
整数除法:恢复余数 / 非恢复余数除法器;LEGv8
SDIV/UDIV。 -
IEEE 754 浮点:符号 + 指数 + 尾数;规格化数 / 非规格化数 / NaN / 无穷;舍入模式(最近偶数 / 朝 0 / 朝 +∞ / 朝 -∞)。
-
SIMD 与并行:一条指令处理多个数据(ARM NEON / SSE / AVX);提升 4-16 倍吞吐。
-
子字并行:把 32-bit 寄存器拆为 4 个 8-bit / 2 个 16-bit 同时运算;GPU / ML 常用。
|
本章主旨
本章聚焦"ALU 怎么做算术"——整数加减乘除、IEEE 754 浮点、SIMD / 子字并行。这些是 CPU 微架构的核心电路,与第 4 章的 CPU 设计直接挂钩。理解算术电路有助于理解延迟 / 吞吐量 / 优化的硬件根源。 |
一、核心概念
本章围绕 6 个核心概念展开:从整数加法出发,介绍乘法 / 除法的移位-加法实现,再深入 IEEE 754 浮点,最后给 SIMD 与子字并行。
| 概念 | 定义 + 重要性 | 实现提示 |
|---|---|---|
整数加减法 |
二进制加法器串行进位;溢出靠符号位与最高位的进位异或检测。 |
§3.2;超前进位加速但复杂;现代 ALU 用超前进位 + 串行进位混合。 |
整数乘法 |
移位-加法(Shift-and-Add);LEGv8 |
§3.3;64-bit × 64-bit 结果 128-bit,分两次取;迭代次数 = 操作数位数。 |
整数除法 |
恢复 / 非恢复余数除法;LEGv8 |
§3.4;除法比乘法慢(迭代 + 比较 + 减法);编译器优化:常量除法转乘法 + 移位。 |
IEEE 754 浮点 |
符号 (1) + 指数 (8/11) + 尾数 (23/52);规格化 / 非规格化 / NaN / 无穷;4 种舍入。 |
§3.5;高精度计算的基础;浮点不精确( |
SIMD 与并行 |
一条指令处理多个数据;ARM NEON、x86 SSE / AVX;4-16 倍吞吐。 |
§3.6-§3.7;GPU / 矩阵运算 / 图像处理的标准优化。 |
子字并行 (subword parallelism) |
把宽寄存器拆为多个窄数据并行运算;ML / 图像 / 加密常用。 |
§3.9;ARM SVE / AVX-512 把 SIMD 推到极致。 |
二、详细笔记
2.1 整数加减法 (Integer Add/Subtract)
What:二进制加法器串行进位;溢出靠符号位进位与最高位进位的异或检测。
Why:加法是 ALU 最基本操作;溢出检测是安全编程的核心。
How:
二进制加法:
其中 c_i 是进位,c₀ = 0。
溢出检测(§3.2):
两个正数相加得负数、或两个负数相加得正数 = 溢出。
|
进位加速
|
When:写汇编 / C 时理解溢出行为;debug 算术 bug;选 int vs long long。
Example:INT_MAX + 1 在 C 中是 未定义行为;现代编译器不会自动 wrap-around。
2.2 整数乘法 (Integer Multiplication)
What:移位-加法(Shift-and-Add);64-bit × 64-bit = 128-bit,结果分高 / 低位。
Why:乘法是科学计算 / 图形 / ML 的核心;MUL/MULH 指令支持全精度乘法。
How:
移位-加法(§3.3):
迭代 n 次(n = 64),每次判断 b_i 并选择加 a·2^i。
LEGv8:
-
MUL X1, X2, X3:低 64-bit 结果。 -
MULH X1, X2, X3:高 64-bit 结果(用于 128-bit 乘法)。
|
乘法加速
|
When:高性能计算;编译器优化(常量乘法转移位-加法);ML / 图形矩阵乘法。
Example:X1 * X2 用 MUL 取低 64 位;X1 * X2 完整结果 = (MULH << 64) | MUL。
2.3 整数除法 (Integer Division)
What:恢复余数 / 非恢复余数除法;迭代次数 = 操作数位数。
Why:除法是科学计算常用;现代 CPU 几十个周期出结果。
How:
恢复余数除法(§3.4):迭代 n 次,每次左移余数并比较除数;若余数 < 除数恢复,否则商位 = 1。
非恢复余数除法:迭代 n 次,根据上一步符号决定加 / 减除数;最后修正余数符号。
LEGv8:
-
SDIV X1, X2, X3:有符号除法。 -
UDIV X1, X2, X3:无符号除法。
|
除法优化
|
When:编译器优化(除法 → 乘法);硬件除法器设计;理解延迟。
Example:UDIV X1, X2, #5(除以 5 无符号)— 编译器转 MUL X1, X2, #0xCCCCCCCD; LSR X1, X1, #38。
2.4 IEEE 754 浮点 (IEEE 754 Floating Point)
What:符号 + 指数 + 尾数;规格化 / 非规格化 / NaN / 无穷;4 种舍入模式。
Why:浮点是科学计算 / 图形 / ML 的标准;IEEE 754 保证跨平台一致性。
How:
二进制表示(§3.5):
-
s:1 bit 符号。 -
exponent:8 bit (单精度) / 11 bit (双精度)。 -
fraction:23 bit (单精度) / 52 bit (双精度);规格化时隐含 1。 -
bias:127 (单) / 1023 (双)。
特殊值:
-
全 0 指数 + 全 0 尾数 = ±0。
-
全 1 指数 + 全 0 尾数 = ±∞。
-
全 1 指数 + 非 0 尾数 = NaN。
-
全 0 指数 + 非 0 尾数 = 非规格化数(指数 = -126 / -1022)。
|
IEEE 754 的"反直觉"特性
|
When:所有科学计算;图形 / 物理引擎;ML 训练;debug 数值 bug。
Example:double d = 0.1 + 0.2; 结果约 0.30000000000000004(不是 0.3)。
2.5 SIMD 与子字并行 (SIMD & Subword Parallelism)
What:一条指令处理多个数据;ARM NEON 128-bit / x86 AVX 256-bit。
Why:图像处理 / 矩阵运算 / ML 大量使用 SIMD;性能提升 4-16 倍。
How:
SIMD 模型(§3.7):
-
标量指令:1 条指令处理 1 个数据。
-
SIMD 指令:1 条指令处理 N 个数据(如 4 个 float / 8 个 int16)。
ARM NEON:
-
128-bit 寄存器
V0–V31。 -
一条指令同时处理 4 个 float / 8 个 int32 / 16 个 int16 / 32 个 int8。
子字并行(§3.9):把宽寄存器拆为多个窄数据并行运算(4×8bit / 2×16bit / …)。
|
SIMD 的工程优势
|
When:图形 / 物理 / ML / 加密 / 信号处理;编译器优化(向量化);手写 SIMD intrinsic。
Example:float a[4], b[4], c[4]; for (i=0; i<4; i++) c[i] = a[i] + b[i]; 可用 1 条 NEON 指令 VADD.F32 Q0, Q0, Q1。
三、关键图表
视觉图表
非可视化条目
|
非可视化条目(表 / 算法)
|
核心公式对照表
|
核心公式对照表
|
四、思维导图
mindmap
root((第 3 章 计算机算术))
整数加减
二进制加法器
进位链
溢出检测
整数乘法
移位加法
MUL与MULH
64次迭代
整数除法
恢复余数
SDIVUDIV
常量优化
浮点
IEEE754
符号指数尾数
舍入模式
SIMD
一指令多数据
NEONAVX
4到16倍
子字并行
宽拆窄
ML加密
SVEAVX512
五、重点与易错点
-
整数溢出是 C 未定义行为:编译器可优化掉溢出检查;用
__builtin_add_overflow或safe-int库。-
二进制补码的范围不对称:INT64_MIN = -2^63,其相反数 2^63 超出范围;比较时区分有符号 / 无符号。
-
IEEE 754 浮点不精确:
0.1 + 0.2 ≠ 0.3;比较用容差fabs(a-b) < epsilon。 -
NaN 不等于自己:检测用
isnan(x),而非x == x(虽然x != x也 work)。 -
除法比乘法慢:编译器把常量除法转乘法 + 移位;硬件除法器用 10-20 周期。
-
SIMD 是性能倍增器:图像 / 物理 / ML 大量使用;编译器
-O3 -ftree-vectorize自动向量化。 -
ARM NEON 128-bit / x86 AVX 256-bit:寄存器宽度决定并行度;新一代指令集扩展越来越大。
-
子字并行:把宽寄存器拆为窄数据;适合 ML / 加密等小数据并行场景。
-
跨章衔接:第 4 章 CPU 微架构实现本章算术电路;第 5 章内存层级加速浮点数组访问;第 6 章 SIMD + 多线程组合提升并行。
-