【组成原理-数据】定点数的编码与运算
0 必知的常用数
- (128)10 = (7F)16 = 27
- (256)10 = (FF)16 = 28
- (1024)10 = (400)16 = 210
- (32768)10 = (FFFF)16 = 215
- (65536)10 = (10000)16 = 216
- (2147483648)10 = 231
- (4294967296)10 = 232
1 定点数的编码
1.1 编码的种类
定点数编码有四种:
- 原码:最高位表示真值的符号(1 表示负,0 表示正),其余各位表示真值的绝对值
【注 1】设原码字长为 n(即有 n 位),则原码整数的表示范围为
-(2n-1-1) ≤ x ≤ +(2n-1-1)
【注 2】设原码字长为 n(即有 n 位),则原码小数的表示范围为
-(1-2-(n-1)) ≤ x ≤ +(1-2-(n-1))
【注 3】原码全 0,对应真值的最小值
-(2n-1)
;原码全 1,对应真值的最大值+(2n-1-1)
【注 4】0 的表示不唯一,分正负零(0,000,0000 和 1,000,0000)
- 反码:正数的反码与原码一样,负数的反码其数值部分全部取反
【注 1】设反码字长为 n(即有 n 位),则反码整数的表示范围为
-(2n-1-1) ≤ x ≤ +(2n-1-1)
【注 2】设反码字长为 n(即有 n 位),则反码小数的表示范围为
-(1-2-(n-1)) ≤ x ≤ +(1-2-(n-1))
【注 3】反码全 0,对应真值的最小值
-(2n-1)
;反码全 1,对应真值的最大值+(2n-1-1)
【注 4】0 的表示不唯一,分正负零(0,000,0000 和 1,111,1111)
- 补码(带符号整数):正数的补码与反码一样,负数的补码等于反码加 1
【注 1】设补码字长为 n(即有 n 位),则补码整数的表示范围为
-(2n-1) ≤ x ≤ +(2n-1-1)
【注 2】设补码字长为 n(即有 n 位),则补码小数的表示范围为
-1 ≤ x ≤ +(1-2-n)
【注 3】补码全 0,对应真值的最小值
-(2n-1)
;补码全 1,对应真值的最大值+(2n-1-1)
【注 4】0 的表示唯一(0,000,0000);无论补码有多少位,只要所有位都为 1,那么表示的真值为 -1
【注 5】若补码的符号位相同,则数值位越大码值越大
- 移码:真值基础上加上一个偏置常数(取 2n)
【注 1】设移码字长为 n(即有 n 位),则移码整数的表示范围为
-(2n-1) ≤ x ≤ +(2n-1-1)
【注 2】移码全 0,对应真值的最小值
-2n
;移码全 1,对应真值的最大值+(2n-1)
【注 3】0 的表示唯一(1,000,0000)
【注 4】移码保持了数据原有的大小顺序,移码大真值就大,移码小真值就小
真值 | 补码 | 移码 |
---|---|---|
-128 | 1000,0000 | 0000,0000 |
-127 | 1000,0001 | 0000,0001 |
-126 | 1000,0010 | 0000,0010 |
... | ... | ... |
-2 | 1111,1110 | 0111,1110 |
-1 | 1111,1111 | 0111,1111 |
0 | 0000,0000 | 1000,0000 |
1 | 0000,0001 | 1000,0001 |
2 | 0000,0010 | 1000,0010 |
... | ... | ... |
125 | 0111,1101 | 1111,1101 |
126 | 0111,1110 | 1111,1110 |
127 | 0111,1111 | 1111,1111 |
1.2 编码的转换
- 正数:
原码 --(不用变)--> 反码 --(不用变)--> 补码 --(符号位取反)--> 移码
- 负数:
原码 --(数值部分取反)--> 反码 --(直接加 1)--> 补码 --(符号位取反)--> 移码
- 负数:
原码 <--(从右往左找第一个“1”,“1”左边所有数值位取反)--> 补码
- 补码转真值:最高的符号位有负值加权,例:
[1,000,0011]补 = (-27+21+20)10 = (-125)10
【例 1】(-100)10 的编码转换(默认 8 位字长)
先化为十六进制,再转换为二进制:(100)10 = (64)16 = (0110,0100)2
(1)原码:1,110,0100
(2)反码:1,001,1011
(3)补码:1,001,1100
(4)移码:0,001,1100
【例 2】(1,000,1101)2(默认 8 位字长),若为(1)原码;(2)反码;(3)补码;(4)移码,求对应真值?
(1)原码:1,000,1101 --> 转换为十六进制:1(-),000(0),1101(13) --> 转换为十进制:(-13)10
(2)反码:1,000,1101 --> 原码:1,111,0010 --> 转换为十六进制:1(-),111(7),0010(2) --> 转换为十进制:-(16*7+2)10 = (-114)10
(3)补码:1,000,1101 --> 原码:1,111,0011 --> 转换为十六进制:1(-),111(7),0011(3) --> 转换为十进制:-(16*7+3)10 = (-115)10
(4)移码:1,000,1101 --> 补码:0,000,1101 --> 转换为十六进制:0(+),000(0),1101(13) --> 转换为十进制:(+13)10
补充:负数补码和原码的转换技巧(几秒钟内迅速转换一个 32 位二进制数!)
下面教大家一个小技巧:有时候需要对一个长达 16 位或 32 位的负定点数进行原码和补码的转换,如果一位位进行取反,这就显得太过麻烦了。实际上有非常迅速地转换方法
我们注意到十六进制与二进制之间的联系,即一位十六进制数正好对应四位二进制数,所以同时变换四位二进制数相当于变换一位十六进制数,这样一个 16 位数只需变换 4 次即可。变换操作的实质是取反操作,见下表,容易发现,取反前和取反后的值加起来恒等于 15,所以我们看到一位十六进制数就可以立即说出它取反后的结果。
取反前 | 取反后 |
---|---|
0(0000) | F(1111) |
1(0001) | E(1110) |
2(0010) | D(1101) |
3(0011) | C(1100) |
4(0100) | B(1011) |
5(0101) | A(1010) |
6(0110) | 9(1001) |
7(0111) | 8(1011) |
8(1000) | 7(0111) |
9(1001) | 6(1011) |
A(1010) | 5(0101) |
B(1011) | 4(0100) |
C(1100) | 3(0011) |
D(1101) | 2(0010) |
E(1110) | 1(0001) |
F(1111) | 0(0000) |
【例 3】一个 16 位补码 0x8F0A 的原码是多少?
【解】根据补码转原码规则,先找到该补码的第一个“1”在哪里,它所在的十六进制位数不能用上述方法,需要特殊处理。显然在最低位的“A”处出现第一个“1”,写出二进制形式:1010,按照转换规则得到:0110,即十六进制的 6。
剩余三位全部取反,“8F0”取反后为“70F”,所以对应无符号原码为 0x70F6。而对于有符号原码,最高位为符号位,答案应为 0x80F6。
其实一开始的特殊处理也是可以直接口答结果,因为容易发现,特殊处理前和特殊处理后的值相加恒等于 16。见下表:
特殊处理前 | 特殊处理后 |
---|---|
0(0000) | 不需要处理 |
1(0001) | F(1111) |
2(0010) | E(1110) |
3(0011) | D(1101) |
4(0100) | C(1100) |
5(0101) | B(1011) |
6(0110) | A(1010) |
7(0111) | 9(1001) |
8(1000) | 8(1000) |
9(1001) | 7(0111) |
A(1010) | 6(0110) |
B(1011) | 5(0101) |
C(1100) | 4(0100) |
D(1101) | 3(0011) |
E(1110) | 2(0010) |
F(1111) | 1(0001) |
【例 4】一个 32 位补码 0xFFFF FFDF 对应真值是多少?
【解】最低位的“F”需要特殊处理,转换为“1”(16 减 15)。剩余七位全部取反,“FFFF FFD”取反后为“0000 002”,所以对应原码为 0x0000 0021,真值为 -(2 * 16 + 1) = -33。
【例 5】真值 -98 转化为 32 位补码是多少?
【解】将 98 化为十六进制数 0x62,扩展成 32 位原码 0x0000 0062。最低位的“2”需特殊处理,转换为“E”(16 减 2)。剩余七位全部取反,“0000 006”取反后为“FFFF FF9”,所以对应补码为 0xFFFF FF9E。
【总结】负数补码和原码的转换技巧
前提:补码表示的是真值是负数!
(1)找到需要特殊处理的最低位,该位需要特殊处理,特殊处理前和特殊处理后的值相加恒等于 16;
(2)剩余的高位进行取反操作,取反前和取反后的值相加恒等于 15。
1.3 C 语言的强制转换
- 相同字长下,有符号数与无符号数的转换:保持位值不变,仅改变解释位值的方式
- 长字长转换短字长:多余的高位直接丢弃,低位直接赋值
- 短字长转换长字长:无符号情况下,扩展的高位部分用 0 填充;有符号情况下,扩展的高位部分用原数字符号填充
- C 语言中赋值和判断也会出现强制类型转换,常见转换路径:char-->int-->long-->double 和 float-->double(范围和精度从小到大,转换过程没有损失)
【例 1】16 位补码 0x8FA0 扩展为 32 位是 0xFFFF 8FA0。
【例 2】假设变量 i、f 和 d 的数据类型分别为 int、float 和 double,其中 f = 1.5678E3,d = 1.5E100,则下列是否为“真”?
i==(int)(float)i
:转换过程为 int-->float-->int,没有精度损失,结果为真f==(float)(int)f
:转换过程为 float-->int-->float,转换的第一步存在精度损失,结果为假f==(float)(double)f
:转换过程为 float-->double-->float,没有精度损失,结果为真d==(double)(float)d
:转换过程为 double-->float-->double,转换的第一步存在精度损失,结果为假(d+f)-f==f
:浮点数运算,f 需要先转换为 double 类型,再和 d 进行对阶,对阶过程中 f 产生精度损失,结果为假
补充:不同机器下的数据类型长度
类型 | 16 位机器 | 32 位机器 | 64 位机器 |
---|---|---|---|
char | 8 | 8 | 8 |
short | 16 | 16 | 16 |
int | 16 | 32 | 32 |
long | 32 | 32 | 32 |
long long | 64 | 64 | 64 |
float | 16 | 32 | 32 |
double | 64 | 64 | 64 |
2 定点数的运算
2.1 定点数的移位
移位有三种:算术移位、逻辑移位、循环移位。
2.1.1 算术移位(有符号数)
【规则】
- 算术移位过程中,符号位均保持不变。
- 正数的算术移位:原码、补码、反码算术移位,空位添 0
- 负数原码的算术移位:用 0 占据空位
负数的原码数值部分与真值相同,因此移位时符号位不变,其余空位添 0
- 负数反码的算术移位:空位添 1
负数的反码数值部分与负数的原码相反,因此移位时其余空位添相反的数,即为 1
- 负数补码的算术移位:算术左移,低位空位添 0;算术右移,高位空位添 1
负数的原码转补码,从右往左(从低到高)找到第一个“1”,这个“1”的左边(符号位除外)与原码相反,故空位添相反的数,即为 1;右边与原码相同,故空位仍添 0
【例】负数补码的算术移位
算术右移 1 位:1,110,0110 >> 1 = 1,111,0011
算术右移 2 位:1,110,0110 >> 2 = 1,111,1001
算术左移 1 位:1,110,0110 << 1 = 1,100,1100
算术左移 2 位:1,110,0110 << 1 = 1,001,1000
【注】补码正数的符号位为 0,左移最高位为 0 时,数据不会丢失;负数的符号位为 1,左移最高位为 1 时,数据不会丢失。
2.1.2 逻辑移位(无符号数)
【规则】
- 逻辑移位将操作数视为无符号数
- 逻辑左移:高位丢弃,低位添 0
- 逻辑右移:低位丢弃,高位添 0
2.1.3 循环移位
【规则】
- 不带进位的循环左移:高位溢出的数填充回低位,且高位溢出的数还要存入进位标志位 CF
- 不带进位的循环右移:低位溢出的数填充回高位,且低位溢出的数还要存入进位标志位 CF
- 带进位的循环左移:CF 的值填充回低位,且高位溢出的数还要存入进位标志位 CF
- 带进位的循环右移:CF 的值填充回高位,且低位溢出的数还要存入进位标志位 CF
- 循环移 n 位:相当于进行 n 次的循环移 1 位
- 一般用途:将数据的低字节数据与高字节数据互换位置
【例】一个 8 位寄存器内的数值为 0100,1011,进位标志位 CF=1,若(1)带进位循环左移一位;(2)带进位循环右移一位;(3)不带进位循环左移一位;(4)不带进位循环右移一位,结果是多少?
【注】括号内的英文表示该数值位是从 CF、数值的高位(HIGH)还是数值的低位(LOW)移进来的。
(1)带进位循环左移一位:100,1011,1 (CF);CF = 0 (HIGH)
(2)带进位循环右移一位:1 (CF),0100,101;CF = 1 (LOW)
(3)不带进位循环左移一位:100,1011,0 (HIGH);CF = 0 (HIGH)
(4)不带进位循环右移一位:1 (LOW),0100,101;CF = 1 (LOW)
2.2 定点数的加减法
2.2.1 补码的加减法
- 加法运算:补码直接相加
- 减法运算:被减数-减数,减数转换为其负数的补码,转换为加法运算进行
【例】A = 15,B = 28,计算 [A+B]补,[A-B]补
转换为二进制:A = (15)10 = (000,1111)2, B = (28)10 = (001,1100)2
[A]原= 0,000,1111, [B]原= 0,001,1100
[A]补= 0,000,1111, [B]补= 0,001,1100, [-B]补= 1,110,0100
[A+B]补 = 0,000,1111 + 0,001,1100 = 0,010,1011 = (+43)10
[A-B]补 = 0,000,1111 + 1,110,0100 = 1,111,0011 = (-13)10
2.2.2 补码加减溢出的判别
发生溢出的情况:
- 两个同号数相加,得到的结果却异号
- 两个异号数相减,得到的结果与被减数异号
【模 2 补码】有一个符号位的补码,即正常的补码。
【模 4 补码(变形补码)】有两个符号位 S1S2 的补码,“00”表示正数,“11”表示负数,如:
- -3:补码:1,101;变形补码:11,101
- +3:补码:0,011;变形补码:00,011
若两个符号位不同,“01”表示正溢出,“10”表示负溢出,最高位符号位表示真正的符号。
实际情况下,存储每个变形补码仅需一个符号位,因为无论正数还是负数,两个符号位都是一样的,只有在运算时才会出现不一样的情况。
- 溢出标志位 OF = 1 时,说明发生了溢出
- OF = 最高位(即符号位)进位 ⊕ 次高位(即数值的最高位)进位 = S1⊕ S2
- OF 位仅对于有符号数有意义!
即:最高位和次高位,一个有进位,另一个没有进位,若它们的异或值是 1,则结果就有溢出。
补码加减溢出的相关例题
【例 1】溢出的例子:0100,0000 + 0100,0000 = 1000,0000
列竖式:
运算 | 溢出 | 操作数 |
---|---|---|
. | 0100 0000 | |
(+) | 0100 0000 | |
. | 1000 0000 |
- 加黑体数位为最高位,最高位没有产生进位
- 斜体数位为次高位,次高位产生了进位
- 因此结果溢出
【例 2】溢出的例子:1000,0000 + 1000,0000 = 0000,0000
列竖式:
运算 | 溢出 | 操作数 |
---|---|---|
. | 1000 0000 | |
(+) | 1000 0000 | |
. | 1 | 0000 0000 |
- 加黑体数位为最高位,最高位产生了进位
- 斜体数位为次高位,次高位没有产生进位
- 因此结果溢出
【例 3】没有溢出的例子:1111,1111 + 0001,0000 = 0000,1111
列竖式:
运算 | 溢出 | 操作数 |
---|---|---|
. | 1111 1111 | |
(+) | 0001 0000 | |
. | 1 | 0000 1111 |
- 加黑体数位为最高位,最高位产生了进位
- 斜体数位为次高位,次高位产生了进位
- 因此结果没有溢出
补充:使用 SF 和 OF 判断补码大小关系
SF 位:补码为非负,SF = 0;补码为负,SF = 1
以cmp ah, bh
为例,a-b 测试:
OF | OF 说明 | SF | SF 说明 | 结果 |
---|---|---|---|---|
0 | 没有溢出,逻辑上真正结果的正负=实际结果的正负 | 1 | 实际结果为负 | 逻辑上真正的结果为负,(ah)<(bh) |
1 | 有溢出,逻辑上真正结果的正负≠实际结果的正负 | 1 | 实际结果为负 | 逻辑上真正的结果为非负,(ah)≥(bh) |
1 | 有溢出,逻辑上真正结果的正负≠实际结果的正负 | 0 | 实际结果为非负 | 逻辑上真正的结果为负,(ah)<(bh) |
0 | 没有溢出,逻辑上真正结果的正负=实际结果的正负 | 0 | 实际结果为非负 | 逻辑上真正的结果为非负,(ah)≥(bh) |
2.2.3 进/借位的判别
- CF 位仅对无符号数有意义!
- 加法:CF = 最高位进位输出
- 减法:CF = 最高位进位输出取反
2.3 定点数的乘除法
2.3.1 定点数乘除法的技巧
在介绍定点数乘除法规则之前,先讲一个相关技巧:当一个数乘以或除以 2 的幂次方的数时,可以使用移位运算,具体原理就不细说了。
【规则】
(1)补码:当二进制数 A 乘以 2n 时,二进制数 A 算术左移 n 位;当二进制数 A 除以 2n 时,二进制数 A 算术右移 n 位。
(2)原码:当二进制数 A 乘以 2n 时,二进制数 A 逻辑左移 n 位;当二进制数 A 除以 2n 时,二进制数 A 逻辑右移 n 位。
【例 1】32 位补码乘法运算 B052H * 0008H = ?
【解】十六进制 B052H 转成二进制:1011 0000 0101 0010,因为 8 = 23,所以需算数左移三位,即 1 0000 0101 0010 000,整理一下得到:1000 0010 1001 0000,即十六进制的 8290H(可以发现结果溢出,因为数值部分高三位都被丢弃了,原结果应为 D8290H)。
【例 2】32 位补码乘法运算 B052H / 0008H = ?
【解】十六进制 B052H 转成二进制:1011 0000 0101 0010,因为 8 = 23,所以需算数右移三位,即 111 1011 0000 0101 0,整理一下得到:1111 0110 0000 1010,即十六进制的 F60AH。
2.3.2 乘法的溢出判断
- 无符号乘法:n 位 x n 位,用 2n 位保存中间运算结果,取后 n 位为最终结果。仅当前 n 位都是 0 时不溢出。
- 有符号乘法:n 位 x n 位,用 2n 位保存中间运算结果,取后 n 位为最终结果。仅当前 n+1 位都是 0 或 1 时不溢出。
【例】32 位补码 7FFF,FFFFH 乘 2 的 64 位中间乘积结果是多少?最终结果需存入 32 位寄存器中,请问溢出了吗?
【解】中间结果是 0000,0000,FFFF,FFFEH,由于前 33 位不全为 0 或 1,所以发生了溢出。
2.3.3 原码的乘法
设[X]原=xs.x1x2...xn,[Y]原=ys.y1y2...yn,原码一位乘法 X*Y 的规则如下:
- 符号位 = xs ⊕ ys
- 部分积 = X * yi
- 部分积初值为 0。从 Y 的最低位 yn 开始,
部分积 = 部分积 + yn * |X|
,然后将部分积和 Y 逻辑右移一位。该步骤重复 n 次,进行加法运算也为 n 次
【例】x = -0.1101,y = 0.1011,进行原码一位乘法 x * y:
操作 | 通用寄存器(被乘数) | ACC(高位部分积) | MQ(低位部分积/乘数) | MQ 丢失 |
---|---|---|---|---|
初始状态,乘数 y=00.1011 | 00.1101 | 00.0000 | 1011 | |
step1. 乘数最低位为 1,ACC 加 |X| | 00.1101 | 00.1101 | 1011 | |
step1. 部分积(和乘数)逻辑右移一位 | 00.1101 | 00.0110 | 1101 | 1 |
step2. 乘数最低位为 1,ACC 加 |X| | 00.1101 | 01.0011 | 1101 | 1 |
step2. 部分积(和乘数)逻辑右移一位 | 00.1101 | 00.1001 | 1110 | 11 |
step3. 乘数最低位为 0,ACC 加 0 | 00.1101 | 00.1001 | 1110 | 11 |
step3. 部分积(和乘数)逻辑右移一位 | 00.1101 | 00.0100 | 1111 | 011 |
step4. 乘数最低位为 1,ACC 加 |X| | 00.1101 | 01.0001 | 1111 | 011 |
step4. 部分积(和乘数)逻辑右移一位 | 00.1101 | 00.1000 | 1111 | 1011 |
符号位 = 1 ⊕ 0 = 1
x * y = -0.10001111
2.3.4 补码的乘法
设[X]补=xs.x1x2...xn,[Y]补=ys.y1y2...yn,补码一位乘法 X*Y 的规则如下:
- 部分积、被乘数采用双符号位补码;乘数采用单符号位补码
- 符号位参与运算
- Y 增设辅助位 yn+1 = 0
- 部分积初值为 0。从 Y 的最低位 yn 开始:当
(ynyn+1) = (01)
,部分积 = 部分积 + [X]补
;当(ynyn+1) = (10)
,部分积 = 部分积 + [-X]补
;其他情况加 0。然后将部分积和 Y 算术右移一位 - 以上步骤重复 n+1 次,但最后一次不用移位。所以需要加法运算 n+1 次,移位 n 次
【例】x = -0.1101,y = 0.1011,进行补码一位乘法 x * y:
[x]补 = 11.0011,[-x]补 = 00.1101,[y]补 = 0.1011
操作 | 通用寄存器(被乘数) | ACC(高位部分积) | MQ(低位部分积/乘数) | MQ(辅助位) | MQ 丢失 |
---|---|---|---|---|---|
初始状态,乘数 y=00.1011 | 11.0011 [负数: 00.1101] | 00.0000 | 01011 | 0 | |
step1. 乘数最低位和辅助位为 10,ACC 加 [-X]补 | 11.0011 [负数: 00.1101] | 00.1101 | 01011 | 0 | |
step1. 部分积(和乘数)算术右移一位 | 11.0011 [负数: 00.1101] | 00.0110 | 10101 | 1 | 0 |
step2. 乘数最低位和辅助位为 11,ACC 加 0 | 11.0011 [负数: 00.1101] | 00.0110 | 10101 | 1 | 0 |
step2. 部分积(和乘数)算术右移一位 | 11.0011 [负数: 00.1101] | 00.0011 | 01010 | 1 | 10 |
step3. 乘数最低位和辅助位为 01,ACC 加 [+X]补 | 11.0011 [负数: 00.1101] | 11.0110 | 01010 | 1 | 10 |
step3. 部分积(和乘数)算术右移一位 | 11.0011 [负数: 00.1101] | 11.1011 | 00101 | 0 | 110 |
step4. 乘数最低位和辅助位为 10,ACC 加 [-X]补 | 11.0011 [负数: 00.1101] | 00.1000 | 00101 | 0 | 110 |
step4. 部分积(和乘数)算术右移一位 | 11.0011 [负数: 00.1101] | 00.0100 | 00010 | 1 | 0110 |
step5. 乘数最低位和辅助位为 01,ACC 加 [+X]补 | 11.0011 [负数: 00.1101] | 11.0111 | 00010 | 1 | 0110 |
注:最后的 MQ = 00010 的最低位为原符号位,不用
[x * y]补 = 11.01110001,x * y = -0.10001111
2.3.5 原码的除法
设[X]原=xs.x1x2...xn,[Y]原=ys.y1y2...yn,加减交替法(不恢复余数法)求 X/Y 的规则如下:
- 首先,|被除数| - |除数| = 新余数
- 若新余数为负:商 0,余数左移,然后加|除数|,得到新余数
- 若新余数为正:商 1,余数左移,然后减|除数|,得到新余数
- 以上两个步骤重复 n+1 次,最后一次若余数为负,商 0,需加上|除数|得到正确余数(余数为负,说明不够减,仅在此处恢复余数)
- 总的加法运算为 n+1 或 n+2 次,移位总次数为 n 次
【例】x = 0.1011,y = 0.1101,利用加减交替法求 x / y:
|x| = 0.1011,|y| = 0.1101,[|y|]补 = 0.1101,[-|y|]补 = 1.0011
操作 | 通用寄存器(除数) | MQ(被除数/部分余数) | MQ(商) |
---|---|---|---|
初始状态:|x|=0.1011,|y|=0.1101 | 0.1101 [负数: 1.0011] | 0.1011 | 0.0000 |
step0. |x|-|y| | 0.1101 [负数: 1.0011] | 1.1110 | 0.0000 |
step1. 部分余数为负,商 0 | 0.1101 [负数: 1.0011] | 1.1110 | 0.0000 |
step1. 部分余数和商左移一位 | 0.1101 [负数: 1.0011] | 1.1100 | 0.0000 |
step1. +|y| | 0.1101 [负数: 1.0011] | 0.1001 | 0.0000 |
step2. 部分余数为正,商 1 | 0.1101 [负数: 1.0011] | 0.1001 | 0.0001 |
step2. 部分余数和商左移一位 | 0.1101 [负数: 1.0011] | 1.0010 | 0.0010 |
step2. -|y| | 0.1101 [负数: 1.0011] | 0.0101 | 0.0010 |
step3. 部分余数为正,商 1 | 0.1101 [负数: 1.0011] | 0.0101 | 0.0011 |
step3. 部分余数和商左移一位 | 0.1101 [负数: 1.0011] | 0.1010 | 0.0110 |
step3. -|y| | 0.1101 [负数: 1.0011] | 1.1101 | 0.0110 |
step4. 部分余数为负,商 0 | 0.1101 [负数: 1.0011] | 1.1101 | 0.0110 |
step4. 部分余数和商左移一位 | 0.1101 [负数: 1.0011] | 1.1010 | 0.1100 |
step4. +|y| | 0.1101 [负数: 1.0011] | 0.0111 | 0.1100 |
step5. 部分余数为正,商 1 | 0.1101 [负数: 1.0011] | 0.0111 | 0.1101 |
step6. 部分余数为正,不需要+|y| | 0.1101 [负数: 1.0011] | 0.0111 | 0.1101 |
x / y = +0.1101,余数 = 0.0111 * 2-4
2.3.6 补码的除法
设[X]补=xs.x1x2...xn,[Y]补=ys.y1y2...yn,加减交替法求 X/Y 的规则如下:
- 部分余数、被除数、除数采用双符号位补码
- 符号位参与运算
- 首先,若 X、Y 同号,则余数 = X - Y;若 X、Y 异号,则余数 = X + Y
- 若余数与 Y 同号,则商 1,余数左移,减去 Y
- 若余数与 Y 异号,则商 0,余数左移,加上 Y
- 重复以上两个步骤 n 次,商末位恒置 1
【例】x = 0.1000,y = -0.1011,利用加减交替法求 x / y:
[x]原 = 00.1000,[x]补 = 00.1000
[y]原 = 11.1011,[y]补 = 11.0101,[-y]补 = 00.1011
操作 | 通用寄存器(除数) | MQ(被除数/部分余数) | MQ(商) |
---|---|---|---|
初始状态:x=00.1000,y=11.0101 | 11.0101 [负数: 00.1011] | 00.1000 | 0.0000 |
step0. x、y 异号,+y | 11.0101 [负数: 00.1011] | 11.1101 | 0.0000 |
step1. 部分余数与 y 同号,商 1 | 11.0101 [负数: 00.1011] | 11.1101 | 0.0001 |
step1. 部分余数和商左移一位 | 11.0101 [负数: 00.1011] | 11.1010 | 0.0010 |
step1. 部分余数-y | 11.0101 [负数: 00.1011] | 00.0101 | 0.0010 |
step2. 部分余数与 y 异号,商 0 | 11.0101 [负数: 00.1011] | 00.0101 | 0.0010 |
step2. 部分余数和商左移一位 | 11.0101 [负数: 00.1011] | 00.1010 | 0.0100 |
step2. 部分余数+y | 11.0101 [负数: 00.1011] | 11.1111 | 0.0100 |
step3. 部分余数与 y 同号,商 1 | 11.0101 [负数: 00.1011] | 11.1111 | 0.0101 |
step3. 部分余数和商左移一位 | 11.0101 [负数: 00.1011] | 11.1110 | 0.1010 |
step3. 部分余数-y | 11.0101 [负数: 00.1011] | 00.1001 | 0.1010 |
step4. 部分余数与 y 异号,商 0 | 11.0101 [负数: 00.1011] | 00.1001 | 0.1010 |
step4. 部分余数和商左移一位 | 11.0101 [负数: 00.1011] | 01.0010 | 1.0100 |
step4. 部分余数+y(商末位恒置 1) | 11.0101 [负数: 00.1011] | 00.0111 | 1.0101 |
[x/y]补 = 1.0101,余数 = 0.0111 * 2-4