扩展和移位
682 字
3 分钟
扩展和移位
扩展和移位
符号扩展
当把短位宽的带符号数存入长位宽寄存器时,需要对多出的位进行填充。符号扩展的对象是带符号数。
正数的扩展
符号位不变(= 0),所有扩展位用 0 填充。
- 整数向左扩展填 0
- 小数向右扩展填 0
例:8 位 +5(00000101)→ 16 位 00000000 00000101
负数的扩展
取决于该负数用的是何种编码:
原码表示
| 方向 | 规则 |
|---|---|
| 整数 | 在符号位和数值位之间填充 0 |
| 小数 | 在数值位之后填充 0 |
例:8 位原码 -5 = 10000101 → 16 位 = 10000000 00000101
补码表示
| 方向 | 规则 |
|---|---|
| 整数 | 向左扩展,填充符号位(即 1) |
| 小数 | 向右扩展,填充 0 |
例:8 位补码 -5 = 11111011 → 16 位 = 11111111 11111011
补码整数扩展时填符号位(而非 0)是保证数值不变的关键。填 0 的话
11111011会变成00000000 11111011= 251,而不是 −5。
溢出判断(乘法)
两个 int(32 位)相乘得到 64 位乘积,但寄存器只能保留低 32 位。如何判断溢出?
64位乘积:1111 1111 1111 1111 1111 │ 1111 1111 ... 0010 0000 1111 0111 ←────── 高 32 位 ────────→│←─────── 低 32 位 ───────────────→ │ 红色虚线:32位寄存器截断位置判断规则:查看高 32 位是否全是 0(正数)或全是 1(负数补码)。如果不是,说明低 32 位表示不了完整的 64 位结果 → 溢出。
移位操作
左移
:x 向左移动 k 位,右端补 k 个 0。每左移一位相当于乘以 2。
右移
:x 向右移动 k 位。分为两种:
| 类型 | 左端填充 | 适用场景 |
|---|---|---|
| 逻辑右移 | 补 k 个 0 | 无符号数 |
| 算术右移 | 补 k 个最高位的值(符号位) | 带符号数 |
算术右移示例
(补码表示 −4),算术右移 2 位:
1100 ──算术>>2──→ 1111
补码: -4 补码: -1 (除以 4)算术右移 2 位 = 除以 : ✓
算术右移保持了符号,逻辑右移不保持。
补码加减运算电路
一个电路同时实现加法和减法,关键是利用补码的性质:。
┌────────────┐ Sub ─┤ Cin │ │ │ X ──────────────────┤ │──────→ F (结果) │ 加法器 │ ┌──┐ ┌───────┤ ├──→ Cout Y ────┤~ ├──┤ 1 │ │──→ OF └──┘ │ MUX │ │──→ SF │ │ │──→ ZF Y ───┤ 0 │ │──→ CF └──┬────┘ │ │ ┌───────────┘ Y'| Sub(控制信号) | MUX 输出 | Cin | 实际运算 |
|---|---|---|---|
| 0 | (选通 0 端) | 0 | (加法) |
| 1 | (选通 1 端) | 1 | (减法) |
::: tip Sub == Cin 减法时 Sub=1,同时把 Cin 也置为 1,从而完成 的转换。 :::



