定点数与浮点数的运算
定点数的加减法运算
- 整数加法:A[补] + B[补] = [A + B]补
- 小数加法:A[补] + B[补] = [A + B]补
运算过程中数值位与符号位一同运算,并将符号位产生的进位自然丢掉,例A=-1100100
,B=001101
,求A+B
使用1
2
3
4
5A[补] = 1,001110
B[补] = B[原] = 0,001101
A[补] + B[补] = (A + B)[补] = 1,001110 + 0,001101 =1,011011
A + B = - 100101python
控制台进行结果的校验:
再举几个例子,用以熟悉定点数的加减运算:
例1:A = -10010000
,B = -01010000
,求A+B
例2:1
2
3
4
5A[补] = 1,01110000
B[补] = 1,10110000
(A + B)[补] = 1,00100000 #丢弃掉符号位的进位
A + B = - 11100000A = -10010000
,B = -11010000
,求A+B
例2中发生了一个现象,即1
2
3
4
5A[补] = 1,01110000
B[补] = 1,00110000
(A+B)[补] = 0,10100000 # 注意 这里符号位为0 以及是正数了 正数的补码原码反码相同
A + B = 10100000A
、B
都为负数,相加后却产生了一个正数,原因是两个数都使用8位保存,所以产生了溢出
,那么如何判断溢出呢,我们可以约定: - 单符号位表示变成双符号位:0 => 00 1 => 11
- 双符号位产生的进位丢弃
- 结果的双符号位不同则表示溢出
上面的约定称为双符号位判断法
,使用双符号位判断法
重新在来看例2:A = -10010000
,B = -11010000
,求A+B
复习完加法运算,再来看一下定点数的减法运算,定点数减法运算其实是把它的过程转换为加法:1
2
3
4
5
6A[补] = 1,01110000
B[补] = 1,00110000
(A+B)[补] = 11,01110000 + 11,00110000 = 10,10100000
|
双符号位不同,表示溢出 - 整数减法:A[补] - B[补] = A + (-B)补
- 小数减法:A[补] - B[补] = A + (-B)补
其中-B[补]
等于B[补]
连同符号位按位取反,末位加一,举个例子
A=11001000,B=-00110100,求A-B:1
2
3
4
5A[补] = A[原] = 0,11001000
B[补] = 1,11001100
(-B)[补] = 0,00110100
A[补] - B[补] = A + (-B)[补] = 00,11001000 + 00,00110100 = 00,11111100
浮点数的加减法运算
对于浮点数的加减法运算,主要有一下几个步骤:
- 对阶,目的是使两个浮点数阶码一致,使得尾数可以进行运算,规则是阶码按小阶看齐大阶的原则
- 尾数求和
- 尾数规格化
- 舍入
- 溢出判断
接下来通过一个例子来演示这个过程,设有两个数x
、y
,其中x=0.1101 * 2^01
,y=(-0.1010) * 2^11
,并且尾数数值位的存储为4位
阶码符号位 | 阶码数值位 | 尾数符号位 | 尾数数值位 |
---|---|---|---|
00 | 0001 | 00 | 1101 |
00 | 0011 | 11 | 1010 |
第一步,按照对阶的原则,小阶看齐大阶
阶码符号位 | 阶码数值位 | 尾数符号位 | 尾数数值位 |
---|---|---|---|
00 | 0011 | 00 | 0011(01) |
00 | 0011 | 11 | 1010 |
x = 0.001101 * 2^11 ,y = (-0.1010) * 2^11 ,此时由于尾数数值位为四位存储,所以后面的01就被舍弃了 |
|||
第二步,尾数求和,使用补码进行运算,减法运算转化为加法运算:A - B = A + (-B) |
1 | x[原] = 00, 0011 |
通过第二部,可以得到以下结果:
阶码符号位 | 阶码数值位 | 尾数符号位 | 尾数数值位 |
---|---|---|---|
00 | 0011 | 11 | 1001 |
第三步,尾数规格化,对于尾数的规格化需要判断两种情况:
- S > 0 需要满足:
S[补] = 00.1xxxxxx
- S < 0 需要满足:
S[补] = 11.0xxxxxx
而第二步取得的S = 11,1001
即S<0
但是尾数的格式并不满足要求,所以需要进行左移(对应小数点右移),同时阶码相应变化,以满足规格化:左移完后,对应的阶码也需要减1,之前最高位的1
11, 1001 << 1 = 11, 0010
1
被舍弃:
阶码符号位 | 阶码数值位 | 尾数符号位 | 尾数数值位 |
---|---|---|---|
00 | 0010 | 11 | 0010 |
所以,S = (x + y)[补] = 11, 0010
,而x + y
的原码就是(x + y)[原] = - 0.1110
,x + y
的结果为:-0.1110 * 2^10
第四步 舍入,尾数规格化一般情况下都是左移,但是在特殊情况下可能需要右移,比如发生了溢出,双符号位不一致下,需要右移,右移的话还需要进行舍入操作,舍入操作为”0舍1入”,例:设S
补码为10.10110111
,此时需要进行右移:
1 | S[补] = 10.10110111 >> = 11.01011011(1) = 11.01011100 |
右移完成后记得阶码需要+1,还有一种情况是右移完成后还会溢出,例:
1 | S[补] = 01.11111111 |
注意:因为右移了两次,则阶码需要加2
第五步 溢出判断,在定点数运算过程中,双符号位不一致为溢出,而在浮点数的运算过程中,双符号位不一致不算溢出,因为在浮点数的运算过程中,尾数的双符号位可以进行右移,举个例子:x=0.11010011 * 2^1101
,y=0.11101110*2^1100
第一步:对阶,小阶向大阶对齐
阶码符号位 | 阶码数值位 | 尾数符号位 | 尾数数值位 |
---|---|---|---|
00 | 1101 | 00 | 11010011 |
00 | 1100 | 00 | 11101110 |
|
↓
阶码符号位 | 阶码数值位 | 尾数符号位 | 尾数数值位 |
---|---|---|---|
00 | 1101 | 00 | 11010011 |
00 | 1101 | 00 | 01110111 |
| | |
阶码加1对齐 尾数右移一位 0被舍去
第二步,尾数求和
1 | x 补码=原码=反码= 00.11010011 |
第三步,规格化,第四步舍入
1 | 01.01001010 >> = 00.10100101 |
第五步 溢出判断
阶码符号位 | 阶码数值位 | 尾数符号位 | 尾数数值位 |
---|---|---|---|
00 | 1101 | 00 | 10100101 |
阶码符号位一致,没有溢出,则x+y=00.10100101*2^1101
浮点数的乘除法运算
浮点数的乘除法和加减法相似,同样需要经过对阶、尾数求和、尾数规格化、舍入、溢出判断五个步骤,乘法的运算规则为:阶码相加,尾数求积
除法的运算规则为:阶码相减,尾数求商
,举个例子简单演示一下,设x = 0.11010011 * 2^1101
,y = 0.11101110 * 2^0001
,假设阶码4位,尾数8位,计算x * y
1 | x * y = (0.11010011 * 0.11101110) * r^1101+0001 = 11000100*r^1110 |