补码定点整数算术
本文最后更新于4 天前,其中的信息可能已经过时,如有错误请发送邮件到184874483@qq.com

答案先汇总如下:

题号答案
030101 0100,按选项选对应这一项
04D,C0H
05D,1100 1010
06C,CB8H
07C,74H, DDH
08C
09A
10C,r₁ × r₂
11B
12B,01
13C0 ⊕ C1 = 1,即二者一个有进位、一个无进位时溢出

下面逐题讲。

03 题:补码定点整数算术左移两位

题目是:

0101 0101 算术左移两位。

补码的算术左移,在位形操作上可以按“整体左移,低位补 0”处理。也就是:

0101 0101 左移 1 位 -> 1010 1010
1010 1010 左移 1 位 -> 0101 0100

所以寄存器中的结果位形是:

0101 0100

但这里要注意一个考研易错点:0101 0101 是正数,十进制为 85。左移两位本质上相当于乘以 4,应得到 340,而 8 位补码整数范围是:

-128 ~ +127

所以数学结果已经超出范围。也就是说,题目若只问“左移后的机器位形”,结果是 0101 0100;若问“是否溢出”,则发生溢出。

04 题:算术左移不会发生溢出的是哪一个

判断补码左移一位是否溢出,最快方法是看左移前最高两位是否相同。

对于 8 位补码:

若符号位和最高数值位相同,左移一位不溢出;
若符号位和最高数值位不同,左移一位溢出。

逐个看:

80H = 1000 0000,最高两位是 10,溢出
90H = 1001 0000,最高两位是 10,溢出
B0H = 1011 0000,最高两位是 10,溢出
C0H = 1100 0000,最高两位是 11,不溢出

所以答案是:

D. C0H

这类题不要先转十进制,直接看最高两位最快。

05 题:补码定点整数右移一位

题目是:

1001 0101 右移一位

补码算术右移的规则是:高位补符号位,低位移出。

原数最高位是 1,说明是负数,所以右移时左边补 1

1001 0101
右移一位
1100 1010

所以答案是:

D. 1100 1010

补码右移题的关键是:不是左边补 0,而是补符号位。

06 题:两个十六进制机器数相加

题目是:

7E5H + 4D3H

直接按十六进制加法算:

    7 E 5
+   4 D 3
-----------
    C B 8

具体过程:

5 + 3 = 8

E + D = 14 + 13 = 27
27 = 1B,所以本位写 B,向高位进 1

7 + 4 + 1 = C

所以结果是:

CB8H

答案是:

C

07 题:BAH 的算术左移和算术右移

题目给出机器数字长为 8 位,机器数 BAH 为补码。

先把 BAH 转成二进制:

B = 1011
A = 1010

BAH = 1011 1010

算术左移 1 位:整体左移,低位补 0:

1011 1010 左移 1 位 -> 0111 0100

0111 0100 转十六进制:

0111 = 7
0100 = 4

所以是 74H

算术右移 1 位:高位补符号位。原数符号位是 1,所以左边补 1

1011 1010 右移 1 位 -> 1101 1101

1101 1101 转十六进制:

1101 = D
1101 = D

所以是 DDH

所以答案是:

74H, DDH

选:

C

这里也有一个易错点:BAH 是负数,左移后变成了 74H,符号变了,所以这个左移结果实际上已经溢出。但题目问的是“移位后分别得什么位形”,所以仍按机器移位结果选 74H, DDH

08 题:定点运算器中必须有什么电路

题目问:无论采用双符号位还是单符号位,必须有什么?

答案是:

溢出判断电路

单符号位补码加减法可以用进位关系判断溢出;双符号位补码可以用两个符号位是否相同判断溢出。这些判断本质上常用异或逻辑实现。

所以答案是:

C. 溢出判断电路,它一般用“异或”门来实现

09 题:机器运算产生溢出的根本原因

溢出的根本原因不是“符号位进位丢弃”,也不是“运算发生错误”,而是:

机器字长有限,能表示的数值范围有限。

例如 8 位补码只能表示:

-128 ~ +127

如果实际数学结果超过这个范围,就会溢出。

所以答案是:

A. 寄存器的位数有限

10 题:判断哪个运算会溢出

题目给出:

r₁ = F5H
r₂ = EEH

都是 8 位补码。

先转成十进制。

F5H 是负数,因为最高位为 1。可以用“无符号值 – 256”:

F5H = 245
245 - 256 = -11

所以 r₁ = -11

EEH

EEH = 238
238 - 256 = -18

所以 r₂ = -18

8 位补码范围是:

-128 ~ +127

逐项判断:

A. r₁ + r₂ = -11 + (-18) = -29,不溢出

B. r₁ - r₂ = -11 - (-18) = 7,不溢出

C. r₁ × r₂ = (-11) × (-18) = 198,超过 +127,溢出

D. r₁ / r₂ = (-11) / (-18),结果不可能超出 8 位补码范围

所以答案是:

C. r₁ × r₂

这种题的关键是先把十六进制补码转成真值,再看结果是否超出表示范围。

11 题:关于模 4 补码

模 4 补码也叫变形补码,常见特点是使用双符号位来判断溢出。

合法的双符号位状态是:

00:正数
11:负数

发生溢出时:

01:正溢出
10:负溢出

但存储时不一定真的保存两个符号位。因为没有溢出时,两个符号位必然相同,所以存储每个模 4 补码时只需要保存一个符号位;进入运算器运算时再扩展成双符号位即可。

所以正确说法是:

B. 每个模 4 补码存储时只需要一个符号位

易错点在于:模 4 补码“运算时用双符号位”,但“存储时只需一个符号位”。不要把这两个场景混在一起。

12 题:双符号位下两个正数相加溢出的特征

双符号位补码中:

00 表示正数
11 表示负数
01 表示正溢出
10 表示负溢出

两个正数相加,如果发生溢出,一定是结果太大,超过最大正数范围,因此是正溢出。

正溢出的双符号位特征是:

01

所以答案是:

B. 01

13 题:用进位判断加减法溢出

题目说:

符号位的进位为 C0
最高位的进位为 C1

这里的考点是补码加减法溢出的进位判断法。

结论是:

C0 和 C1 不同,则溢出;
C0 和 C1 相同,则不溢出。

也就是:

C0 ⊕ C1 = 1 时溢出

具体说:

C0 = 1,C1 = 0,溢出
C0 = 0,C1 = 1,溢出
C0 = 1,C1 = 1,不溢出
C0 = 0,C1 = 0,不溢出

所以第 13 题不能简单理解成“有进位就溢出”。补码运算中,最高进位被丢弃是正常现象。真正判断溢出的标准是:

符号位进位和最高数值位进位是否不同。

因此本题答案应表述为:

C0、C1 一个产生进位,一个不产生进位。

也就是只满足 I 或只满足 II 的互斥情况;III 和 IV 都不溢出。

答案汇总:

题号答案
16D,约 100 个周期
17D,I、II、III 都正确
18B,0100 0101, 1101 1001, 1
19A,1, 1
20C,DAH, 0
21A,8CH, 1
22A,CF, 王道

16 题:32 位无符号整数乘法需要多少周期

这题考的是最基本的“移位加法乘法器”。

对于 32 位无符号数乘法,通常要对乘数的 32 位逐位处理。每一轮大致包括:

判断乘数最低位
需要时进行一次加法
被乘数左移一位
乘数右移一位

题目说一次 ALU 运算和一次移位操作各需要 1 个时钟周期。按照基础乘法器模型,每轮约需要:

1 次 ALU 运算 + 2 次移位操作 = 3 个周期

一共 32 轮,所以:

32 × 3 = 96 个周期

由于题目问“约为”,所以选最接近的:

D. 100

这题容易错选 64。如果按“每轮一次加法 + 一次合并移位”理解,会得到 32 × 2 = 64。但本题选项中同时给出 96100,并且问“约为”,明显是按基础移位加法乘法器的“三步法”理解,即约 100 个周期。

17 题:关于移位运算的判断

题目判断三个说法。

I:补码算术左移时,高位移出,低位补 0。若左移前后的符号位不同,则发生溢出。

这个说法正确。补码算术左移本质上相当于乘以 2。左移后如果符号位发生变化,说明结果超出补码可表示范围,发生溢出。

II:无符号数逻辑左移时,若最高位移出的是 1,则发生溢出。

这个说法也正确。无符号数左移相当于乘以 2,如果最高位移出的是 1,说明原来的高位有效信息被丢失,结果超过机器字长可表示范围。

III:逻辑左移和补码算术左移的结果都一样,都是移出最高位,并在低位补 0。

这个说法也正确。注意这里说的是“移位后的位形结果一样”。逻辑左移和补码算术左移在操作形式上都是:

高位移出,低位补 0

区别主要在于解释方式和溢出判断,而不是位移操作本身。

所以答案是:

D. I、II、III

18 题:用 8 位加法器计算无符号数 x – y

题目给出:

x = 69
y = 38

要求在 8 位加法器中计算 x - y,问两个输入端信息和低位进位信息分别是什么。

先把 x、y 转成 8 位二进制:

x = 69 = 0100 0101
y = 38 = 0010 0110

加法器本身只会做加法,要实现减法,一般用:

x - y = x + y 的按位取反 + 1

所以第二个输入端不是直接输入 y,而是输入 y 的按位取反:

y        = 0010 0110
按位取反 = 1101 1001

低位进位输入为 1,用来完成“加 1”。

因此加法器输入应为:

第一个输入端:0100 0101
第二个输入端:1101 1001
低位进位:1

答案是:

B. 0100 0101, 1101 1001, 1

这里容易错选 1101 1010, 0。因为 1101 1010-y 的补码形式,和 按位取反 + 1 的结果一样。但题目问的是“加法器的两个输入端信息和输入的低位进位信息”,标准减法器结构是第二输入端取反,低位进位置 1,所以应选 B。

19 题:补码表示下计算 x – y 的低位进位和 OF

题目给出:

[x]补 = F5H
[y]补 = 7EH

先把它们转成真值。

F5H 是 8 位补码,最高位为 1,是负数:

F5H = 245
245 - 256 = -11

所以 x = -11

7EH 最高位为 0,是正数:

7EH = 126

所以 y = 126

计算:

x - y = -11 - 126 = -137

8 位补码的表示范围是:

-128 ~ +127

-137 小于 -128,所以发生溢出,OF = 1

再看低位进位输入。加法器计算减法时:

x - y = x + y 的按位取反 + 1

所以低位进位输入为:

1

因此答案是:

A. 1, 1

用机器数验证一下:

x      = F5H = 1111 0101
y      = 7EH = 0111 1110
~y     = 81H = 1000 0001
Cin    = 1

F5H + 81H + 1 = 177H
取低 8 位 = 77H

77H 是正数,但真实结果应是负数 -137,符号错误,说明确实溢出。

20 题:计算 x/2 + 2y 的机器数和 OF

题目给出:

[x]补 = 44H
[y]补 = DCH

先求真值。

44H = 0100 0100 = 68

DCH 最高位为 1,是负数:

DCH = 220
220 - 256 = -36

所以 y = -36

计算表达式:

x/2 + 2y
= 68/2 + 2 × (-36)
= 34 - 72
= -38

-38 在 8 位补码范围 -128 ~ +127 内,所以:

OF = 0

再把 -38 转为 8 位补码:

38 = 0010 0110
-38 的补码 = 1101 1010 = DAH

所以答案是:

C. DAH, 0

也可以直接用移位做:

x = 44H = 0100 0100
x/2:算术右移一位 -> 0010 0010 = 22H

y = DCH = 1101 1100
2y:算术左移一位 -> 1011 1000 = B8H

22H + B8H = DAH

结果为 DAH,且没有溢出。

21 题:计算 x – 2y 的机器数和 OF

题目仍然是:

[x]补 = 44H
[y]补 = DCH

由上一题可知:

x = 68
y = -36
2y = -72

所以:

x - 2y
= 68 - (-72)
= 140

但是 8 位补码范围是:

-128 ~ +127

140 超过最大正数 127,所以发生正溢出:

OF = 1

再看机器结果。先求 2y

y = DCH = 1101 1100
2y = 算术左移一位 = 1011 1000 = B8H

计算:

x - 2y = 44H - B8H

用加法器实现减法:

44H - B8H = 44H + (~B8H) + 1
B8H = 1011 1000
~B8H = 0100 0111 = 47H

44H + 47H + 1 = 8CH

所以机器结果是:

8CH

8CH 最高位为 1,按补码解释是负数,这和真实数学结果 +140 不一致,说明发生溢出。

答案是:

A. 8CH, 1

22 题:C 语言代码中的比较使用哪个标志位,输出什么

代码是:

int si = 65536;
short i = si;
unsigned j = 0;

if (i <= j - 1)
    printf("王道");
else
    printf("计算机教育");

先看赋值:

si = 65536

short 通常是 16 位。65536 的十六进制是:

65536 = 0x00010000

赋给 16 位 short i 时,低 16 位为:

0000H

所以:

i = 0

再看:

unsigned j = 0;

所以:

j = 0

但是表达式中是:

i <= j - 1

由于 junsigned,所以 j - 1 按无符号数运算:

0 - 1 = 0xFFFFFFFF

也就是无符号整数的最大值。

同时,i 会被转换成无符号数参与比较:

i = 0
j - 1 = 0xFFFFFFFF

所以判断条件为真:

0 <= 0xFFFFFFFF

最终输出:

王道

因为这是无符号数比较,所以分支判断主要依据无符号比较相关的标志位,也就是 CF,而不是有符号溢出标志 OF

答案是:

A. CF, 王道

这题的关键陷阱有两个:第一,short i = 65536i 变成 0;第二,junsigned,所以 j - 1 不是 -1,而是无符号最大值。


在计算补码和反码的数字之和中,我们是不是要把它给进行化简到真数才比较方便计数,对吧?我们在判断是否溢出的时候,也可以利用算出来之后的数值来与范围进行比较,也可以利用,二进制求和之后首位来进行判断。在第22题里面,它这里面涉及到了大量的数据类型转换,不同数据类型进行比较,遵循的是什么规则?

对,可以把思路分成两层:一层是“为了算题方便,把机器数先译成真值”;另一层是“真正的机器运算,本质上仍然是按二进制位求和、取反、加 1、移位”。考研做题时,两种方法都要会,但使用场景不同。

一、补码、反码做加法时,要不要先转成真值?

如果题目只是问“这个运算是否溢出”“结果真值是多少”,先把补码、反码译成真值通常更直观。

例如 8 位补码:

F5H = 1111 0101
最高位是 1,说明是负数
真值 = 245 - 256 = -11

这种方法很适合快速判断:

x = -11
y = 126
x - y = -137

而 8 位补码范围是:

-128 ~ +127

所以 -137 溢出。

但是,如果题目问的是“机器结果是什么”“加法器输入端是什么”“OF、CF 是多少”,就不能只停留在真值层面,还要回到机器数按位运算。

比如计算补码减法:

x - y = x + (-y)

在加法器中通常实现为:

x + 按位取反(y) + 1

所以题目问加法器的输入端时,答案不是直接输入 -y 的真值,而是输入 y 的按位取反,并且低位进位 Cin = 1

所以可以这样记:

判断数值大小、是否超范围:转真值最方便;
求机器结果、标志位、加法器输入:必须看二进制位运算。

二、补码加法溢出,不能只看结果最高位

你说“可以利用二进制求和之后首位来判断”,这里要稍微修正一下:只看结果最高位是不够的

补码加法溢出的判断,常用两种方法。

第一种,真值范围判断法:

n 位补码范围:-2<sup>n-1</sup> ~ 2<sup>n-1</sup> - 1

例如 8 位补码范围:

-128 ~ +127

如果数学真值结果超出这个范围,就溢出。

第二种,符号位判断法:

同号相加,结果变号,则溢出;
异号相加,一定不溢出。

具体来说:

正数 + 正数 = 负数,正溢出
负数 + 负数 = 正数,负溢出
正数 + 负数,不溢出
负数 + 正数,不溢出

所以不能只看“结果最高位是 0 还是 1”。例如:

0100 0000 + 1100 0000 = 0000 0000

一个正数加一个负数,结果最高位是 0,但这不代表发生了溢出。因为异号相加本来就不会溢出。

第三种,进位判断法:

符号位的进位 C0
最高数值位向符号位的进位 C1
若 C0 ≠ C1,则溢出;
若 C0 = C1,则不溢出。

也就是:

OF = C0 ⊕ C1

这也是硬件中很常见的溢出判断方法。

三、反码加法和补码加法有什么区别?

补码加法最简单:

直接按二进制相加,最高位进位丢弃。

例如 8 位补码相加,如果产生第 9 位进位,直接舍弃即可。

但反码加法不同。反码加法有一个特殊规则:

最高位产生的进位,要循环加到最低位。

这叫“循环进位”或者“回卷进位”。

例如反码运算中,如果两个 8 位反码相加得到:

1 0010 1010

前面的最高进位 1 不能直接丢掉,而是要加回最低位:

0010 1010
+      1
---------
0010 1011

所以反码加法题要特别注意:补码最高进位丢弃,反码最高进位循环加回最低位

不过现在 408 中主要考补码,反码更多用于理解机器数表示和转换。真正做加减法、判断溢出时,补码是重点。

四、第 22 题涉及的 C 语言类型转换规则

第 22 题的核心不是机器数加减,而是 C 语言的“整型提升”和“通常算术转换”。

代码大致是:

int si = 65536;
short i = si;
unsigned j = 0;

if (i <= j - 1)
    printf("王道");
else
    printf("计算机教育");

这里有三层转换。

1. 赋值给 short 时发生截断

假设常见考研环境:

int      32 位
short    16 位
unsigned 32 位

si = 65536,也就是:

65536 = 0x00010000

赋给 16 位 short i 时,只保留低 16 位:

0x00010000 的低 16 位 = 0x0000

所以:

i = 0

严格按 C 标准,超出 short 表示范围的赋值结果与具体实现有关;但在 408 和常见机器题中,一般按“截取低位”处理。

2. j - 1 中,1 会转换成 unsigned

因为:

unsigned j = 0;

所以表达式:

j - 1

不是有符号运算,而是无符号运算。

1 会先转换成 unsigned int,于是:

j - 1 = 0u - 1u

无符号整数运算发生下溢时,不是得到 -1,而是按模运算回绕。

对于 32 位 unsigned:

0u - 1u = 2<sup>32</sup> - 1 = 0xFFFFFFFF

所以:

j - 1 = UINT_MAX

也就是无符号最大值。

3. i <= j - 1 比较时,i 也会转换成 unsigned

此时左边是:

i = 0

右边是:

j - 1 = 0xFFFFFFFF

因为右边是 unsigned int,所以比较时,左边的 i 也要转换成 unsigned int

于是判断变成:

0u <= 0xFFFFFFFFu

这个条件成立。

所以最终输出:

王道

五、C 语言不同整数类型混合运算的基本规则

408 中常考的是下面这个顺序。

第一步,先做整型提升。

小于 int 的整数类型,例如:

char
short
signed char
unsigned char
unsigned short

在表达式运算前,通常会先提升为 int。如果 int 表示不了全部值,才提升为 unsigned int

所以:

short i;

在参与表达式运算时,通常先变成 int

第二步,如果两边类型不同,就做通常算术转换。

常见规则可以这样记:

有 double 向 double 转;
有 float 向 float / double 转;
整数之间,先看 signed / unsigned,再看等级 rank。

对于 408 常见整型题,重点是 signed 和 unsigned 的混合运算:

如果有 unsigned int,另一个 int 通常会转换成 unsigned int。

所以:

int a = -1;
unsigned b = 1;

a < b

不是比较:

-1 < 1

而是先把 a 转成 unsigned:

-1 转成 unsigned = 0xFFFFFFFF

于是变成:

0xFFFFFFFF < 1

结果是假。

这类题非常容易错,因为从数学直觉看 -1 < 1 是真,但 C 语言实际按无符号数比较,结果变成假。

六、第 22 题为什么用 CF,而不是 OF?

这题问“条件判断依据什么标志寄存器”,答案选 CF,因为最终比较是无符号比较。

要区分:

有符号数比较:主要看 SF、OF、ZF
无符号数比较:主要看 CF、ZF

其中:

CF:进位 / 借位标志,常用于无符号数比较
OF:溢出标志,常用于有符号数比较
ZF:零标志,用于判断是否相等

对于无符号比较:

a < b  看 CF = 1
a == b 看 ZF = 1
a <= b 看 CF = 1 或 ZF = 1

所以严格说,<= 这种判断不仅可能涉及 CF,也会涉及 ZF。但在选择题里,通常把“无符号比较”归结为看 CF,把“有符号比较”归结为看 OF 相关标志。

因此第 22 题选:

CF,王道

七、做这类题的固定流程

遇到 C 语言整数转换题,最好不要直接凭直觉比较,而是按下面顺序走:

1. 先看变量声明类型:int、short、unsigned、char 等;
2. 看赋值时是否发生截断;
3. 看表达式中是否有 unsigned;
4. 小整型先提升为 int;
5. signed 和 unsigned 混合时,通常转成 unsigned;
6. 最后再判断比较结果和输出。

第 22 题完整流程就是:

si = 65536 = 0x00010000

short i = si
=> i 取低 16 位
=> i = 0

unsigned j = 0

j - 1
=> 0u - 1u
=> 0xFFFFFFFFu

i <= j - 1
=> 0u <= 0xFFFFFFFFu
=> true

输出:王道

所以这道题真正考的是:C 语言中 unsigned 会“污染”整个表达式,使比较转为无符号比较。


在2021题里面,cah ,8ch我能知道它是否会溢出,但是我不知道,就是说它溢出的时候会输出什么样的结果,以及在第22题里面标志寄存器中的cf of这几个概念,其实我也不太理解,你能给我讲一下吗?

你这里问的是两个很关键的点:第一,补码运算发生溢出时,机器到底给出什么结果;第二,CF、OF 这些标志位到底表示什么,以及为什么第 22 题看 CF 而不是 OF

先说结论:溢出时,机器仍然会输出一个固定字长的二进制结果,但这个结果已经不能当作正确的有符号真值来解释。
也就是说,寄存器不会因为溢出就“不输出”或者输出特殊符号,而是照样把低 8 位、低 16 位、低 32 位保留下来,同时把溢出标志 OF 置为 1,告诉后续电路或程序:“这个有符号结果不可信”。

一、补码溢出时,机器输出的是什么?

以第 21 题为例:

[x]补 = 44H
[y]补 = DCH
求 x - 2y 的机器数和 OF

先转真值:

44H = 0100 0100 = 68

DCH = 1101 1100
最高位为 1,是负数
真值 = 220 - 256 = -36

所以:

x = 68
y = -36

x - 2y = 68 - 2 × (-36)
       = 68 + 72
       = 140

但是 8 位补码的表示范围是:

-128 ~ +127

140 超过了最大正数 127,所以发生正溢出,OF = 1

但是机器不会停在那里。机器仍然会按 8 位补码运算给出结果。

先算 2y

y = DCH = 1101 1100

算术左移一位:

1101 1100 << 1 = 1011 1000 = B8H

所以:

x - 2y = 44H - B8H

减法用加法实现:

44H - B8H
= 44H + B8H 的补码相反数
= 44H + (~B8H + 1)

计算:

B8H = 1011 1000
~B8H = 0100 0111 = 47H
~B8H + 1 = 0100 1000 = 48H

所以:

44H - B8H
= 44H + 48H

二进制相加:

  0100 0100
+ 0100 1000
------------
  1000 1100

结果就是:

1000 1100 = 8CH

所以第 21 题的机器结果是:

8CH,OF = 1

关键就在这里:8CH 是机器实际算出来并保留在寄存器里的 8 位结果,但由于 OF = 1,它不能作为正确的有符号补码结果来解释。

如果强行把 8CH 当作 8 位补码解释:

8CH = 1000 1100
无符号值 = 140
补码真值 = 140 - 256 = -116

这就变成了 -116,显然和真实数学结果 +140 不一致。这个“不一致”正是溢出的表现。

所以要分清两句话:

机器结果:8CH
真实数学结果:+140
8 位补码无法表示 +140
因此 OF = 1,机器结果作为有符号数无效

二、为什么溢出后会变成 8CH?

因为固定字长机器只保留低 n 位。

8 位机器中,所有运算结果最后都只能落在 8 位里。超过 8 位的部分要么被丢弃,要么通过标志位反映出来。

对于第 21 题:

真实数学结果 = 140

140 的二进制是:

140 = 1000 1100

它刚好是 8 位,但问题在于:8 位补码里,最高位是符号位。

8 位补码中:

0000 0000 ~ 0111 1111 表示 0 ~ +127
1000 0000 ~ 1111 1111 表示 -128 ~ -1

所以 1000 1100 在 8 位补码语境下不是 +140,而是 -116

这就是补码有符号溢出的本质:二进制位形还在,但它已经落入了错误的符号区间。

可以这样理解:

数学上:68 + 72 = 140

机器上:
0100 0100 + 0100 1000 = 1000 1100

两个正数相加,结果最高位却变成 1,像负数
所以发生正溢出

这类题以后可以直接用这个规则判断:

正数 + 正数 = 负数,正溢出
负数 + 负数 = 正数,负溢出
异号相加,不溢出

第 21 题本质上就是:

68 + 72

两个正数相加,结果机器位形为:

1000 1100

最高位为 1,结果像负数,所以溢出。

三、第 20 题和第 21 题的区别

第 20 题是:

x/2 + 2y

已知:

x = 68
y = -36

所以:

x/2 + 2y
= 34 + 2 × (-36)
= 34 - 72
= -38

-38 在 8 位补码范围内,所以不溢出。

-38 的补码:

38 = 0010 0110
-38 = 1101 1010 = DAH

所以第 20 题是:

DAH,OF = 0

第 21 题是:

x - 2y = 140

超过 +127,所以:

8CH,OF = 1

两题的区别不是“机器能不能算出一个十六进制结果”,而是:

第 20 题:机器结果 DAH 能正确表示 -38,所以 OF = 0
第 21 题:机器结果 8CH 不能正确表示 +140,所以 OF = 1

四、CF 和 OF 的核心区别

CFOF 都和“超过范围”有关,但它们服务的对象不同。

CF:Carry Flag,进位 / 借位标志,主要用于无符号数运算
OF:Overflow Flag,溢出标志,主要用于有符号补码运算

这句话非常重要。

同一串二进制,既可以被解释成无符号数,也可以被解释成有符号补码数。例如:

1000 1100

如果看成无符号数:

1000 1100 = 140

如果看成 8 位补码:

1000 1100 = -116

机器加法器本身并不知道程序员想把它当有符号数还是无符号数。机器只负责二进制相加,然后设置标志位。到底该看 CF 还是 OF,取决于这次运算被当作什么类型来解释。

五、CF:无符号数的进位 / 借位

CF 主要用于无符号数。

对于加法:

如果最高位向更高位产生进位,则 CF = 1
否则 CF = 0

例如 8 位无符号加法:

  1111 1111   = 255
+ 0000 0001   = 1
------------
1 0000 0000

8 位寄存器只能保留低 8 位:

0000 0000

但最高位产生了进位,所以:

CF = 1

这表示无符号加法溢出:

255 + 1 = 256

而 8 位无符号数范围是:

0 ~ 255

所以超范围。

但是如果从有符号补码角度看:

1111 1111 = -1
0000 0001 = +1

那么:

-1 + 1 = 0

有符号运算并没有溢出,所以:

OF = 0

这个例子说明:

CF = 1 不一定 OF = 1
OF = 1 也不一定 CF = 1

它们不是一回事。

六、OF:有符号补码的溢出

OF 主要用于有符号补码运算。

补码加法判断 OF,最常用的是:

同号相加,结果变号,则 OF = 1
异号相加,不会溢出

例如第 21 题中的核心加法:

  0100 0100   = +68
+ 0100 1000   = +72
------------
  1000 1100

两个操作数都是正数,结果却变成最高位为 1,好像是负数。

所以:

OF = 1

但是这个加法有没有产生最高进位呢?

0100 0100 + 0100 1000 = 1000 1100

没有超过 8 位,没有产生第 9 位进位,所以:

CF = 0

这就是非常典型的情况:

OF = 1,CF = 0

含义是:

作为有符号补码运算,它溢出了;
作为无符号加法,68 + 72 = 140,没有超过 255,所以没有无符号进位。

七、同一个结果,CF 和 OF 可以不同

用几个 8 位例子对比一下更清楚。

运算机器结果无符号角度有符号角度CFOF
FFH + 01H00H255 + 1 = 256,无符号溢出-1 + 1 = 0,不溢出10
44H + 48H8CH68 + 72 = 140,未超过 25568 + 72 = 140,超过 +12701
80H + 80H00H128 + 128 = 256,无符号溢出-128 + -128 = -256,有符号溢出11
01H + 01H02H正常正常00

所以不要把 CFOF 混成一个“溢出标志”。

更准确地说:

CF 判断无符号数是否超出范围;
OF 判断有符号补码数是否超出范围。

八、减法和比较时,CF 怎么理解?

减法中,CF 通常表示借位。

例如无符号数:

0 - 1

显然不够减,需要借位,所以:

CF = 1

在固定 8 位中:

0000 0000 - 0000 0001 = 1111 1111

机器结果是 FFH,也就是无符号的 255。这不是数学上的 -1,而是无符号模运算回绕。

所以无符号比较时,常通过减法来设置标志位。

例如比较:

a < b

机器内部可以做:

a - b

如果 a - b 需要借位,说明:

a < b

于是:

CF = 1

所以无符号比较常用规则是:

a < b    看 CF = 1
a == b   看 ZF = 1
a <= b   看 CF = 1 或 ZF = 1

其中 ZF 是零标志位,表示结果是否为 0。

九、OF 在有符号比较中的作用

有符号比较不能简单看最高位,因为有符号运算可能溢出。

例如判断:

a < b

机器可以计算:

a - b

如果结果是负数,通常说明 a < b。但是如果减法发生有符号溢出,结果的符号位可能是错的。这时就需要结合 OF 修正。

所以有符号比较常用:

SF 和 OF

其中:

SF:Sign Flag,符号标志,等于结果最高位
OF:Overflow Flag,有符号溢出标志
ZF:Zero Flag,零标志

常见规则是:

有符号 a < b:看 SF ⊕ OF = 1
有符号 a <= b:看 ZF = 1 或 SF ⊕ OF = 1

考研里不一定要求把这几个跳转条件全部背下来,但要知道大方向:

无符号比较:主要看 CF、ZF
有符号比较:主要看 SF、OF、ZF

第 22 题问 CF / OF,本质就是让判断:这次比较是无符号比较,还是有符号比较。

十、第 22 题为什么看 CF,而不是 OF?

第 22 题代码是:

int si = 65536;
short i = si;
unsigned j = 0;

if (i <= j - 1)
    printf("王道");
else
    printf("计算机教育");

先看:

short i = si;

在考研常见设定中:

int      32 位
short    16 位
unsigned 32 位

65536 的十六进制是:

65536 = 0x00010000

赋给 16 位 short,只保留低 16 位:

0x00010000 的低 16 位 = 0x0000

所以:

i = 0

再看:

unsigned j = 0;

那么:

j - 1

不是有符号的 0 - 1 = -1,而是无符号运算:

0u - 1u = UINT_MAX

在 32 位 unsigned 中:

UINT_MAX = 0xFFFFFFFF = 2³² - 1

然后比较:

i <= j - 1

由于右边是 unsigned,左边的 i 也会被转换成 unsigned

于是比较变成:

0u <= 0xFFFFFFFFu

这个条件当然成立,所以输出:

王道

因为这次比较已经变成了无符号比较,所以判断条件依赖的是无符号比较标志,也就是主要看:

CF、ZF

而选项里通常把无符号比较归为:

CF

所以第 22 题选:

CF,王道

十一、第 22 题如果按有符号比较,会发生什么?

如果没有 unsigned j 这个陷阱,直觉上可能会想:

j = 0
j - 1 = -1
i = 0

0 <= -1

这当然是假。

如果是有符号比较,确实应该输出:

计算机教育

但问题是 C 语言里,只要表达式中混入了 unsigned,很多时候另一个有符号数会被转换成无符号数。

所以实际不是比较:

0 <= -1

而是比较:

0u <= 4294967295u

这就是真。

这道题的本质陷阱就是:

unsigned 会把整个表达式拉到无符号语境中。

十二、做题时怎么快速判断看 CF 还是 OF?

可以直接按类型判断。

如果题目说:

无符号数加减、无符号数比较

重点看:

CF

如果题目说:

补码、有符号整数、int、short、signed

重点看:

OF

但 C 语言题要特别注意:变量声明里只要出现 unsigned,表达式可能被转换成无符号运算。

所以第 22 题虽然有 short i,但右边有:

unsigned j

于是整个比较转为无符号比较,看 CF,不是看 OF

可以整理成一句考试用判断:

CF 管无符号进位/借位,OF 管有符号补码溢出。

再细一点:

无符号数:范围是 0 ~ 2ⁿ - 1,超了看 CF。
有符号补码:范围是 -2ⁿ⁻¹ ~ 2ⁿ⁻¹ - 1,超了看 OF。

十三、回到你的疑问:溢出时到底输出什么?

最后再把这个点压实。

以 8 位补码为例,机器运算永远输出 8 位结果:

44H + 48H = 8CH

从二进制看:

0100 0100 + 0100 1000 = 1000 1100

所以寄存器里就是:

1000 1100

也就是:

8CH

但因为这是两个正数相加却得到负号位,所以:

OF = 1

因此:

机器输出:8CH
是否可信:作为有符号补码结果不可信
真实数学结果:140
溢出原因:140 超过 8 位补码最大值 127

做补码溢出题时,一定要把这三件事分开:

1. 机器位形结果是多少?
2. 这个结果按补码解释成什么真值?
3. 真实数学结果是否超出补码表示范围?

第 21 题就是最典型的例子:

机器位形结果:8CH
按 8 位补码解释:-116
真实数学结果:+140
因为真实结果无法用 8 位补码表示,所以 OF = 1

本题应选 C

这张图考的是 32 位补码一位乘法器,本质上对应考研里常说的 Booth 一位乘法思想。它不是普通无符号移位加法乘法,而是针对补码有符号数设计的乘法逻辑。

图中结构大致可以这样读:

被乘数放在寄存器 X 中,位数为 32 位;部分积放在 P 中,乘数放在 Y 中,P | Y 合起来构成 64 位寄存器;ALU 是 32 位的,每次只对部分积 P 和被乘数 X 做加法或减法;控制逻辑根据乘数末位及附加位判断本轮执行 +X-X,还是不操作,然后再让 P | Y 整体右移一位。这个过程重复 32 次。

Booth 一位乘法的基本规则是看当前乘数最低位和附加位,常写成:

Y0 Y-1 = 00 :不操作
Y0 Y-1 = 01 :P = P + X
Y0 Y-1 = 10 :P = P - X
Y0 Y-1 = 11 :不操作
然后 P、Y、Y-1 整体算术右移一位

所以逐项判断如下。

A 项说“32 位无符号整数的乘法电路和该图没有区别”,这是错误的。无符号一位乘法通常只需要根据乘数位判断是否加被乘数,不需要根据相邻两位判断加法或减法,也不需要为了补码符号保持而进行算术右移。该图中明显有“加/减”控制信号,说明它不是普通无符号乘法器,而是补码乘法器。

B 项说“执行过程中 ALU 要么做加法,要么做减法,不可能执行空操作”,这是错误的。Booth 一位乘法中,当判断位组合为 0011 时,本轮不需要对部分积加减被乘数,也就是可以空操作。只有 01 时加,10 时减。

C 项说“图中的乘积寄存器 P 和乘数寄存器 Y 所执行的右移是算术右移”,这是正确的。因为这是补码乘法,右移时必须保持符号位。更准确地说,是 P、Y 以及附加位整体构成的移位寄存器做算术右移,最高位补 P 的符号位,不能做逻辑右移。如果逻辑右移,高位补 0,会破坏负数的符号扩展,结果就不再是正确的补码乘法。

D 项说“计算完成后,若乘积寄存器 P 中的值不全为 0,则发生溢出”,这是错误的。两个 32 位补码数相乘,完整结果是 64 位,放在 P | Y 中,正常情况下并不存在 64 位结果溢出的问题。如果题目要求只保留低 32 位,那么判断溢出也不能简单看 P 是否全为 0。对于有符号补码乘法,若最终 64 位结果能够被低 32 位正确符号扩展表示,才不溢出。也就是说,高 32 位 P 应该是低 32 位 Y 符号位的扩展:

若 Y 的最高位为 0,则 P 应全为 0
若 Y 的最高位为 1,则 P 应全为 1

例如负数乘积的高位可能全为 1,这不代表溢出;所以 D 项把无符号乘法的部分判断思路错误套到了补码有符号乘法上。

因此本题结论是:

A 错
B 错
C 对
D 错

正确答案:C

这类题的快速识别方法是:只要看到 补码一位乘法 + 加/减控制 + P、Y 整体右移 + 附加判断位,基本就是 Booth 乘法。考点通常集中在三个地方:第一,ALU 不一定每轮都加减,可能空操作;第二,补码乘法右移必须是算术右移;第三,溢出判断不能简单看高位是否非 0,而要看高位是否为低位符号位的正确扩展。

对于这种类型的题目 ,这个结构我们是否需要熟记呢?它涉及到哪些知识 ,,本质上考的是什么东西?

这种题不需要把整张逻辑结构图一笔一画背下来,但需要熟记它背后的“结构模板”。也就是说,不要求记住每根线怎么连、方框位置怎么摆,但必须看到 X、P、Y、ALU、右移、计数器、控制逻辑 这些部件时,能立刻判断出:这是 补码一位乘法,也就是 Booth 乘法的硬件实现

它本质上不是在考画图,而是在考:补码乘法算法如何映射成硬件数据通路和控制逻辑


一、这种结构要不要熟记?

要熟,但不是死背图形,而是熟记它的几个关键部件和作用。

对于 32 位补码一位乘法器,可以把结构压缩成下面这个模型:

X:被乘数寄存器,存放被乘数
P:乘积高位 / 部分积寄存器,32 位
Y:乘数寄存器,32 位
P | Y:合起来构成 64 位乘积寄存器
ALU:对 P 和 X 做加法或减法
控制逻辑:根据 Y 的最低位和附加位判断加、减或不操作
计数器:控制循环次数,32 位乘法做 32 次
右移逻辑:每轮之后 P、Y 和附加位整体右移一位

如果从做题角度压缩记忆,可以记成一句话:

补码一位乘法 = P 与 X 加/减 + P、Y、附加位整体算术右移 + 做 n 轮

所以结构图不用完整背,但必须记住这几个不变量:

第一,X 是被乘数寄存器,不参与右移。

第二,P 是部分积寄存器,要和 X 送入 ALU 做加减。

第三,Y 是乘数寄存器,会和 P 一起右移。

第四,控制逻辑不是只看一位,而是看 Y0 和附加位 Y-1

第五,每轮可能加、可能减、也可能什么都不做。

第六,补码乘法右移必须是算术右移,而不是逻辑右移。

这几个点熟了,图形怎么变都能做。


二、它涉及哪些知识点?

这类题看起来是“乘法器结构”,但其实同时串了四块内容。

第一块是 补码表示与补码加减法。因为被乘数和乘数都是补码形式,所以硬件里不需要单独判断正负号再取绝对值,而是直接用补码加减完成乘法。这也是 Booth 乘法能直接处理有符号数的原因。

第二块是 定点乘法算法。考研里常见的乘法有无符号乘法、原码一位乘法、补码一位乘法。它们的共同点是“逐位处理乘数,每轮移位”,区别在于是否需要减法、右移方式、符号如何处理。

第三块是 数据通路结构。也就是寄存器、ALU、移位器、控制逻辑、计数器之间如何配合。题目给图时,通常不是让你设计电路,而是让你判断图中某个部件的功能或某个选项的说法是否正确。

第四块是 溢出与结果位数。两个 32 位数相乘,完整乘积需要 64 位保存。若题目默认结果存在 P | Y 这个 64 位寄存器中,一般不按 32 位结果判断溢出。如果题目要求只保留 32 位结果,则有符号乘法的溢出判断要看高 32 位是否是低 32 位符号位的扩展,而不是简单看高 32 位是否全 0。


三、补码一位乘法的核心规则

补码一位乘法,也就是 Booth 一位乘法,最核心的控制规则是看 Y0 和附加位 Y-1

Y0 是乘数寄存器当前最低位,Y-1 是附加位,初始为 0。

Y0 Y-1 = 00 :P 不变
Y0 Y-1 = 01 :P = P + X
Y0 Y-1 = 10 :P = P - X
Y0 Y-1 = 11 :P 不变
然后 P、Y、Y-1 整体算术右移一位

这张图里的“加/减”控制信号,就是为了实现 P + XP - X。如果只是普通无符号乘法,一般只需要根据乘数位决定是否加被乘数,不需要这种 Booth 式的加减判断。

所以看到图中有 加/减控制,就要警觉:这不是普通无符号乘法,而是补码 Booth 乘法。


四、这种题可以直接套用什么方法?

做这种结构判断题,可以直接套一个四步法。

第一步:先判断是哪种乘法器

看题干关键词。

如果题干说“补码一位乘法”,并且图中有 加/减 控制,那么基本就是 Booth 乘法。

如果题干说“无符号乘法”或只根据乘数位判断是否加被乘数,一般是普通移位加法乘法。

如果题干说“原码一位乘法”,通常是先处理符号位,数值部分按绝对值做乘法,符号单独确定。

本题明确说“32 位补码一位乘法”,所以算法定位就是 Booth 乘法。


第二步:识别寄存器分工

这一步是防止选项偷换概念。

X 是被乘数寄存器,通常保持不动。

Y 是乘数寄存器,会右移。

P 是部分积寄存器,和 Y 合起来保存中间结果。

P | Y 合起来是 64 位寄存器,最终结果也在这里。

ALU 只负责对 PX 做加法或减法,不直接对整个 64 位乘积做加减。

所以看到选项说 P 和 Y 一起右移,这通常是对的;看到选项说 X 也跟着右移,通常就要怀疑。


第三步:判断每轮操作

补码 Booth 乘法每轮不一定加减,可能空操作。

这个点很常考。因为很多同学会以为“既然图里有 ALU,那每轮 ALU 必须做加法或减法”。实际上不是。

Booth 规则中:

00:不操作
01:加 X
10:减 X
11:不操作

所以如果选项说“执行过程中 ALU 要么加法,要么减法,不可能空操作”,这是错的。


第四步:判断右移类型

这是本题最核心的判断点。

补码表示的是有符号数,右移时必须保持符号位,所以 P、Y、Y-1 整体右移应是 算术右移

算术右移的含义是:最高位补原符号位。

逻辑右移的含义是:最高位补 0。

补码乘法中如果用逻辑右移,负数的符号扩展会被破坏,中间结果就会错。因此,凡是补码一位乘法,看到右移,一般优先判断为算术右移。

可以记成:

无符号乘法:通常逻辑右移
补码 Booth 乘法:整体算术右移

五、本质上到底考什么?

这类题本质上考的不是“乘法怎么算出具体结果”,而是考三个层次。

第一个层次是 算法规则:补码 Booth 乘法每轮根据 Y0Y-1 判断 +X、-X、不操作

第二个层次是 硬件实现:为什么需要 P、Y、X、ALU、控制逻辑、计数器,每个部件在算法中对应什么动作。

第三个层次是 易错概念辨析:无符号乘法和补码乘法是否一样,ALU 是否每轮都工作,右移是算术右移还是逻辑右移,乘积是否溢出如何判断。

考研选择题通常就是围绕这些点设置干扰项。

例如本题四个选项的本质分别是:

A:考无符号乘法和补码乘法电路是否一样
B:考 Booth 乘法是否允许空操作
C:考补码乘法右移类型
D:考 32 位乘法结果与溢出判断

所以这道题不是孤立地考一张图,而是把补码表示、移位、ALU、乘法算法、溢出判断揉在一起考。


六、几个高频陷阱

第一,容易把补码一位乘法当成无符号乘法。

无符号乘法通常是“当前乘数位为 1 就加,为 0 就不加”,没有 +X / -X 的 Booth 判断。而补码 Booth 乘法要看相邻两位变化,所以会出现减法。

看到“加/减”控制信号,就不要再按普通无符号乘法理解。


第二,容易认为 ALU 每轮必须工作。

这是错的。0011 都是不操作。硬件里可以让 ALU 不改变 P,或者通过控制信号使写入无效。题目说“不可执行空操作”,通常就是错项。


第三,容易把右移看成普通逻辑右移。

只要是补码有符号运算,右移通常要考虑符号保持。Booth 乘法中,P、Y、Y-1 整体右移是算术右移,最高位补 P 的符号位。


第四,容易用“高位不为 0”判断有符号乘法溢出。

这只适合某些无符号截断场景,不能直接套到补码有符号乘法。

如果两个 32 位补码数相乘,完整结果用 64 位保存,不应简单说 P 非 0 就溢出。负数乘积的高位可能全是 1,这是正常的符号扩展。

若只保留低 32 位,有符号溢出的判断应是:

低 32 位最高位为 0:高 32 位应全为 0
低 32 位最高位为 1:高 32 位应全为 1
否则表示低 32 位无法正确表示完整乘积,发生溢出

七、做题时的快速判断口诀

这类题可以记下面这一套:

补码乘法看 Booth,
两位决定加减无;
P 与 X 进 ALU,
P、Y 整体算右移;
做满 n 轮得 2n 位,
溢出别只看高位非零。

更简化一点:

补码一位乘法:
看 Y0Y-1,01 加,10 减,00/11 不动,整体算术右移。

这句话基本能解决大多数围绕补码一位乘法结构图的选择题。


八、复习时应该掌握到什么程度?

408 风格下,不需要把乘法器内部控制线路设计到门级电路,但要能做到以下程度:

看到结构图,能说出哪个寄存器存被乘数、哪个存乘数、哪个存部分积。

看到 加/减 控制,能判断这是补码 Booth 乘法的重要特征。

看到“每轮 ALU 必须加或减”这种说法,能判断错误,因为可能空操作。

看到“右移”相关说法,能判断补码乘法应该是算术右移。

看到“P 不全为 0 就溢出”这种说法,能判断错误,因为有符号数高位可能是符号扩展。

所以这类题最重要的不是会不会手算一个很长的乘法过程,而是能把 算法规则、寄存器含义、移位方式、溢出判断 四件事对应起来。掌握这四点,结构图换一种画法也不会影响判断。

本题答案:A

这道题的关键不是让你真的手算 32 次除法循环,而是考 32 位补码整数除法中的特殊溢出情况

题干说:

除数寄存器 Y
余数/商寄存器 Q
Y、Q 均为补码表示
问:什么初始值下除法执行时间最短?

在这种除法器中,正常的 32 位整数除法一般要经过多次“左移 + 加/减 + 上商”的迭代过程。图中也有计数器 Cₙ,说明正常情况下要按位循环执行。

所以如果问“执行时间最短”,通常不是比较哪个商更简单,而是要看有没有 一开始就能判定异常 的情况。对于 32 位补码整数除法,最典型的异常就是:

-2³¹ ÷ (-1) = +2³¹

但是 32 位补码整数的表示范围是:

-2³¹ ~ 2³¹ - 1

也就是说,+2³¹ 超出了 32 位补码正数的最大范围,因此发生 商溢出。这种情况不需要完整执行 32 轮除法,可在开始阶段直接判定溢出,因此执行时间最短。


先把选项中的十六进制数转换成 32 位补码真值:

FFFF FFFF = -1
8000 0000 = -2³¹

逐项判断。

A 项:

Y = FFFF FFFF = -1
Q = 8000 0000 = -2³¹

表示:

Q ÷ Y = (-2³¹) ÷ (-1) = +2³¹

但 32 位补码最大正数是 2³¹ - 1,所以 +2³¹ 不能表示,发生商溢出。可以提前终止,执行时间最短。

B 项:

Y = 8000 0000 = -2³¹
Q = FFFF FFFF = -1

表示:

(-1) ÷ (-2³¹) = 0,余数为 -1

商为 0,可以表示,不溢出,需要正常执行除法过程。

C 项:

Y = FFFF FFFF = -1
Q = FFFF FFFF = -1

表示:

(-1) ÷ (-1) = 1

商为 1,可以表示,不溢出。

D 项:

Y = 8000 0000 = -2³¹
Q = 8000 0000 = -2³¹

表示:

(-2³¹) ÷ (-2³¹) = 1

商为 1,也可以表示,不溢出。

因此只有 A 会产生补码整数除法中特殊的商溢出。

结论:

正确答案:A

这类题的固定做法是:先把 FFFF FFFF8000 0000 识别出来。

FFFF FFFF = -1
8000 0000 = 最小负数 = -2³¹

然后重点检查是否出现:

最小负数 ÷ (-1)

只要是 32 位补码整数除法:

0x80000000 ÷ 0xFFFFFFFF
= -2³¹ ÷ (-1)
= +2³¹

这个结果超出 32 位补码范围,发生商溢出。

所以看到这种题,不要真的去模拟除法器。它本质上考的是 补码整数除法的溢出边界,尤其是 最小负数 ÷ -1 这一种特殊情况。

25~28 题的答案分别是:

25:D
26:B
27:A
28:C

这几题本质上都在考“补码表示、符号扩展、定点补码运算溢出、C 语言整型提升规则”,属于计算机组成原理中“数据的表示和运算”的高频题型。

第25题:C 语言中 int、short 混合运算

题意是:32 位机器,xzint 型,yshort 型。

已知:

x = 127;
y = -9;
z = x + y;

要求判断执行后 x、y、z 的机器数表示。

x = 127,int 型占 32 位,所以:

x = 0000007FH

y = -9,short 型占 16 位。先写出 +9:

+9 = 0009H

16 位补码表示 -9,就是对 0009H 求补码:

0009H -> FFF7H

所以:

y = FFF7H

注意这里最容易错的是把 -9 写成 FFF9H
FFF9H 其实表示的是 -7,不是 -9

执行:

z = x + y;

在 C 语言中,short 参与表达式运算时要先进行整型提升。也就是说,y 会从 16 位 short 提升为 32 位 int。

因为 y 是负数,所以要进行符号扩展:

y = FFF7H  ->  FFFFFFF7H

然后计算:

0000007FH + FFFFFFF7H = 00000076H

真值角度看就是:

127 + (-9) = 118

118 的 32 位补码就是:

00000076H

所以第25题选:

D
x = 0000007FH,y = FFF7H,z = 00000076H

这题的核心陷阱是两个:第一,-9 的 16 位补码是 FFF7H;第二,short 和 int 混合运算时,short 要先符号扩展为 int。

第26题:8位补码乘法是否溢出

题意是:四个整数用 8 位补码表示:

r1 = FEH
r2 = F2H
r3 = 90H
r4 = F8H

运算结果仍然存在一个 8 位寄存器中,判断哪一个乘法会溢出。

8 位补码表示范围是:

-128 ~ +127

先把每个机器数转换成真值。

FEH 是 8 位补码:

FEH = 11111110

最高位是 1,说明是负数。其真值为:

FEH = 254
254 - 256 = -2

所以:

r1 = -2

同理:

r2 = F2H = 242 - 256 = -14
r3 = 90H = 144 - 256 = -112
r4 = F8H = 248 - 256 = -8

逐项计算:

A. r1 × r2 = (-2) × (-14) = 28
B. r2 × r3 = (-14) × (-112) = 1568
C. r1 × r4 = (-2) × (-8) = 16
D. r2 × r4 = (-14) × (-8) = 112

8 位补码能表示的最大正数是 127,所以只有:

1568

超出了 8 位补码范围。

所以第26题选:

B

这题不要直接在十六进制上硬算,最快方法是先转真值,再看结果是否在 -128 ~ +127 内。

第27题:8位补码下计算 z = 2x + y/2

题意是:某字长为 8 位的计算机中,已知:

[x]补 = 11110100
[y]补 = 10110000

若:

z = 2x + y/2

z 的机器数。

先把 x、y 从补码转为真值。

x = 11110100,最高位是 1,所以是负数。它对应的无符号值是:

11110100 = F4H = 244

8 位补码真值为:

244 - 256 = -12

所以:

x = -12

y = 10110000,无符号值是:

10110000 = B0H = 176

真值为:

176 - 256 = -80

所以:

y = -80

代入表达式:

z = 2x + y/2
z = 2 × (-12) + (-80)/2
z = -24 - 40
z = -64

8 位补码中,-64 的表示是:

先写出 +64

01000000

取反加一:

10111111 + 1 = 11000000

所以:

[z]补 = 11000000

选项中写成分组形式就是:

1 1000000

所以第27题选:

A

这题要注意,y/2 对负数来说,在计算机组成原理中常按补码算术右移理解。这里 -80 / 2 = -40,能整除,不涉及向上还是向下取整的问题。

第28题:8位定点补码运算判断溢出

题意是:

x = 103
y = -25

判断下列表达式采用 8 位定点补码运算时,哪个会溢出。

8 位补码范围仍然是:

-128 ~ +127

逐项看真值结果即可。

A:

x + y = 103 + (-25) = 78

78 在范围内,不溢出。

B:

-x + y = -103 + (-25) = -128

-128 是 8 位补码可以表示的最小值,所以不溢出。

注意:很多人会误以为 -128 溢出,但 8 位补码范围是 -128 ~ +127,所以 -128 可以表示。

C:

x - y = 103 - (-25) = 128

128 超过了 8 位补码最大正数 127,所以溢出。

D:

-x - y = -103 - (-25) = -78

-78 在范围内,不溢出。

所以第28题选:

C

这题用真值判断最快。只要结果超出 -128 ~ +127,就一定溢出。

这类题的统一做法

这几题可以套一个固定流程。

第一步,看字长。
如果是 8 位补码,范围是:

-128 ~ +127

如果是 n 位补码,范围是:

-2ⁿ⁻¹ ~ 2ⁿ⁻¹ - 1

第二步,把机器数转真值。
对于 8 位补码:

最高位为 0:直接看成正数
最高位为 1:真值 = 无符号值 - 256

例如:

F2H = 242
242 - 256 = -14

第三步,先用真值算出结果。
尤其是判断溢出时,不要急着二进制硬加,真值法最快。

第四步,看结果是否超出表示范围。
8 位补码只要结果不在:

-128 ~ +127

内,就溢出。

第五步,如果题目问机器数,再把真值转回补码。
负数转补码可以用两种方法:

方法一:正数原码取反加一
方法二:真值 + 2ⁿ

比如 8 位补码表示 -64

-64 + 256 = 192
192 = C0H = 11000000

这类题真正考的不是复杂计算,而是几个基本点是否稳:补码范围、负数补码转真值、真值转补码、符号扩展、以及 C 语言整型提升规则。

答案汇总:

30:B
31:A
32:B
33:C
34:D
35:D

第30题:逻辑右移与算术右移

原机器数为:

1101 1000

题目问分别进行“逻辑右移 1 位”和“算术右移 1 位”。

逻辑右移的规则是:最高位补 0,低位移出。

1101 1000 逻辑右移 1 位
= 0110 1100

算术右移的规则是:最高位补原符号位。原数最高位是 1,所以右移后最高位仍补 1。

1101 1000 算术右移 1 位
= 1110 1100

所以结果依次是:

0110 1100,1110 1100

选 B。

这类题的关键是:逻辑右移不管符号,统一补 0;算术右移保留符号,正数补 0,负数补 1。

第31题:减法中的 CF 和 OF

题目给出减法指令:

(R1) - (R2) -> R3

已知:

R1 = FFFF FFFFH
R2 = FFFF FFF0H

先按无符号数看:

FFFF FFFFH = 2³² - 1
FFFF FFF0H = 2³² - 16

所以:

FFFF FFFFH - FFFF FFF0H = 0000 000FH

即结果为 15。

对于减法来说,CF 表示借位标志。判断方法很简单:

若无符号数 x < y,则 x - y 需要借位,CF = 1
若无符号数 x >= y,则不需要借位,CF = 0

这里:

FFFF FFFFH > FFFF FFF0H

所以不借位,CF = 0。

再看 OF。OF 是有符号溢出标志。

FFFF FFFFH 表示 -1
FFFF FFF0H 表示 -16

所以:

-1 - (-16) = 15

15 在 32 位补码范围内,不溢出,因此 OF = 0。

所以:

CF = 0,OF = 0

选 A。

这类题必须分清:CF 管无符号借位,OF 管有符号溢出。不要把结果最高位、正负号和 CF 混在一起判断。

第32题:继续考减法的 OF 和 CF

题目已经告诉:

x = 100,y = 200
执行 x - y
OF = 0,CF = 1

这其实是在提示 CF 的判定规则:减法中如果无符号意义下 x < y,则需要借位,CF = 1。

现在问:

x = 10,y = -20
执行 x - y

先看有符号结果:

10 - (-20) = 30

30 在 int 的表示范围内,所以没有有符号溢出:

OF = 0

再看 CF。CF 要从无符号角度看。

在 32 位补码机器中,-20 的机器数不是“负数”,而是一个很大的无符号数:

-20 的补码无符号解释 = 2³² - 20

所以从无符号减法角度看:

10 - (2³² - 20)

显然 10 小于 2³² – 20,需要借位,因此:

CF = 1

所以:

OF = 0,CF = 1

选 B。

这题最容易错在把 y = -20 直接当成普通数学负数去判断 CF。CF 不管有符号语义,它只看机器数的无符号减法是否借位。

第33题:int 转 short,再转 int

代码为:

int i = -32777;
short si = i;
int j = si;

统考默认环境一般按:

int:32 位
short:16 位
补码表示

16 位 short 的范围是:

-32768 ~ 32767

-32777 已经超出了 short 的范围。

先求 -32777 的低 16 位。

因为:

32777 = 32768 + 9 = 8009H

所以 32 位补码中:

-32777 = FFFF 7FF7H

赋值给 short 时,只保留低 16 位:

7FF7H

7FF7H 的最高位是 0,所以作为 short 解释时是正数:

7FF7H = 32759

再赋值给 int:

j = 32759

选 C。

这类强制类型转换题要抓住两步:长整数转短整数,截断低位;短整数转长整数,看原类型是否有符号,有符号数要符号扩展。这里截断后最高位为 0,所以扩展后仍是正数。

第34题:整数乘法运算叙述判断

题目问错误的是哪一项。

A:用阵列乘法器实现的乘运算可以在一个时钟周期内完成。
这在组成原理考法中一般认为正确。阵列乘法器属于硬件并行乘法器,可以通过组合逻辑并行产生部分积并求和,速度快,可以设计成一个时钟周期完成。

B:用 ALU 和移位器实现的乘运算无法在一个时钟周期内完成。
这通常正确。用 ALU 和移位器实现乘法,往往对应移位加法的迭代过程,每次处理一位或若干位,通常需要多个时钟周期。

C:变量与常数的乘运算可编译优化为若干移位及加减运算指令。
正确。例如:

x × 8 可以优化为 x << 3
x × 9 可以优化为 (x << 3) + x
x × 15 可以优化为 (x << 4) - x

这叫强度削弱,是常见编译优化。

D:两个变量的乘运算无法编译转换为移位及加法等指令的循环实现。
错误。两个变量相乘当然可以用软件循环实现,比如根据乘数的每一位决定是否累加被乘数,并不断移位。这正是乘法器的基本思想,只不过可以由硬件做,也可以由软件指令序列模拟。

因此错误项是 D。

这题考的不是复杂乘法算法,而是区分“硬件乘法器”“迭代移位加法”“编译优化”。看到“无法”这种绝对说法要特别警惕。

第35题:8 位补码减法与溢出

已知:

[x]补 = A3H
[y]补 = 75H

机器字长为 8 位,都是带符号整数。

先还原真值:

A3H = 1010 0011B

最高位为 1,是负数。其真值为:

A3H = 163
163 - 256 = -93

所以:

x = -93

再看 y:

75H = 0111 0101B

最高位为 0,是正数:

y = 117

数学上:

x - y = -93 - 117 = -210

但 8 位补码能表示的范围是:

-128 ~ 127

-210 超出范围,所以一定溢出:

OF = 1

再看机器实际得到的结果:

A3H - 75H
= A3H + (-75H)

75H 的相反数补码为:

75H = 0111 0101
按位取反:1000 1010
加 1:1000 1011 = 8BH

所以:

A3H + 8BH = 12EH

8 位机器只保留低 8 位:

2EH

2EH 的十进制是:

2 × 16 + 14 = 46

所以机器得到的结果是 46,但这是溢出后的错误结果。

因此:

x - y 的机器结果 = 46
OF = 1

选 D。

这题的关键是:数学真值是 -210,但机器结果按 8 位补码截断后变成 46。题目选项问的是“通过补码加减运算得到的 x – y 的值及 OF 标志”,所以要填机器运算结果和溢出标志,即 46,1。

所以在35题里面,我们知道如果两个数如果它溢出的话,实际上想要求最后输出的值是把一个数转换成补码,相当于补码的补码,对吧? 在33题里面,在超出了范围里,求第16位该如何快速求呢?我没有看懂这个式子

不是“补码的补码”这个说法最准确,而应理解为:

机器做补码加减法时,不管是否溢出,硬件都会按固定字长只保留低 n 位。溢出只是说明这个 n 位结果不能代表真实数学结果。

所以第35题的本质是:

8 位补码运算:
[x - y]补 = [x]补 + [-y]补

题目给:

[x]补 = A3H
[y]补 = 75H

要做 x - y,机器实际做的是:

[x]补 + [-y]补

[-y]补 怎么来?就是对 [y]补 求相反数的补码。

对于补码来说,一个数的相反数补码可以用:

按位取反 + 1

所以:

[y]补 = 75H = 0111 0101

[-y]补:
0111 0101 取反 = 1000 1010
1000 1010 + 1 = 1000 1011 = 8BH

于是:

A3H - 75H
= A3H + 8BH
= 1010 0011
+ 1000 1011
= 1 0010 1110

8 位机器只保留低 8 位:

0010 1110 = 2EH = 46

所以机器最后算出来的低 8 位结果是 46。

但真实数学结果是:

A3H 表示 -93
75H 表示 117

x - y = -93 - 117 = -210

8 位补码范围是:

-128 ~ 127

-210 超范围,所以发生溢出,OF = 1。

因此第35题是:

机器结果 = 46
OF = 1

也就是 D。

这里要特别区分两个东西:

真实数学结果:-210
机器低 8 位结果:46
溢出标志 OF:1

考研题如果问“补码加减运算得到的结果”,一般要写机器保留下来的 n 位结果;如果问“真值是否溢出”,再判断数学结果是否超范围。


第33题中,你没看懂的关键式子其实是在快速求“低 16 位”。

代码是:

int i = -32777;
short si = i;
int j = si;

默认按 408 常见考法:

int 是 32 位补码
short 是 16 位补码
int 转 short 时,保留低 16 位
short 转 int 时,符号扩展

所以核心问题是:

-32777 的低 16 位是多少?

方法一:用“模 2¹⁶”最快

16 位机器只保留低 16 位,本质等价于对 2¹⁶ = 65536 取模。

所以:

-32777 在 16 位中的结果
= -32777 mod 65536
= 65536 - 32777
= 32759

因此 short si 中保存的机器数对应的无符号值是 32759。

再看 32759 是否超过 32767:

32759 < 32767

所以它作为 16 位有符号 short 解释时还是正数:

si = 32759

再赋给 int,符号扩展后仍是:

j = 32759

所以选 C。

这个方法最适合考场使用。

方法二:用“越界绕回”理解

16 位 short 的范围是:

-32768 ~ 32767

而:

-32777 = -32768 - 9

它比 short 最小值还小 9。

补码溢出后会从正数最大端附近绕回来。具体是:

-32768 再减 1,会变成 32767
-32768 再减 2,会变成 32766
-32768 再减 9,会变成 32759

所以:

-32777 截断成 short 后 = 32759

这个方法甚至比算十六进制更快。

方法三:用十六进制低 16 位

先看:

32768 = 8000H
32777 = 32768 + 9 = 8009H

所以:

+32777 = 0000 8009H

要求:

-32777 的补码

32 位补码可以用:

2³² - 32777

但由于最后只要低 16 位,所以只看:

2¹⁶ - 32777
= 10000H - 8009H
= 7FF7H

也就是说:

-32777 的低 16 位 = 7FF7H

而:

7FF7H = 32759

所以最后:

j = 32759

这类题的统一做法可以记成一句话:

大类型转小类型:截断,保留低位。
小类型转大类型:扩展,有符号数符号扩展,无符号数零扩展。

第33题就是:

int -> short:保留低 16 位
short -> int:因为 short 是有符号类型,所以符号扩展

由于保留下来的低 16 位是:

7FF7H = 0111 1111 1111 0111

最高位是 0,所以符号扩展后还是正数:

0000 0000 0000 0000 0111 1111 1111 0111

因此 j = 32759

3)x和y相减后的结果存放在寄存器 D中,寄存器 D中的内容是什么?此时溢出标志OF、符号标志 SF 各是什么?

下面按图中的两道综合题来做。核心是两件事:第一题考“同一串机器码按 unsigned / int 解释不同,以及逻辑移位、算术移位的结果”;第二题考“8 位补码加减法、溢出 OF、符号 SF”。

01 题:R1 = 8000 0004H,分别按 unsigned int 和 int 解释

已知 R1 是 32 位寄存器:

R1 = 8000 0004H

写成二进制大致是:

1000 0000 0000 0000 0000 0000 0000 0100

最高位是 1,所以如果按 unsigned int 看,它只是一个很大的正数;如果按 int 补码看,它是一个负数。

1)当 x 是 unsigned int 型时

unsigned int 没有符号位,32 位全部参与数值表示。

x = 8000 0004H
  = 2³¹ + 4
  = 2147483652

所以:

x 的真值 = 2147483652

题目说 unsigned int 型的乘除法采用逻辑移位。

乘以 2,相当于逻辑左移 1 位:

8000 0004H << 1 = 0000 0008H

因为最高位的 1 被移出去了,只保留低 32 位。

所以:

2x 存放在 R1 中的机器码 = 0000 0008H

如果从数学真值看:

2 × 2147483652 = 4294967304

但 32 位 unsigned int 的表示范围是:

0 ~ 2³² - 1
= 0 ~ 4294967295

所以结果超过了 32 位范围。计算机中只保留低 32 位,相当于对 2³² 取模:

4294967304 mod 2³² = 8

因此最终寄存器中结果对应的 unsigned 真值是:

2x 的真值 = 8

再看除以 2。unsigned int 除以 2 用逻辑右移 1 位,高位补 0:

8000 0004H >> 1 = 4000 0002H

所以:

x/2 存放在 R1 中的机器码 = 4000 0002H

其 unsigned 真值为:

4000 0002H = 2³⁰ + 2 = 1073741826

所以:

x/2 的真值 = 1073741826

整理如下:

x 的类型x 的真值2x 机器码2x 真值x/2 机器码x/2 真值
unsigned int21474836520000 0008H84000 0002H1073741826

这里最容易错的是把 8000 0004H 看成负数。它只有在 int 补码解释下才是负数,在 unsigned int 解释下是正数。

2)当 x 是 int 型时

int 默认按 32 位补码解释。最高位为 1,说明它是负数。

补码转真值可以用公式:

真值 = 无符号值 - 2³²

所以:

x = 8000 0004H
  = 2147483652 - 4294967296
  = -2147483644

因此:

x 的真值 = -2147483644

题目说 int 型的乘除法采用算术移位。

先看除以 2。负数算术右移时,高位补 1:

8000 0004H 算术右移 1 位 = C000 0002H

解释为 32 位补码:

C000 0002H = 3221225474 - 4294967296
           = -1073741822

所以:

x/2 存放在 R1 中的机器码 = C000 0002H
x/2 的真值 = -1073741822

再看乘以 2。算术左移和逻辑左移在形式上都是:左移,低位补 0,高位移出。

8000 0004H << 1 = 0000 0008H

所以:

2x 存放在 R1 中的机器码 = 0000 0008H

如果按数学计算:

2x = 2 × (-2147483644)
   = -4294967288

这个数已经超出 32 位 int 的表示范围:

-2³¹ ~ 2³¹ - 1
= -2147483648 ~ 2147483647

所以发生溢出。寄存器只保存左移后的低 32 位结果,即:

0000 0008H

按 int 补码解释为:

2x 的寄存器结果真值 = 8

整理如下:

x 的类型x 的真值2x 机器码2x 结果真值x/2 机器码x/2 真值
int-21474836440000 0008H8C000 0002H-1073741822

这一问的陷阱是:int2x 数学真值应该是 -4294967288,但 32 位寄存器装不下,左移后实际保存的是 0000 0008H,再按补码解释就是 8。考研题通常问“存放在寄存器中的机器码”和“寄存器结果的真值”,要以有限字长运算后的机器码为准。


02 题:x = -68,y = -80,8 位补码加减法

题目给出:

x = -68
y = -80
A、B、C、D 都是 8 位寄存器
采用补码形式,含 1 位符号位

8 位补码表示范围是:

-128 ~ 127

1)寄存器 A 和 B 中的内容

先求 x = -68 的 8 位补码。

正数 68 的二进制为:

68 = 0100 0100B = 44H

负数补码 = 正数原码按位取反再加 1:

0100 0100
取反:1011 1011
加 1:1011 1100

所以:

-68 的补码 = 1011 1100B = BCH

因此:

A = BCH

再求 y = -80

80 = 0101 0000B = 50H

取反加 1:

0101 0000
取反:1010 1111
加 1:1011 0000

所以:

-80 的补码 = 1011 0000B = B0H

因此:

B = B0H

答案:

A = BCH
B = B0H

2)x 和 y 相加,结果存放在 C 中

计算:

x + y = -68 + (-80) = -148

但 8 位补码的范围是:

-128 ~ 127

-148 超出了表示范围,所以一定发生溢出。

用机器码加法验证:

  BC
+ B0
----
 16C

8 位寄存器只能保存低 8 位:

C = 6CH

6CH 的二进制是:

0110 1100

最高位是 0,所以符号标志:

SF = 0

两个负数相加,却得到一个正数结果,这是典型的补码溢出:

OF = 1

所以:

C = 6CH
OF = 1
SF = 0

注意,C = 6CH 按 8 位补码解释是真值 +108,这不是数学上的 -148,而是溢出后寄存器中保留下来的错误结果。

3)x 和 y 相减,结果存放在 D 中

这里默认理解为:

x - y

即:

-68 - (-80) = 12

数学结果 12 在 8 位补码范围内,所以不会溢出。

用机器码计算:

x - y = x + (-y)

已知:

y = -80

所以:

-y = +80

+80 的 8 位补码是:

0101 0000B = 50H

于是:

  BC
+ 50
----
 10C

只保留低 8 位:

D = 0CH

0CH 的二进制是:

0000 1100

最高位是 0,所以:

SF = 0

结果没有超出 -128 ~ 127,所以:

OF = 0

因此:

D = 0CH
OF = 0
SF = 0

这两题的做题规律

第一题看到 8000 0004H,不要立刻说它是负数。必须先看题目给的是 unsigned int 还是 int。同一串机器码,按 unsigned 解释是 2147483652,按 int 补码解释是 -2147483644

第二题判断 OF 时,不要只看最高位,也不要和 CF 混淆。补码有符号加法的溢出判断常用规则是:

同号相加,结果异号,则 OF = 1
异号相加,一定不溢出

对于减法:

x - y = x + (-y)

转成加法后再判断即可。

本题答案汇总:

01 题:

unsigned int:
x = 2147483652
2x 机器码 = 0000 0008H,真值 = 8
x/2 机器码 = 4000 0002H,真值 = 1073741826

int:
x = -2147483644
2x 机器码 = 0000 0008H,寄存器结果真值 = 8,发生溢出
x/2 机器码 = C000 0002H,真值 = -1073741822


02 题:

A = BCH
B = B0H

x + y:
C = 6CH
OF = 1
SF = 0

x - y:
D = 0CH
OF = 0
SF = 0

乘法指令阵列乘法实现的乘法指令以及alu和位移显示的乘法指令,这些知识点我不太清楚,能给我讲解一下吗?并且一小问,当取乘积的低n位作为乘法结果时,在判断是否溢出,你既然只取低n位,那么你又是如何知道高n位结果呢?这么多道题目下来,既然有符号整数加减,无符号整数加减,这四种运算都对于一串二进制位进行解释,那么,我们课本上介绍了那么加减法运算器是否都是可以视为这种同一种?并且乘除计算器又该如何理解呢?就像在第四题里面提到了,Alu位移器,寄存器及相应控制逻辑这些内容

可以把这部分统一理解成一句话:加减乘除运算器处理的本质都是二进制位串,所谓有符号、无符号,主要区别不在“怎么加”,而在“怎么解释结果、怎么判断溢出、乘除时是否需要符号扩展和修正”。

第 04 题里提到的“阵列乘法器”“用 ALU 和移位器实现的乘法指令”,其实是在区分两种乘法硬件实现方式:一种偏“串行迭代”,一种偏“并行硬件”。


一、先把“ALU、移位器、寄存器、控制逻辑”放到一张图里理解

组成原理里讲运算器时,不要把“运算器”只理解成一个加法器。一个典型 CPU 内部执行算术运算,大致涉及这些部件:

寄存器:保存操作数、部分结果、最终结果
ALU:做加法、减法、逻辑与或非异或、比较等
移位器:完成左移、右移、算术移位、逻辑移位
控制逻辑:决定每一步该谁工作、移几位、加不加、循环几次、结果写到哪里

比如计算乘法 x × y,如果没有专门乘法器,本质上可以拆成:

判断乘数某一位是不是 1
如果是 1,就把被乘数左移若干位后加到部分积中
然后继续检查下一位

这就需要:

寄存器保存 x、y、部分积
移位器负责 x << i 或者整体移位
ALU 负责加法
控制逻辑负责循环、判断、调度

所以题目里说“基于 ALU、位移器、寄存器及相应控制逻辑实现乘法指令”,意思不是说 ALU 本身会乘法,而是说:乘法指令虽然在指令层面是一条指令,但硬件内部用多轮加法和移位把乘法做出来。


二、没有乘法指令、ALU 移位实现乘法指令、阵列乘法器,这三者的区别

这三种情况可以按“软件实现、串行硬件实现、并行硬件实现”来理解。

第一种是没有乘法指令。这时程序里的 x * y 不能直接翻译成一条机器乘法指令,只能由编译器生成一段指令序列,例如:

初始化 result = 0
循环检查 y 的每一位
如果当前位是 1,则 result = result + x
x 左移 1 位
y 右移 1 位
循环 n 次

这时每一步都要取指、译码、执行,还要有循环跳转,所以慢。它是“软件层面用很多条指令模拟乘法”。

第二种是有乘法指令,但乘法指令内部由 ALU + 移位器 + 寄存器 + 控制逻辑实现。这时程序层面看起来有一条 MUL 指令,但 CPU 内部仍然要重复执行“移位、判断、加法”的过程。区别是这些步骤在 CPU 控制逻辑内部完成,不需要每一步都暴露成程序中的多条普通指令,所以比软件模拟快。

第三种是阵列乘法器实现的乘法指令。阵列乘法器是专门为乘法设计的组合逻辑或较高并行度硬件。它可以同时生成很多部分积,并通过加法器阵列把这些部分积快速相加。它的硬件成本更高,但速度更快。

所以考研题里常见判断是:

没有乘法指令:最慢
ALU + 移位器实现乘法指令:中间
阵列乘法器实现乘法指令:最快

这里的“最快”和“最慢”不是说某个具体 CPU 一定如此,而是从组成原理的典型模型出发:并行硬件越多,执行时间越短;软件循环越多,执行时间越长。


三、用 ALU 和移位器实现乘法,本质是什么

以无符号乘法为例,假设乘数 y 是 8 位:

y = y7 y6 y5 y4 y3 y2 y1 y0

那么:

x × y = y0 × x
      + y1 × (x << 1)
      + y2 × (x << 2)
      + ...
      + y7 × (x << 7)

如果某一位 yi = 0,对应部分积就是 0;如果 yi = 1,对应部分积就是 x << i

例如:

13 × 11
13 = 0000 1101
11 = 0000 1011

因为 11 = 8 + 2 + 1,所以:

13 × 11 = 13 × (8 + 2 + 1)
        = (13 << 3) + (13 << 1) + 13
        = 104 + 26 + 13
        = 143

这就是“移位 + 加法”实现乘法的本质。

如果是有符号乘法,情况会复杂一点。常见思路有两种:

一种是先把符号拿出来,转成绝对值做无符号乘法,最后根据符号修正结果。

负 × 正 = 负
正 × 负 = 负
负 × 负 = 正

另一种是直接基于补码做乘法,比如 Booth 算法。这类算法会根据乘数相邻位的变化决定加、减或不操作,适合补码有符号乘法。408 一般不会要求把 Booth 乘法全过程背得特别机械,但要知道:有符号乘法可以直接在补码体系下通过加减和移位实现。


四、阵列乘法器是什么,为什么快

阵列乘法器可以理解为“把手算乘法的很多步骤用硬件并行铺开”。

手算二进制乘法时,会先产生很多部分积:

        x3 x2 x1 x0
×       y3 y2 y1 y0
--------------------
        x × y0
      x × y1 左移 1 位
    x × y2 左移 2 位
  x × y3 左移 3 位
--------------------
        最终乘积

阵列乘法器会用与门生成部分积。例如 xi × yj 在二进制里就是:

xi AND yj

然后用一堆半加器、全加器把这些部分积加起来。

它的优势是并行度高,不用像“ALU + 移位器”那样一轮一轮循环 n 次。缺点是硬件面积大、成本高、功耗也可能更高。

考研中对阵列乘法器通常不考特别深的电路细节,重点是知道:

阵列乘法器:用大量硬件并行产生和累加部分积,速度快,硬件复杂
ALU + 移位器乘法:用少量硬件反复迭代,速度慢一些,硬件简单
软件模拟乘法:没有乘法指令,用多条指令完成,通常最慢

五、“只取低 n 位作为乘法结果”,为什么还能知道高 n 位

这个问题很关键。

题目说“只取低 n 位作为乘法结果”,并不等于硬件或者分析过程完全不知道高 n 位。这里要分清两个层面:

完整乘积:n 位 × n 位,理论上最多需要 2n 位保存
返回结果:某些指令或 C 语言表达式只保留低 n 位

也就是说,完整乘积本来是 2n 位,只是最终写回目标寄存器或函数返回值时只保留低 n 位。

例如 32 位乘法:

32 位 × 32 位 = 最多 64 位乘积

如果函数返回类型是 32 位 intunsigned int,那么最终只返回低 32 位。但是在判断是否溢出时,要看真实数学乘积能不能放进 32 位。如果不能放进去,即使低 32 位存在,也说明发生了溢出。

所以“如何知道高 n 位”有三种情况:

第一种,从题目分析角度,可以直接算完整 2n 位乘积。组成原理题目通常要求从机器数和真值角度分析,不是说程序运行时一定把高 n 位返回给用户。

第二种,从硬件角度,很多乘法指令内部确实会产生 2n 位乘积,只是最后根据指令格式保存其中一部分。有些体系结构还会把高位和低位分别放到两个寄存器中。例如常见教材模型里经常默认乘积寄存器可以保存双倍字长结果。

第三种,如果某个机器真的只实现“模 2ⁿ 乘法”,只给出低 n 位,且没有额外标志位或高位寄存器,那么单靠最终低 n 位确实无法还原高 n 位。因为不同的完整乘积可能具有相同的低 n 位。

例如 8 位结果只看到:

低 8 位 = FEH

它可能来自:

00FEH
01FEH
02FEH
FFFEH
...

低 8 位相同,高 8 位可以不同。所以如果硬件完全丢弃高位且不提供任何溢出标志,运行后就不能从低 n 位唯一判断高 n 位是什么。

但考研题里问“当取低 n 位作为结果时如何判断溢出”,默认是从完整 2n 位乘积判断,或者假设硬件在产生完整乘积/部分积过程中有能力检测被舍弃的高位。


六、无符号乘法只取低 n 位时,怎么判断溢出

无符号数的 n 位范围是:

0 ~ 2ⁿ - 1

两个 n 位无符号数相乘,真实结果最多需要 2n 位。

如果完整 2n 位乘积的高 n 位全为 0,说明乘积没有超过 n 位范围,可以安全放进低 n 位。

高 n 位 = 000...000  → 无符号乘法不溢出
高 n 位 ≠ 000...000 → 无符号乘法溢出

例如 8 位无符号乘法:

20 × 10 = 200

200 可以用 8 位无符号数表示:

完整 16 位:0000 0000 1100 1000
高 8 位:0000 0000
低 8 位:1100 1000

高 8 位全 0,所以不溢出。

再如:

200 × 2 = 400

400 超过 8 位无符号范围 0 ~ 255

完整 16 位:0000 0001 1001 0000
高 8 位:0000 0001
低 8 位:1001 0000

高 8 位不全为 0,所以无符号乘法溢出。最终若只保存低 8 位,会得到 90H = 144,但真实结果 400 的高位信息丢了。


七、有符号乘法只取低 n 位时,怎么判断溢出

有符号补码 n 位范围是:

-2ⁿ⁻¹ ~ 2ⁿ⁻¹ - 1

有符号乘法判断溢出不能简单看高 n 位是否全 0,因为负数的正确扩展高位应该是全 1。

规则是:

有符号乘法不溢出 ⇔ 完整 2n 位乘积的高 n 位,必须是低 n 位符号位的符号扩展

换句话说:

如果低 n 位的最高位是 0,说明低 n 位表示非负数,那么高 n 位应该全是 0。

高 n 位全 0,低 n 位最高位为 0 → 不溢出

如果低 n 位的最高位是 1,说明低 n 位表示负数,那么高 n 位应该全是 1。

高 n 位全 1,低 n 位最高位为 1 → 不溢出

否则就是有符号溢出。

举一个 8 位例子:

-2 × 3 = -6

8 位低位结果是:

FAH = 1111 1010

完整 16 位补码乘积应该是:

1111 1111 1111 1010

高 8 位是 1111 1111,正好是低 8 位符号位 1 的扩展,所以不溢出。

再看:

100 × 2 = 200

200 超过 8 位有符号范围 -128 ~ 127。完整 16 位是:

0000 0000 1100 1000

低 8 位是:

1100 1000

低 8 位最高位是 1,按 8 位补码会解释成负数 -56。如果它真的是一个合法的 8 位负数结果,那么高 8 位应该全为 1,但现在高 8 位是全 0。

高 8 位 = 0000 0000
低 8 位符号位 = 1
不符合符号扩展 → 有符号溢出

所以本题第 04 题里:

n = 32
x = 2³¹ - 1 = 7FFFFFFFH
y = 2

完整 64 位乘积:

00000000 FFFFFFFE

对无符号乘法:

高 32 位 = 00000000

高 32 位全 0,所以无符号结果放入 32 位不溢出。

对有符号乘法:

低 32 位 = FFFFFFFE
低 32 位符号位 = 1

如果它作为合法的 32 位有符号结果,64 位完整乘积的高 32 位应该是:

FFFFFFFF

但实际高 32 位是:

00000000

不符合符号扩展,所以有符号乘法溢出。

这也是这题的核心陷阱:同样的低 32 位 FFFFFFFEH,作为 unsigned 是 4294967294,没溢出;作为 signed 是 -2,但真实数学结果是 4294967294,所以 signed 溢出。


八、加减法运算器:有符号和无符号是不是可以看成同一个?

可以。对于加法和减法,核心结论就是:

有符号整数加法
无符号整数加法
有符号整数减法
无符号整数减法

底层都可以用同一个二进制加法器完成。

原因是补码体系有一个非常重要的性质:补码加减法和无符号模 2ⁿ 加减法在位级运算规则上完全一致。

比如 8 位加法器做的事情只是:

把两个 8 位二进制位串相加
保留低 8 位
产生进位标志

它不关心这两个位串是 signed 还是 unsigned。

例如:

1000 0110 + 1111 0110 = 1 0111 1100

8 位加法器只知道:

低 8 位 = 0111 1100
最高位向外有进位

至于它表示什么,要看解释方式:

unsigned: 134 + 246 = 380,低 8 位为 124,有进位
signed: -122 + (-10) = -132,低 8 位为 +124,有符号溢出

同一个加法结果,分别产生不同的“语义判断”。

对无符号加法,主要看 CF:

CF = 1 通常表示最高位产生进位,即无符号加法超过范围

对有符号加法,主要看 OF:

OF = 1 表示补码有符号溢出

判断有符号加法溢出最常用的方法是:

同号相加,结果异号 → 溢出
异号相加 → 不可能溢出

减法也可以用同一个加法器,因为:

A - B = A + (-B)

而补码里的 -B 可以通过:

B 按位取反,再加 1

实现。所以减法器通常可以设计成“加法器 + 取反控制 + 低位进位 1”。

也就是说,加法器不需要知道“这是 signed 还是 unsigned”。真正不同的是结果出来之后:

无符号减法看是否借位,常用 CF 判断
有符号减法看 OF 判断补码溢出

所以课本里的“加减法运算器”完全可以理解成同一个底层部件:同一个加法器完成位串加减,不同标志位负责不同语义解释。


九、乘除运算器是否也能像加减法一样完全视为同一个?

这里要稍微区分。

对“只取低 n 位的乘法结果”而言,有一个重要结论:

n 位乘法只看低 n 位时,有符号乘法和无符号乘法的低 n 位结果相同。

原因是低 n 位本质上都是模 2ⁿ 的乘积。

例如:

8 位下:
FEH 可以解释为 unsigned 254,也可以解释为 signed -2

如果只看低 8 位,很多时候 signed 和 unsigned 的乘积低位是一样的。

但是,如果要得到完整 2n 位乘积,高 n 位就可能不同,因为 signed 乘法需要符号扩展,unsigned 乘法需要零扩展。

比如 8 位:

FEH × 02H

如果按无符号:

254 × 2 = 508
完整 16 位 = 01FCH

如果按有符号:

-2 × 2 = -4
完整 16 位 = FFFCH

低 8 位都是:

FCH

但高 8 位不同:

无符号高 8 位 = 01H
有符号高 8 位 = FFH

所以乘法的结论是:

只要低 n 位:有符号/无符号乘法结果低位相同
要完整 2n 位:有符号/无符号乘法结果可能不同
溢出判断:有符号/无符号规则不同

这和加减法类似,但又比加减法多一层复杂性:乘法天然可能产生双倍字长结果。


十、除法为什么不能简单完全类比加法器

除法比乘法更要注意 signed 和 unsigned 的差异。

因为除法不是简单的模 2ⁿ 位级运算。加法、减法、乘法的低 n 位都和模 2ⁿ 运算关系很强,而除法会涉及商和余数, signed 和 unsigned 解释会直接改变数学意义。

比如同一串 8 位:

1111 1110

按 unsigned 是:

254

按 signed 是:

-2

那么:

254 ÷ 2 = 127
-2 ÷ 2 = -1

商完全不同。

所以除法器通常需要区分:

无符号除法:按非负整数做除法
有符号除法:先处理符号,或用补码除法规则处理,商和余数还要符合符号规则

在指令系统中,很多机器会区分 signed divide 和 unsigned divide,例如有符号除法指令、无符号除法指令。乘法也常常区分有符号乘法和无符号乘法,尤其是当结果要保留高位或双倍字长时。

因此考研里可以这样记:

加减法:底层加法器完全可共用,signed/unsigned 主要区别在标志位解释
乘法:低 n 位可共用思路,但完整 2n 位和溢出判断要区分 signed/unsigned
除法:signed/unsigned 的数学意义不同,通常需要区分处理

十一、这类题的快速做题框架

遇到这种题,先不要急着背硬件名词。先判断题目问的是哪一层。

如果问“能不能用同一个加法器实现有符号/无符号加减”,答案基本是:

能。因为底层都是二进制加法,减法转加法。
区别在解释方式和溢出标志。

如果问“无符号加减是否溢出”,重点看:

加法:最高位是否产生进位,CF
减法:是否发生借位,CF

如果问“有符号加减是否溢出”,重点看:

加法:同号相加结果异号
减法:A - B,A 和 B 异号且结果符号与 A 不同

如果问“乘法指令怎么实现”,优先按三层回答:

没有乘法指令:软件用加法、移位、循环模拟
ALU + 移位器实现:一条乘法指令内部迭代完成加法和移位
阵列乘法器实现:专用并行硬件生成和累加部分积,速度最快

如果问“只取低 n 位如何判断乘法溢出”,就看完整 2n 位乘积:

无符号:高 n 位全 0 → 不溢出;否则溢出
有符号:高 n 位是低 n 位符号位的扩展 → 不溢出;否则溢出

最后要特别记住第 04 题这种陷阱:

完整乘积 = 00000000 FFFFFFFE

unsigned:
高 32 位全 0,所以不溢出

signed:
低 32 位符号位为 1,但高 32 位不是全 1,所以溢出

这里不是“低 32 位一样,所以溢出情况一样”。恰恰相反,低位一样,但解释方式和溢出判断不同,才是这类题的考点。

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇