文章目录
[6.1 无符号数和有符号数](#6.1 无符号数和有符号数)
[6.1.1 无符号数](#6.1.1 无符号数)
[6.1.2 有符号数](#6.1.2 有符号数)
[6.2 数的定点表示和浮点表示](#6.2 数的定点表示和浮点表示)
[6.2.1 定点表示](#6.2.1 定点表示)
[6.2.2 浮点表示](#6.2.2 浮点表示)
[6.2.3 定点数和浮点数的比较](#6.2.3 定点数和浮点数的比较)
[6.2.5 IEEE754标准](#6.2.5 IEEE754标准)
[6.3 定点运算](#6.3 定点运算)
[6.3.1 移位运算](#6.3.1 移位运算)
[6.3.2 加减法](#6.3.2 加减法)
[6.3.3 乘法运算](#6.3.3 乘法运算)
[6.3.4 除法运算](#6.3.4 除法运算)
[6.4 浮点四则运算](#6.4 浮点四则运算)
[6.4.1 浮点加减运算](#6.4.1 浮点加减运算)
[6.4.2 浮点乘除运算](#6.4.2 浮点乘除运算)
6.1 无符号数和有符号数
6.1.1 无符号数
1、定义
所谓无符号数即没有符号的数,在寄存器中的每一位均可用来存放数值。
例如
123
就是一个 无符号数 ,±123
就是一个有 符号数,显然无符号数只能表达正数,不能表达负数。
2、表示范围
无符号的数的表示范围和**机器字长** 有关,如果机器字长为16位,那么无符号数的表示范围就是:0~65535
65535
就是216-1
。
6.1.2 有符号数
对有符号数而言,++符号的"正"、"负"机器是无法识别的++ ,但由于"正"、"负"恰好是两种截然不同的状态,++如果用"0"表示"正",用"1"表示"负"++,这样符号也被数字化了,并且规定将它放在有效数字的前面,这样就组成了有符号数。
有符号数的表示有三种方式:
- 原码
- 补码
- 反码
1、原码
原码定义如下:
例:如果是整数:
[1101]原 = 0,1101
[-1101]原 = 1,1101
使用" **,"**作为间隔。
如果是小数:
[0.1101]原 = 0.1101
[-0.1101]原 = 1.1101
使用" **."**作为间隔, 并且把原先整数位的
0
改为了符号位。
原码中有一个特殊例子,那就是0的原码。
由于0
可以表示为﹢0
和﹣0
,所以0
的原码有两种:
﹢0
:0,0
﹣0
:1,0
如果机器中采用原码做运算,会出现如下问题:
当一个正数加上一个负数的时候,符号位有可能为正也有可能为负。
相当于做了减法运算,但是计算机不擅长做减法而是擅长加法,所以需要进行一个转换。
为了避免这种情况于是出现了补码。
2、补码
补码的本质其实就是**同余**。
举个例子,在时钟 的背景下,如果想要把6
点变为3
点,有两种做法:
- 6 - 3 = 3
- 6 + 9 = 15 = 3
15点相当于3点。
所以这里6加9和减去3的效果是一样的。
补码的定义如下:
有一种更简单的方法求解:
- 对于正数x:[x]原 = [x]补
- 对于负数x :[x]补 = [x]原 符号位不变,各位取反,末位加一
例如:
- [1101]补=[1101]原 = 0,1101
- [-1101]补 = 1,0011
负数求解过程如下:
首先求解原码:[- 1101]原 = 1,1101
除了符号位1
,后面四位取反:1,0010
最后末位一个数加一1,0011
++如果遇到算数溢出,则舍去溢出部分++。
和原码不同的是,±0
的补码都是相同的,以4位为例:
- [+ 0000]补:0,0000
- [ - 0000]补:0,0000
- 0000的原码是1,0000
各位取反为:1,1111
末尾加1会发现此时变为了10,0000
++这里会发现符号位溢出了,需要去掉最高位++ ,所以[-0000]补:0,0000
最后补充一个知识点:
相反数的补码 :连同符号位,各位取反,末位加一
假设[y]补 = y0.y1y2...yn
,求[-y]补
3、反码
定义:
求解很简单:
- 正数:等同于原码
- 负数:符号位不变,各位取反
例如:
- [1101]反=[1101]原 = 0,1101
- [-1101]反 = 1,0010
4、移码
当真值使用补码表示的时候,由于符号位和数值部分一起编码,所以比较的时候很难从补码的形式上判断真实的大小。
例如数21
对应二进制的补码就是:0,10101
-21
对应二进制的补码表示是:1,01101
由于在计算机中,,
其实是不存在的,只是为了便于辨别符号和真值才写的,所以符号位也是一个二进制数 ,从代码形式上来看,就会得出1,01101 > 0,10101
。
但实际是相反的,为了便于直接进行比较,所以出现了移码。
移码的定义是在对应真值加上一个2n。
但是这里有一个更简单的方法计算:对应补码符号位取反
例如:
- [10101]移 = 1,10101
- [-10101]移 = 0,01011
这样就可以直接比较移码的大小判断真值的大小。
5、小结
计算机三种码制:
正数:[x]原 = [x]补= [x]反
负数:
- [x]补 = [x]原 符号位不变,各位取反,末尾加一
- [x]反 = [x]原 符号位不变,各位取反
正数使用,
区分,小数使用.
区分。
表示范围:(假设机器字长为8位,总共可以表示256个数)
- 原码:-127 ~ 127
- 补码:-128 ~ 127
- 反码:-127 ~ 127
- 真值: 0 - 255
6.2 数的定点表示和浮点表示
6.2.1 定点表示
所谓定点表示,就是小数点的位置是固定。
当小数点位于++数符和第一数值位之间时,机器内的数为纯小数++;
当小数点++位于数值位之后时,机器内的数为纯整数++。
在定点机中,由于小数点的位置固定不变,故当机器处理的数不是纯小数或纯整数时,必须乘上一个比例因子,否则会产生"溢出"。
比如机器字长为8位,使用定点表示
4
这个数就是0000100
使用定点表示0.5
这个数就是0.10000000
(小数点后面8位)
简单来说 定点数就是保证 位数固定不变。
6.2.2 浮点表示
①常用的科学计数法:
352.47=3.5247×102
=3524.7×10-1
=0.35247×103
浮点表示也是类似的,其格式如下:
其中:
N
:真值S
:尾数(可正可负)r
:基数(一般取 2,4,8)j
:阶码(可正可负)
举个例子:
11.0101 = 0.110101 * 210
注意:这里的 10不是十进制当中的十,而是二进制表示的 2。
S
:0.110101r
:2j
:10
1、浮点数的表现形式
浮点数的表现形式如下:
前j
位用于表示阶码 ,其中1位表示**阶符** (1
表示-
,0
表示+
),剩下用于表示真值;
后s
位用于表示尾数 ,其中1位表示数符 (1
表示-
,0
表示+
),剩下用于表示真值;
举个例子,假设阶码有4
位,尾数有8
位 , 0.110101 * 2
10可以表示为:
0,010; 0.1101010
阶符
:0(1位)- 阶码真值 :010(3位)
数符
:0(1位)尾数真值
:.1101010(7位)
使用
;
间隔尾数和阶码
其中:当小数点后面第一位为1的时候,这种为浮点数的规格化形式。
例如:N = 0.110101 * 210
2、浮点数的表示范围
以通式N= S×rj
为例,设浮点数++阶码的数值位取m 位,尾数的数值位取n位++ ,当浮点数为非规格化数时,它在数轴上的表示范围如下所示。
首先看正数区,也就需要求出最大正数 和最小正数即可确定范围。
如果是最大正数,那么阶码就应该取正数的最大值 ,m位数值为阶码代表阶码数值的最大值应该为2m-1
。
例如:阶码数值为有4位,那么最大值应该是
1111
也就是15 = 24 -1
其次,尾数 也要最大,++也就是尾数数值部分应该全为1++ ,数值部分总共有n位
,那尾数的最大值就是1-2-n
例如:尾数数值有8位,那么最大值应该是
0.11111111
也就是1-2-8
浮点数的数值只有在这两个区间(负数区和正数区)之间是有效的,超出这两个区域的都被称为溢出。
- 上溢出:浮点数阶码大于最大阶码,机器停止运算,进行中断溢出处理
- 下溢出:浮点数阶码小于最小 阶码,尾数强置 为0,按照机器零处理
3、浮点数的规格化
在浮点数中:基数r越大,表示的浮点数范围越大,但是精度会下降。
为了提高精度,一般会把尾数转为规格化数 ,++通常通过修改阶码并且将尾数左右移动的方式实现++,实现规则如下:
- 基数为2 时
- 尾数最高位为1的数是规格化数
左规
:尾数左移1
位,阶码减1
右规
:尾数右移1
位,阶码加1
- 基数为4 时
- 尾数最高2位不全为0的数是规格化数
左规
:尾数左移2
位,阶码减1
右规
:尾数右移2
位,阶码加1
- 基数为8 时
- 尾数最高3位不全为0的数是规格化数
左规
:尾数左移3
位,阶码减1
右规
:尾数右移3
位,阶码加1
注意这里的左移指的是尾数左移,实际小数点是右移的。
例如:0.0010变为0.0100就是左移1位
例:将十进制数+13/128
写成二进制定点数和浮点数(++数值部分取10位,阶码部分取4位,阶符和数符各取1位++),分别写出它在定点机和浮点机中的机器数形式。
这里只要知道
1/128
就是2-7即可,记得知道+13/128 = 1101 * 2-7
解:令x=+13/128
其二进制形式:x=0.0001101000
定点数形式:x=0.0001101000
定点数不足的位数使用0补齐,小数后面补0,整数前面补0。
浮点数规格化表示:x=0.1101000000×2-11
浮点数的表示可以根据定点数来写, 对定点数进行规格化。
定点机中 [x]原=[x]补=[x]反=0.0001101000
浮点机中 [x]原:1,0011;0.1101000000
[x]补:1,1101;0.1101000000
6.2.3 定点数和浮点数的比较
(1)++当浮点机和定点机中的数其位数相同时,浮点数的表示范围比定点数大得多++。
(2)当++浮点数为规格化数时,其精度远比定点数高++。
(3)浮点数运算要分阶码部分和尾数部分,而且运算结果都要求规格化 ,故浮点运算步骤比定点运算步骤多,运算速度比定点低,运算线路比定点复杂。
(4)在溢出的判断方法上,浮点数是对规格化数的阶码进行判断,而定点数是对数值本身进行判断。如小数定点机中的数其绝对值必须小于1,否则即"溢出",此时要求机器停止运算,进行处理。为了防止溢出,上机前必须选择比例因子,这个工作比较麻烦,给编程带来不便。而浮点数的表示范围远比定点数大,仅当"上溢"时机器才停止运算,故一般不必考虑比例因子的选择。
6.2.5 IEEE754标准
在IEE754浮点数标准中,定义的浮点数的格式如下表所示。
|------------|-----|-------|--------|--------|
| 浮点数 | 符号位 | 阶码 | 尾数 | 总位数 |
| 短实数长实数临时实数 | 111 | 81125 | 235264 | 326480 |
在IEEE754标准里面:
- 阶码 使用移码表示
- 尾数 用补码表示
这样做的目的是机器零的表示正好 可以让所有的位都是
0
,便于机器判断。
6.3 定点运算
6.3.1 移位运算
1、定义
举个简单的例子:15m = 1500cm
这就代表了15这个数字左移了2两位,左移之后空缺的地方补上了0,这就是移位运算。
在十进制中,左移一位,相当于数值大小为原来的10
倍,那么在二进制中,左移一位,相当于数值大小为原来的2
倍。
前面我们知道,++计算机中有些二进制数是代表符号位的++,那么又产生如下定义:
逻辑移位
:无符号位进行移位算数移位
:有符号位进行移位
2、算数移位规则
补位的规则如下:
|------|----------|------|
| | 码 制 | 添补代码 |
| 正数 | 原码、补码、反码 | 0 |
| 负数 | 原码 | 0 |
| 补码 | 左移添0 |
| 右移添1 |
| 反 码 | 1 |
在算数移位的过程中:++符号位不参与移动++。
举个例子:
设机器数字长为8位(含一位符号位),若A=±26
,写出++三种机器数左、右移一位和两位后的表示形式++及对应的真值,并分析结果的正确性。
首先来看正数,根据八位的字长写出其二进制形式0,0011010(左移时最高数位丢1,结果出错,右移时最低数位丢1,影响精度)
:
|----------------------|-----------|-------|
| 移位操作 | 机 器 数 | 对应的真值 |
| [A]原=[A]补=[A]反 |
| 移位前 | 0,0011010 | +26 |
| 左移一位 | 0,0110100 | +52 |
| 左移两位 | 0,1101000 | +104 |
| 右移一位 | 0,0001101 | +13 |
| 右移两位 | 0,0000110 | +6 |
接下来看负数,这里就需要根据三种码制的不同来分别分析:
|------|-----------|-----------|-----|
| 移位操作 | 机 器 数 | 对应的真值 |
| 移位前 | 原码 | 1,0011010 | -26 |
| 左移一位 | 1,0110100 | -52 |
| 左移两位 | 1,1101000 | -104 |
| 右移一位 | 1,0001101 | -13 |
| 右移两位 | 1,0000110 | -6 |
| 移位前 | 补码 | 1,1100110 | -26 |
| 左移一位 | 1,1001100 | -52 |
| 左移两位 | 1,0011000 | -104 |
| 右移一位 | 1,1110011 | -13 |
| 右移两位 | 1,1111001 | -7 |
| 移位前 | 反码 | 1,1100101 | -26 |
| 左移一位 | 1,1001011 | -52 |
| 左移两位 | 1,0010111 | -104 |
| 右移一位 | 1,1110010 | -13 |
| 右移两位 | 1,1111001 | -6 |
总结上述规律:
- 左移可能会导致结果出错(最高位丢失)
- 右移可能会导致结果精度下降(最低位丢失)
3、硬件实现左移和右移
其中(a)真值为正的三种机器数的移位操作;(b)负数原码的移位操作;(c)负数补码的移位操作;(d)负数反码的移位操作。
4、算数移位和逻辑移位的区别
有符号数的移位称为算术移位,无符号数的移位称为逻辑移位。
逻辑移位的规则是:逻辑左移时,高位移出,低位添0;逻辑右移时,低位移出,高位添0。例如,寄存器内容为01010011,逻辑左移为1010010,算术左移为00100110(最高数位"1"移丢)。
又如寄存器内容为10110010,逻辑右移为01011001。若将其视为补码,算术右移为11011001。显然,两种移位的结果是不同的。
上例中为了避免算术左移时最高数位丢1,可采用带进位(Cy)的移位,其示意图如下图所示。算术左移时,符号位移至Cy,最高数位就可避免移出。
6.3.2 加减法
1、补码加法的基本公式
前面说过,计算机通常会把减法化为加法进行计算,而把减法化为加法的做法就是使用补码。
加法公式如下:
- 整数:[A]补+[B]补=[A+B]补 (mod 2n+1)
- 小数:[A]补+[B]补=[A+B]补 (mod 2)
减法公式如下:
- 整数:[A-B]补=[A]补+[-B]补 (mod 2n+1)
- 小数:[A-B]补=[A]补+[-B]补 (mod 2)
例1:x=0.1010,y=-0.0011,用++补码的加法++求x+y
解:[x]补=0.1010,[y]补=1.1101
[x]补+[y]补=0.1010+1.1101=10.0111(溢出部分舍去)
x+y=0.0111
例2:x=0.1001,y=-0.0011,用++补码的减法++求x-y
解:[x]补=0.1001,[y]补=1.1101,[-y]补=0.0011
[x]补-[y]补=[x]补+[-y]补=0.1001+0.0011=0.1100
x-y=0.1100
2、溢出判断
例如在上面的题目中,补码做加减法的时候可能会存在溢出现象,这种溢出判断会影响实际值的大小,也就是超出了机器字长表示的范围。所以需要做溢出判断。
判断方式有两种:
(1)用一位符号做溢出判断
不难知道,只有如下两种情况才可能出现溢出:
- 正数+正数
- 负数+负数
减法统一化为加法。
如果出现溢出现象,那么AB
两位的符号位应该是相同的,当运算结果的符号位和原AB
符号位不同的时候,就是溢出。
例如:
(2)用两位符号做溢出判断
原始的符号位定义如下:
- 正:
0
- 负:
1
两位符号位的定义如下:
- 正:
00
- 负:
11
同样,如果出现溢出现象,那么AB
两位的符号位应该是相同的。
这种带有两位符号位的补码叫做**变形补码,变形补码的运算需要带上符号位。**
变形补码判断溢出的原则是:运算结果的两位符号位不同的时候,就表示溢出,否则就是不溢出。
- 正 溢出:两位符号位为
01
- 负 溢出:两位符号位为
10
无论是否溢出,两位符号位的最高位表示变形补码的真正符号。
例:设x=+1100
,y=+1000
,求6位双符号位补码之和[x+y]补。
[x]补=00,1100, [y]补=00,1000
[x+y]补=00,1100+00,1000=01,0100
[x+y]补=01,0100,其中两个符号位出现01,表示已溢出,并且为上溢出,最终结果符号为正。
验算可得:x+y = 12 + 8 = 20 ,确实为上溢出。
6.3.3 乘法运算
1、笔算乘法
设A=0.1101,B=0.1011,求A×B。
如果是笔算,可以知道:
可以看的出来,二进制的乘法其实可以概括为两个运算:加法运算 和移位运算。
加法就是加法,而移位运算实际上就是乘2n,将其稍作改动可以获得:
由此可以知道原码的计算乘法的方法,主要有两种方法:
- 原码一位乘法
- 原码两位乘法
这里的
一位
指代的是一次和一位二进制数做运算 。
那么两位就是指一次和两位二进制数做运算。
2、原码一位乘运算
在计算机中,乘法最后的结果不是有一块单独的寄存器存储的,而是分为两块:ACC(乘积高位),MQ(乘积低位)。
①乘法运算可用移位和加法来实现,两个4位数相乘,总共需要进行4次加法运算和4次 移位。
②由乘数的末位值确定被乘数是否与原部分积相加,然后右移一位,形成新的部分积;同时,乘数也右移一位,由次低位作新的末位,空出最高位放部分积的最低位。
③每次做加法时,被乘数仅仅与原部分积的高位相加,其低位被移至乘数所空出的高位位置
步骤如下:
- 首先,符号位 由乘数和被乘数的符号位做异或决定,不参与后面的真值运算。
- 高位部分首先置为0,低位部分为乘数真值
- 然后被乘数依次乘以**
乘数
各位(从低位到高位),其结果加上前一次高位部分的结果,作为高位的最终结果** - 高位部分右移一位,移出的部分补到低位部分的高位,低位部分的最低位舍去(这一点非常重要)
- 往复上述过程,直到乘数所有位数都被乘完,最终**++高位和低位合并即为最终结果++**。
比如,一开始高位置为0,也就是00.0000
,低位为乘数真值,也就是1011
。
先做加法运算 ,被乘数1101
乘以乘数最低位1
答案就是1101
,结果加上前一次高位就是00.1101
。
接下来做移位运算 ,高位右移一位:00.0110
1;低位右移并且补位:1110
1
。
3、原码两位乘运算
原码两位乘与原码一位乘一样,符号位的运算和数值部分是分开进行的,但原码两位乘是用两位乘数的状态来决定新的部分积如何形成,因此可提高运算速度。
思路还是和一位乘一样,一位乘每次值乘一个二进制位数,也就是只有0
, 1
,两位乘就有四种情况:
|-----|------------|
| 乘数 | 新的部分积 |
| 0 0 | 加上0倍的|x| |
| 0 1 | 加上1倍的|x| |
| 1 0 | 加上2倍的|x| |
| 1 1 | 加上3倍的|x| |
上面四种情况里面,++0倍就是加上0,1倍就是加上原数,2倍相当于原数直接左移一位++ ,只有3倍处理起来比较麻烦,在计算机中可以这样操作:++原数先乘以4(左移两位),再减去1倍的原数(转为补码就变成了加法)++。
4、补码一位乘运算
6.3.4 除法运算
1、笔算除法分析
笔算除法如下:
和正常十进制的除法运算类似,特点可以归纳为:
- 每次上商都是通过比较余数(被除数)和除数的大小来确定商为1还是0。
- 例如:第一步中
0.1101
作为除数,大于被除数0.1011
,所以第一位上商为0
- 每一次做减法运算,余数(被除数)不动,低位补
0
,再减去右移后的除数。 - 上商的位置不固定(说实话我也不懂这句话是什么意思)
商符
单独处理(也就是做异或运算)
小数定点除法运算对于被除数和除数有一定的约束:0 < |被除数| ≤ |除数|
2、原码除法
原码除法有两种方法:
- 恢复余数法
- 加减交替法
(1)恢复余数法
特点:当余数为负数的时候,加上除数,让余数恢复为原来的余数。
步骤:
- 符号位单独按两数符号异或求得;参与运算的是绝对值的补码
- 判溢出, 要求|被除数| < |除数| (对小数而言)(如果是整数,则要求|被除数| > |除数| );
- 被除数减去除数,(加上除数的补码)
- ++若所得余数为正,相应位上商为1,余数左移一位,减去[y]补;若余数为负,相应位上商为0,余数加上除数(恢复余数),再左移一位,加上[-y]补;++
- 重复第4步,直到求得所要求的商为止(移n次)
- 若最后一步余数为负,则需要恢复余数。
举个例子:
例:已知:x=-0.1011,y=-0.1101,求:[x÷y]原
解:首先写出x和y的原码补码:[x]原=1.1011
,[y]补=1.0011
,[y]原=1.1101
|------------------------|---------|--------------------------------|
| 被除数(余数) | 商 | 说 明 |
| 0.1011 + 1.0011 | 0.0000 | +[-y*]补(减去除数) |
| 1.1110 + 0.1101 | 0 | 余数为负,上商0 恢复余数+[y*]补 |
| 0.1011 1.0110 + 1.0011 | 0 | 被恢复的被除数 左移1位 +[-y*]补(减去除数) |
| 0.1001 1.0010 + 1.0011 | 01 01 | 余数为正,上商1 左移1位 +[-y*]补(减去除数) |
| 0.0101 0.1010 +1.0011 | 011 011 | 余数为正,上商1 左移1位 +[-y*]补(减去除数) |
| 1.1101 + 0.1101 | 0110 | 余数为负,上商0 恢复余数+[y*]补 |
| 0.1010 1.0100 + 1.0011 | 0110 | 被恢复的被除数 左移1位 +[-y*]补(减去除数) |
| 0.0111 | 01101 | 余数为正,上商1 |
符号位由除数和被除数决定,最后可得,商值为0.1101
。
四位小数,做
五次
加法运算,其中最后一次为矫正作用。
(2) 加减交替法
所谓加减交替法,也就是不做余数的回复,通过先移位的方式来避免恢复余数,过程如下:
举个例子:
例:已知:x=-0.1011,y=0.1101,求:[x÷y]原
解:首先写出x和y的原码补码:[x]原=1.1011
,[-y]补=1.0011
,[y]原=1.1101
这里是无论上商为多少,都是先做移位运算,再根据上商做加法
- 上商0:+[y*]补
- 上商1:+[-y*]补
|------------------------|-----------|-------------------------------|
| 被除数(余数) | 商 | 说 明 |
| 0.1011 + 1.0011 | 0.0000 | +[-y*]补(减除数) |
| 1.1110 1.1100 + 0.1101 | 0 0 | 余数为负,上商0 ← 1位 +[y*]补 (加除数) |
| 0.1001 1.0010 + 1.0011 | 01 01 | 余数为正,上商1 ← 1位 +[-y*]补(减除数) |
| 0.0101 0.1010 + 1.0011 | 011 011 | 余数为正,上商1 ← 1位 +[-y*]补(减除数) |
| 1.1101 1.1010 + 0.1101 | 0110 0110 | 余数为负,上商0 ← 1位 +[y*]补 (加除数) |
| 0.0111 | 01101 | 余数为正,上商1 |
最后答案还是相同的:0.1101
3、补码除法
补码除法常采用加减交替法。
算法规则如下:
- 符号位参加运算,除数与被除数均用双符号补码表示。
- ++被除数与除数同号 ,被除数减去 除数;被除数与除数异号 ,被除数加上除数++。
- ++余数与除数同号 ,商上1 ,余数左移一位减去除数; 余数与除数异号 ,商上0,余数左移一位加上除数++。(注意:余数左移加上或减去除数后就得到了新余数。)
- 采用校正法包括符号在内,重复n+1次3
注意,使用此运算规则,需要修正商符, 商的末位恒置1。
简化可得:
|---------------|----|
| [x]补与[y]补 | 商值 |
| 同号 | 1 |
| 异号 | 0 |
关于商符:
在小数定点除法中,被除数的绝对值必须小于除数的绝对值,否则商大于1而溢出。因此:
- 当[x]补与[y]补同号 时,[x]补-[y]补所得的余数[R0]补与[y]补异号,商上"0",恰好与商的符号(正)一致;
- 当[x]补与[y]补异号 时,[x]补+[y]补所得的余数[R0]补与[y]补同号,商上"1",这也与商的符号(负)一致。
可见,商符是在求商值过程中自动形成的。
此外,商的符号还可用来判断商是否溢出。例如:
- 当[x]补与[y]补同号时,若[R0]补与[y]补同号,上商"1",即溢出。
- 当[x]补与[y]补异号时,若[R0]补与[y]补异号,上商"0",即溢出。
当然,对于小数补码运算,商等于"-1"应该是允许的,但这需要特殊处理,为简化问题,这里不予考虑。
举个例子:
例:已知:x=-0.1001, y=+0.1101 求: [x÷y]补
解:[x]补=1.0111,[y]补=0.1101,[-y]补=1.0011
|------------------------|------------|-----------------------------------|
| 被除数(余数) | 商 上商 | 说 明 |
| 1.0111+ 0.1101 | 0.0000 | [x]补与[y]补异号,+[y]补 |
| 0.0100 0.1000 + 1.0011 | 1 1 | [R]补与[y]补同号,上商1 ← 1位 +[-y]补 |
| 1.1011 1.0110 + 0.1101 | 10 10 | [R]补与[y]补异号,上商0 ← 1位 +[y]补 |
| 0.0011 0.0110 + 1.0011 | 101 101 | [R]补与[y]补同号,上商1 ← 1位 +[-y]补 |
| 1.1001 1.0010 | 1010 10101 | [R]补与[y]补异号,上商0 ← 1位,末位商恒置"1" |
所以[x÷y]补=1.0101
6.4 浮点四则运算
6.4.1 浮点加减运算
首先我们需要知道浮点数的形式:
x = S * r j
由于浮点数尾数的小数点均固定在第一数值位前,尾数的加减运算规则与定点数完全相同 。但由于其阶码的大小又直接反映尾数有效值的小数点位置,++因此当两浮点数阶码不等时,因两尾数小数点的实际位置不一样++,尾数部分无法直接进行加减运算。因此,浮点数加减运算必须按以下n步进行:
①对阶:使两数的阶码位置对齐。
②尾数求和:将对阶后的两尾数按定点加减运算规则求和(差)。
③规格化:为增加有效数字的位数,提高运算精度,必须将求和(差)后的尾数规格化。
④舍入:为提高精度,要考虑尾数右移时丢失的数值位。
⑤判断结果:即判断结果是否溢出。
1、对阶
对阶的目的是使两操作数的小数点位置对齐 ,即使两数的阶码相等 。为此,首先要求出阶差,再按小阶向大阶看齐 的原则,使阶小的尾数向右移位,每右移一位,阶码加1 ,直到两数的阶码相等为止。右移的次数正好等于阶差。++尾数右移时可能会发生数码丢失,影响精度++。
例如,两浮点数**x=0.1101×201
,y=(-0.1010)×211
** ,求x+y。
很明显这里y的阶码比较大,所以这里需要转换的是x的阶码,由01
变为11
,也就是从1
变成了3
,尾数应该右移两位,所以0.1101
变为0.0011
。此时x=0.0011×211
。
2、尾数求和
将对阶后的两个尾数按定点加(减)运算规则进行运算。
eg:如上例中的两数对阶后得:
[x]补=00,11;00.0011
[y]补=00,11;11.0110
则[Sx+Sy]补=00.0011 +11.0110=11.1001
即[x+y]补=00,11;11.1001
3、规格化
由第二章可知,尾数S的规格化形式为
如果采用双符号位的补码,则
- 当S>0时,其补码规格化形式为:[S]补=00.1××...×
- 当S<0时,其补码规格化形式为:[S]补=11.0××...×
对S<0时,有两种情况需特殊处理。
①S=-1/2,则[S]补=11.100...0。对于补码而言,它不满足于上面的规格化表示式。为了便于硬件判断,特规定-1/2
是规格化的数(对补码而言)。
②S=-1,则[S]补=11.000...0。因小数补码允许表示-1,故**-1
视为规格化的数**。
注:规格化又分左规和右规两种。
(1)左规。当尾数出现00.0××...×或11.1××...×时,需左规。左规时尾数左移一位,阶码减1,直到符合补码规格化表示式为止。
如上例求和结果为:
[x+y]补=00,11;11.1001
++尾数的第一数值位与符号位相同,需左规,即将其左移一位,同时阶码减1,++ 得[x+y]补=00,10;11.0010。
(2)右规。当尾数出现01.××...×或10.××...×时,表示尾数溢出,这在定点加减运算中是不允许的,但在浮点运算中这不算溢出,++可通过右规处理。右规时尾数右移一位,阶码加1++。
4、舍入
在对阶和右规的过程中,可能会将尾数的低位丢失,引起误差,影响了精度,为此可用舍入法来提高尾数的精度。常用的舍入方法有三种。
(1)截去法:将多余的位截去,剩下的位不变。其最大误差接近于数据最低位上的1。
特点:有舍无入,具有误差积累。
(2)"0舍1入"法:"0舍1入"法类似于十进制运算中的"四舍五入"法,即在尾数右移时,被移去的最高数值位为0,则舍去;被移去的最高数值位为1,则在尾数的末位加1。这样做可能使尾数又溢出,此时需再做一次右规。
特点:其最大误差是最低位上的-1/2到接近于1/2之间,正误差可以和负误差抵消。是比较理想的方法,但实现起来比较复杂。
(3)"恒置1"法:尾数右移时,不论丢掉的最高数值位是"1"或"0",都使右移后的尾数末位恒置"1"。这种方法同样有使尾数变大和变小的两种可能。
特点:尽管误差范围扩大了,但正负误差可以相互抵消,从统计角度,平均误差为0。因此最后运算结果的准确性提高了。
5、判断溢出
- 阶码[j]补=01,××...×为上溢。
- 阶码[j]补=10,××...×为下溢,按机器零处理。
阶符为"01"时,需做溢出处理。
6、完整运算
6.4.2 浮点乘除运算
两个浮点数相乘,++其乘积的阶码应为相乘两数的阶码之和++ ,++其乘积的尾数应为相乘两数的尾数之积++。
两个浮点数相除,++商的阶码为被除数的阶码减去除数的阶码++ ,++其尾数为被除数的尾数除以除数的尾数所得的商++。
步骤如下:
- 阶码运算
- 尾数运算
- 规格化
- 舍入处理