计算机组成原理第六章 计算机的运算方法

文章目录

[6.1 无符号数和有符号数](#6.1 无符号数和有符号数)

[6.1.1 无符号数](#6.1.1 无符号数)

[6.1.2 有符号数](#6.1.2 有符号数)

1、原码

2、补码

3、反码

4、移码

5、小结

[6.2 数的定点表示和浮点表示](#6.2 数的定点表示和浮点表示)

[6.2.1 定点表示](#6.2.1 定点表示)

[6.2.2 浮点表示](#6.2.2 浮点表示)

1、浮点数的表现形式

2、浮点数的表示范围

3、浮点数的规格化

[6.2.3 定点数和浮点数的比较](#6.2.3 定点数和浮点数的比较)

[6.2.5 IEEE754标准](#6.2.5 IEEE754标准)

[6.3 定点运算](#6.3 定点运算)

[6.3.1 移位运算](#6.3.1 移位运算)

1、定义

2、算数移位规则

3、硬件实现左移和右移

4、算数移位和逻辑移位的区别

[6.3.2 加减法](#6.3.2 加减法)

1、补码加法的基本公式

2、溢出判断

[6.3.3 乘法运算](#6.3.3 乘法运算)

1、笔算乘法

2、原码一位乘运算

3、原码两位乘运算

4、补码一位乘运算

[6.3.4 除法运算](#6.3.4 除法运算)

1、笔算除法分析

2、原码除法

3、补码除法

[6.4 浮点四则运算](#6.4 浮点四则运算)

[6.4.1 浮点加减运算](#6.4.1 浮点加减运算)

1、对阶

2、尾数求和

3、规格化

4、舍入

5、判断溢出

6、完整运算

[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、补码 补码的本质其实就是**[同余](https://www.zhihu.com/search?q=%E5%90%8C%E4%BD%99&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22article%22%2C%22sourceId%22%3A%22682261491%22%7D "同余")**。 举个例子,在**时钟** 的背景下,如果想要把`6`点变为`3`点,有两种做法: * 6 - 3 = 3 * 6 + 9 = 15 = 3 > 15点相当于3点。 所以这里6加9和减去3的效果是一样的。 补码的定义如下: ![](https://file.jishuzhan.net/article/1790850522027134978/0fd6cc1b48e2b4b2d547eb94ee604216.webp) ![](https://file.jishuzhan.net/article/1790850522027134978/faaffd0b712d13f673fcafb8b7298a28.webp) 有一种更简单的方法求解: * 对于**正数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\]补 ![](https://file.jishuzhan.net/article/1790850522027134978/1d29231d77223ff620e77edc351ca322.webp) ##### 3、反码 定义: ![](https://file.jishuzhan.net/article/1790850522027134978/0829e99599707e6cbefa61c961400445.webp) ![](https://file.jishuzhan.net/article/1790850522027134978/3431a034976ac439e271963dbab7b367.webp) 求解很简单: * **正数**:等同于原码 * **负数**:符号位不变,各位取反 例如: * \[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 定点表示 所谓定点表示,**就是小数点的位置是固定**。 ![](https://file.jishuzhan.net/article/1790850522027134978/5e79d2ae0034a0ea94af4c804efdc81a.webp) 当小数点位于++数符和第一数值位之间时,机器内的数为**纯小数**++; 当小数点++位于数值位之后时,机器内的数为**纯整数**++。 在定点机中,由于小数点的位置固定不变,故当机器处理的数不是纯小数或纯整数时,必须乘上一个**比例因子**,否则会产生"溢出"。 > 比如机器字长为8位,使用定点表示 `4`这个数就是 `0000100` > 使用定点表示 `0.5`这个数就是 `0.10000000`(小数点后面8位) > 简单来说 [定点数](https://www.zhihu.com/search?q=%E5%AE%9A%E7%82%B9%E6%95%B0&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22article%22%2C%22sourceId%22%3A%22682261491%22%7D "定点数")就是保证 **位数固定不变**。 #### 6.2.2 浮点表示 ①常用的[科学计数法](https://www.zhihu.com/search?q=%E7%A7%91%E5%AD%A6%E8%AE%A1%E6%95%B0%E6%B3%95&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22article%22%2C%22sourceId%22%3A%22682261491%22%7D "科学计数法"): 352.47=3.5247×102 =3524.7×10-1 =0.35247×103 浮点表示也是类似的,其格式如下: ![](https://file.jishuzhan.net/article/1790850522027134978/93f1f72df54c7c6e3e307d24fef8e5b1.webp) 其中: * `N` :真值 * `S` :尾数(可正可负) * `r` :基数(一般取 2,4,8) * `j` :阶码(可正可负) 举个例子: 11.0101 = 0.110101 \* 2**10** > 注意:这里的 **10**不是十进制当中的十,而是二进制表示的 **2**。 * `S` :0.110101 * `r` :2 * `j` :10 ##### 1、浮点数的表现形式 浮点数的表现形式如下: ![](https://file.jishuzhan.net/article/1790850522027134978/9f0947210f777f5e978310a2cbb77661.webp) 前`j`位用于表示**阶码** ,其中1位表示**[阶符](https://www.zhihu.com/search?q=%E9%98%B6%E7%AC%A6&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22article%22%2C%22sourceId%22%3A%22682261491%22%7D "阶符")** (`1`表示`-`,`0`表示`+`),剩下用于表示**真值**; 后`s`位用于表示**尾数** ,其中1位表示**数符** (`1`表示`-`,`0`表示`+`),剩下用于表示**真值**; 举个例子,假设**阶码有`4`位,尾数有`8`位** ,` 0.110101 * 2`**10**可以表示为: 0,0**10**; 0.1101010 * `阶符` :0(1位) * [阶码真值](https://www.zhihu.com/search?q=%E9%98%B6%E7%A0%81%E7%9C%9F%E5%80%BC&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22article%22%2C%22sourceId%22%3A%22682261491%22%7D "阶码真值") :010(3位) * `数符` :0(1位) * `尾数真值` :.1101010(7位) > **使用`;`间隔尾数和阶码** > **其中:当小数点后面第一位为1的时候,这种为浮点数的规格化形式。** > 例如:N = 0.110101 \* 210 ##### 2、浮点数的表示范围 以通式`N= S×rj`为例,设浮点数++阶码的数值位取**m** 位,尾数的数值位取**n**位++ ,当浮点数为[非规格化数](https://www.zhihu.com/search?q=%E9%9D%9E%E8%A7%84%E6%A0%BC%E5%8C%96%E6%95%B0&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22article%22%2C%22sourceId%22%3A%22682261491%22%7D "非规格化数")时,它在数轴上的表示范围如下所示。 ![](https://file.jishuzhan.net/article/1790850522027134978/00fd3d6fc9f8dc7bd6f45f75269d0ef5.webp) 首先看正数区,也就需要求出**最大正数** 和**最小正数**即可确定范围。 如果是最大正数,那么阶码就应该取**正数的最大值** ,m位数值为阶码代表阶码数值的最大值应该为`2m-1`。 > 例如:阶码数值为有4位,那么最大值应该是 `1111`也就是 `15 = 24 -1` 其次,**尾数** 也要最大,++也就是尾数数值部分应该全为1++ ,数值部分总共有`n位`,那尾数的最大值就是`1-2-n` > 例如:尾数数值有8位,那么最大值应该是 `0.11111111`也就是 `1-2-8` 浮点数的数值只有在这两个区间(负数区和正数区)之间是有效的,超出这两个区域的都被称为**溢出**。 * **上溢出**:[浮点数阶码](https://www.zhihu.com/search?q=%E6%B5%AE%E7%82%B9%E6%95%B0%E9%98%B6%E7%A0%81&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22article%22%2C%22sourceId%22%3A%22682261491%22%7D "浮点数阶码")大于最**大**阶码,机器停止运算,进行中断溢出处理 * **下溢出**:浮点数阶码小于最**小** 阶码,尾数**强置** 为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)浮点数运算要分阶码部分和尾数部分,而且**运算结果都要求规格化** ,故[浮点运算](https://www.zhihu.com/search?q=%E6%B5%AE%E7%82%B9%E8%BF%90%E7%AE%97&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22article%22%2C%22sourceId%22%3A%22682261491%22%7D "浮点运算")步骤比定点运算步骤多,运算速度比定点低,运算线路比定点复杂。 (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、硬件实现左移和右移 ![](https://file.jishuzhan.net/article/1790850522027134978/00277e9a3c97a307d736b37f320cfbe9.webp) 其中(a)真值为正的三种机器数的移位操作;(b)负数原码的移位操作;(c)负数补码的移位操作;(d)负数反码的移位操作。 ##### 4、算数移位和逻辑移位的区别 有符号数的移位称为算术移位,无符号数的移位称为逻辑移位。 逻辑移位的规则是:逻辑左移时,高位移出,低位添0;逻辑右移时,低位移出,高位添0。例如,寄存器内容为01010011,逻辑左移为1010010,算术左移为00100110(最高数位"1"移丢)。 又如寄存器内容为10110010,逻辑右移为01011001。若将其视为补码,算术右移为11011001。显然,两种移位的结果是不同的。 上例中为了避免算术左移时最高数位丢1,可采用带进位(Cy)的移位,其示意图如下图所示。算术左移时,符号位移至Cy,最高数位就可避免移出。 ![](https://file.jishuzhan.net/article/1790850522027134978/30c1ac4da3dd4c3a8574c81991fc4c15.webp) #### 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`符号位不同的时候,就是溢出**。 例如:![](https://file.jishuzhan.net/article/1790850522027134978/6ea441999446f0c82031751078c711ad.webp) **(2)用两位符号做溢出判断** 原始的符号位定义如下: * 正:`0` * 负:`1` 两位符号位的定义如下: * 正:`00` * 负:`11` 同样,如果出现溢出现象,那么`AB`两位的符号位应该是相同的。 这种带有两位符号位的补码叫做**[变形补码](https://www.zhihu.com/search?q=%E5%8F%98%E5%BD%A2%E8%A1%A5%E7%A0%81&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22article%22%2C%22sourceId%22%3A%22682261491%22%7D "变形补码"),变形补码的运算需要带上符号位。** 变形补码判断溢出的原则是:运算结果的**两位符号位不同**的时候,就表示溢出,否则就是不溢出。 * **正** 溢出:两位符号位为`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。 如果是笔算,可以知道: ![](https://file.jishuzhan.net/article/1790850522027134978/a1cfddfb447a14db364fd7db0d2a6b2d.webp) 可以看的出来,二进制的乘法其实可以概括为两个运算:**加法运算** 和**移位运算**。 加法就是加法,**而移位运算实际上就是乘2n**,将其稍作改动可以获得: ![](https://file.jishuzhan.net/article/1790850522027134978/d9ffb14715e10aa24802d21f90208ede.webp) 由此可以知道原码的计算乘法的方法,主要有两种方法: * 原码一位乘法 * 原码两位乘法 > **这里的`一位`指代的是一次和一位二进制数做运算** 。 > 那么两位就是指一次和两位二进制数做运算。 ##### 2、原码一位乘运算 在计算机中,乘法最后的结果不是有一块单独的寄存器存储的,而是分为两块:**ACC(乘积高位),MQ(乘积低位)**。 ![](https://file.jishuzhan.net/article/1790850522027134978/e1827631408aabcb73186f6f1722dbdf.webp) ①乘法运算可用移位和加法来实现,两个4位数相乘,总共需要进行4次加法运算和4次 移位。 ②由乘数的末位值确定被乘数是否与原部分积相加,然后右移一位,形成新的部分积;同时,乘数也右移一位,由次低位作新的末位,空出最高位放部分积的最低位。 ③每次做加法时,被乘数仅仅与原部分积的高位相加,其低位被移至乘数所空出的高位位置 步骤如下: * 首先,**符号位** 由乘数和被乘数的符号位做**异或**决定,不参与后面的真值运算。 * 高位部分首先置为0,低位部分为**乘数真值** * 然后**被乘数**依次乘以**`乘数`各位(从低位到高位),其结果加上前一次高位部分的结果,作为高位的最终结果** * **高位部分右移一位,移出的部分补到低位部分的高位,低位部分的最低位舍去**(这一点非常重要) * 往复上述过程,直到乘数所有位数都被乘完,最终**++高位和低位合并即为最终结果++**。 比如,一开始高位置为0,也就是`00.0000`,低位为乘数真值,也就是`1011`。 先做**加法运算** ,被乘数`1101`乘以乘数最低位`1`答案就是`1101`,结果加上前一次高位就是`00.1101`。 接下来做**移位运算** ,高位右移一位:`00.0110`**1**;低位右移并且补位:**1**`110`**`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、补码一位乘运算 ![](https://file.jishuzhan.net/article/1790850522027134978/257a7c5010a67f5506cd9a76e9d46c7f.webp) #### 6.3.4 除法运算 ##### 1、笔算除法分析 笔算除法如下: ![](https://file.jishuzhan.net/article/1790850522027134978/e7f96cf0afd9c9a2d8d557b9328f46a7.webp) 和正常十进制的除法运算类似,特点可以归纳为: * 每次**上商**都是通过**比较余数(被除数)和除数的大小**来确定商为1还是0。 * 例如:第一步中`0.1101`作为除数,大于**被除数** `0.1011`,所以第一位上商为`0` * 每一次做减法运算,余数(被除数)不动,低位补`0`,**再减去右移后的除数**。 * 上商的位置不固定(说实话我也不懂这句话是什么意思) * **`商符`单独处理(也就是做异或运算)** > 小数定点除法运算对于被除数和除数有一定的约束:0 \< \|被除数\| ≤ \|除数\| ##### 2、原码除法 原码除法有两种方法: * 恢复余数法 * [加减交替法](https://www.zhihu.com/search?q=%E5%8A%A0%E5%87%8F%E4%BA%A4%E6%9B%BF%E6%B3%95&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22article%22%2C%22sourceId%22%3A%22682261491%22%7D "加减交替法") **(1)恢复余数法** **特点**:当余数为负数的时候,加上除数,让余数恢复为原来的余数。 **步骤**: 1. 符号位单独按两数符号异或求得;参与运算的是绝对值的补码 2. 判溢出, 要求\|被除数\| \< \|除数\| (对小数而言)(如果是整数,则要求\|被除数\| \> \|除数\| ); 3. 被除数减去除数,(**加上除数的补码**) 4. ++若所得余数为正,相应位上商为1,余数左移一位,减去\[y\]补;若余数为负,相应位上商为0,余数加上除数(恢复余数),再左移一位,加上\[-y\]补;++ 5. 重复第4步,直到求得所要求的商为止(移n次) 6. 若最后一步余数为负,则需要恢复余数。 举个例子: 例:已知: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. **符号位参加运算**,除数与被除数均用双符号补码表示。 2. ++被除数与除数**同号** ,被除数**减去** 除数;被除数与除数**异号** ,被除数**加上**除数++。 3. ++余数与除数**同号** ,商上**1** ,余数左移一位减去除数; 余数与除数**异号** ,商上**0**,余数左移一位加上除数++。(注意:余数左移加上或减去除数后就得到了新余数。) 4. 采用校正法包括符号在内,重复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 浮点[四则运算](https://www.zhihu.com/search?q=%E5%9B%9B%E5%88%99%E8%BF%90%E7%AE%97&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22article%22%2C%22sourceId%22%3A%22682261491%22%7D "四则运算") #### 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的规格化形式为 ![](https://file.jishuzhan.net/article/1790850522027134978/82a746db907933847cced4e1535eeec9.webp) 如果采用双符号位的补码,则 1. **当S\>0时,其补码规格化形式为:\[S\]补=00.1××...×** 2. **当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.1**001** ++尾数的第一数值位与符号位相同,需左规,即将其左移一位,同时阶码减1,++ 得\[x+y\]补=00,10;11.**001**0。 (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、完整运算 ![](https://file.jishuzhan.net/article/1790850522027134978/9c98178a5dd18de98a27a0e57a98518e.webp) #### ![](https://file.jishuzhan.net/article/1790850522027134978/c2c4aa19a0dc6a458a97aa970fd3d1db.webp) #### 6.4.2 浮点乘除运算 两个浮点数相乘,**++其乘积的阶码应为相乘两数的阶码之和++** ,**++其乘积的尾数应为相乘两数的尾数之积++**。 两个浮点数相除,**++商的阶码为被除数的阶码减去除数的阶码++** ,**++其尾数为被除数的尾数除以除数的尾数所得的商++**。 步骤如下: 1. 阶码运算 2. 尾数运算 3. 规格化 4. 舍入处理

相关推荐
Electron-er1 小时前
汽车LIN总线通讯:从物理层到协议栈的深度解析
单片机·汽车电子·lin总线·lin总线通讯
程序视点1 小时前
Window 10文件拷贝总是卡很久?快来试试这款小工具,榨干硬盘速度!
windows
巴伦是只猫1 小时前
【机器学习笔记Ⅰ】13 正则化代价函数
人工智能·笔记·机器学习
Do vis8241 小时前
STM32第十六天蓝牙模块
stm32·单片机·嵌入式硬件
学不动CV了1 小时前
ARM单片机启动流程(二)(详细解析)
c语言·arm开发·stm32·单片机·51单片机
大千AI助手1 小时前
DTW模版匹配:弹性对齐的时间序列相似度度量算法
人工智能·算法·机器学习·数据挖掘·模版匹配·dtw模版匹配
wuk9982 小时前
基于MATLAB编制的锂离子电池伪二维模型
linux·windows·github
LCG元2 小时前
自动驾驶感知模块的多模态数据融合:时序同步与空间对齐的框架解析
人工智能·机器学习·自动驾驶
lzb_kkk3 小时前
【C++】C++四种类型转换操作符详解
开发语言·c++·windows·1024程序员节