1
0
mirror of https://github.com/Didnelpsun/CS408.git synced 2026-02-08 13:24:29 +08:00

Update 1-data-representation-and-operation.md

This commit is contained in:
Didnelpsun
2021-05-21 23:54:55 +08:00
parent 73eab5a81d
commit 5724216abf

View File

@@ -636,16 +636,148 @@ long double|临时浮点数|1|15|64|80|3FFFH|16383
### 浮点数运算
#### 科学计数法加减运算
1. 对阶:阶数小的向阶数更大的对齐。
+ 因为计算机内部,尾数是定点小数,小数点位置不会变,改变的只是数据的相对位置。
+ 若是阶数大的向阶数小的对齐,则阶数大的尾数值会变大,需要对尾数进行算术左移,若内存不够大很可能会引起最高有效位丢失。
+ 若是阶数小的向阶数大的对齐,则阶数小的尾数值会变小,需要对尾数进行算术右移,若内存不够大很可能会引起最后几位丢失,即精度下降,影响较小。
2. 尾数加减:阶数不变,对尾数进行相加减。
3. 规格化将数据变为整数部分为0到9的数据
+ 当尾数加减结果的第一位为0时需要左规直到第一位不为0。
+ 当结果的整数部分大于等于10需要右规直到整数部分只有一位。
4. 舍入:计算机中由于尾数的比特位有限,所以需要舍弃尾数的低位。舍入方法有:
+ 直接去除。
+ 非0进1。
+ 四舍五入。
5. 判溢出:若运算后阶码超过规定范围则溢出。尾数的溢出未必会导致整体溢出,可以通过第三四步来修补,但是阶码溢出一定会整体溢出。
**例题** 计算$9.85211\times10^{12}+9.96007\times10^{10}$的值并保留四舍五入六位有效尾数。
第一步进行对阶,变成$9.85211\times10^{12}+0.0996007\times10^{12}$。
第二步进行相加得到$9.9517107\times10^{12}$。
第三步由于整数部分为9所以不需要规格化。
第四步因为只能保留六位有效尾数所以保留9.95171因为后一位是0所以不进位为最后答案。
第五步因为阶码无论是10或12都是两位所以肯定没有溢出。
#### 浮点数加减运算
1. 对阶
2. 尾数加减。
3. 规格化
4. 舍入。
5. 判溢出
浮点数的加减基本上与科学计数法的加减一致。基本上浮点数的运算不可能使用IEEE 754的标准因为位数太长不好计算
**例题** 已知十进制数$X=-5/256$$Y=+59/1024$,按机器补码浮点运算规则计算$X-Y$结果用二进制表示浮点数格式如下阶符取2位阶码取3位数符取2位尾数取9位
首先要将十进制的真值转换为二进制原码。因为不是IEEE 754标准所以小数不用转换为1.xxx的格式转成0.xxx的格式就可以了$5D=101B$$1/256=2^{-8}$,所以$X=-101\times2^{-8}=-0.101\times2^{-5}=-0.101\times2^{-101B}$。然后$59D=11 1011B$$1/1024=2^{-10}$,从而$Y=+11 1011\times2^{-10}=0.111011\times2^{-4}=0.111011\times2^{-100B}$
X的阶码为-101转换为补码表示为1011由于使用双符号位所以变成11011X的尾数为-0.101补码表示为1.011由于双符号位所以为11.011尾数取9位所以拓展为11.0110 0000 0。所以X就是11011,11.011000000。
同理Y的阶码为-100转换为补码表示为1100双符号位所以变为11100Y的尾数为0.111011补码表示为0.111011使用使用双符号位为00.111011拓展为9位得到00.111011000.所以Y就是11100,00.111011000。
然后是阶数对齐小阶向大阶靠拢。首先求阶差11011-11100=11011+00100=11111=11,001=-1D。所以X的阶数比Y的阶数小一。所以对X算术右移负数高位补1阶码加一从而由11011,11.011000000变为了11100,11.101100000。即变为了$-0.0101×2^{-100B}$。
然后是尾数加减所以Y的尾数需要变成其负值的补码方法是对尾数包括符号位全部取反然后末尾加1所以-Y=11100,11.000101000。进行相加得到10.110001000。这时候代表出现上溢出(用二进制计算尾数变成-1.001111由于定点小数无法表示绝对值大于等于1的数所以上溢
第三步规格化因为使用双符号位所以正好能补救计算结果的上溢可以通过右规的方式规格化。所以将10.110001000算术右移将符号位的0以及后面的数据全部右移一位符号位补成11得到11.011000100。然后阶码由于右移而加一最后为11101,11.011000100。
第四步舍入由于第三步右移抛弃的是0所以没有丧失精度就不需要舍入。
第五步判溢出11101加1后等于11110符号位都是11所以没有溢出。
最后真值为11101,11.011000100。即$2^{-3}\times(-0.1001111)_2$。
舍入的方法:
+ “0”舍“1”入法类似于十进制数运算中的“四舍五入”法即在尾数右移时被移去的最高数值位为0则舍去;被移去的最高数值位为1则在尾数的末位加1。这样做可能会使尾数又溢出此时需再做一次右规。
+ 恒置“1”法尾数右移时不论丢掉的最高数值位是“1”还是“O”,都使右移后的尾数末位恒置“1”。这种方法同样有使尾数变大和变小的两种可能。
假如加减的结果为11100,10.110001011因为尾数符号位为10代表溢出了所以需要规格化。
使用0舍1入法将尾数整体右移并将符号位的低位移到尾数高位阶码加移位数符号位修改从而变成了11101,11.011000101溢出1最高位为1使用0舍1入时需要加1从而变成11101,11.011000110。假如尾数为全1则加1后又会高位溢出还需要一次右规。恒置1法的答案是一样的。
#### 浮点数强制类型转换
类型|16位机器|32位机器|64位机器
:--:|:------:|:------:|:------:
char|8|8|8
short|16|16|16
int|16|32|32
long|32|32|64
long long|64|64|64
float|16|32|32
double|64|64|64
无损转换:
+ char→int→long→double。
+ float→double。
由于定点数和浮点数不同,浮点数使用阶码+尾数的存储方式存储所以定点数数值精度看位长就可以了而浮点数数值精度看尾数长度按IEEE 754标准有一个隐含的高位1所以double尾数长度为53位。对于32位机器long是32位所以转换到double的53位没有损失而对于64位机器long是64位double还是53位这时候转换就会产生损失了。
int与float转换
+ int表示整数范围$[-2^{31},2^{31}-1]$有效数字32位。
+ float表示整数及小数范围$\pm[2^{-126},2^{127}×(2-2^{-23})]$有效数字23+1=24位。
+ int→float可能损失精度。
+ float→>int可能溢出及损失精度。
## 算术逻辑单元
即运算器中的ALU。
### 原理
#### ALU结构
+ 输入信号有一个操作数的输入口输出信号有一个运算结果输出口旁边还有一个控制单元CU发出的控制信号接口会输入指令译码。
+ 机器字长就是指ALU可以同时处理多长的数据。为了保存结果寄存器的字长与机器字长相等。
#### 逻辑运算
+ 与可以用*表示如A\*B。
+ 或可以用+表示如A+B。
+ 优先级上类比乘法加法,与优先于或。
+ 具有类似的分配律结合律。
+ 与非:先与后非。
+ 或非:先或后非。
+ 异或相异为1相同为0。
+ 同或相同为0相异为1。
### 加法器实现
#### 一位全加器
+ 一位全加器FA中令被加数为$A$,被加数从低到高的位数为$A_i$,令加数为$B$,被加数从低到高的位数为$B_i$,令来自低位$i-1$的进位为$C_{i-1}$,本位的和为$S_i$。$S_i=A_i+B_i+C_{i-1}$。
+ 输入$A_i$、$B_i$、$C_{i-1}$,输出$S_i$、$C_i$。
+ 输入中有奇数个1时为1异或$S_i=A_i\oplus B_i\oplus C_{i-1}$。
+ 输入中至少两个1才会高位进1一种情况是两个本位都是1另一种情况是有一个是1且来自低位的进位是1$C_i=A_iB_i+(A_i\oplus B_i)C_{i-1}$。
#### 串行加法器
+ 基于一个一位全加器一位一位串行进入加法器运算。对比一位全加器需要保存一个进位触发器用来保存进位位进位触发器初始化值为0。
+ 如果操作数长n位加法就要务n次进行每次产生一位和并且串行逐位地送回奇存器。
#### 串行进位并行加法器
+ 把n个全加器串接起来就可进行两个n位数的相加。前一个全加器的进位输出将作为下一个全加器的输入。
+ 串行进位又称为行波进位,每一级进位直接依赖于前一级的进位,即进位信号是逐级形成的。所以不可能比单纯的串行全加器快很多。
#### 并行进位并行加法器
+ 由于$S_i=A_i\oplus B_i\oplus C_{i-1}$,所以计算的重点是计算$C_i$,而$C_i=A_iB_i+(A_i\oplus B_i)C_{i-1}$,通过递归可以不断展开:$C_i=A_iB_i+(A_i\oplus B_i)(A_{i-1}B_{i-1}+(A_{i-1}\oplus B_{i-1})C_{i-2})$一直可以递归到$C_0$,而$A_i$、$B_i$、$C_0$都是一开始可以知道的,所以第$i$位向更高位的进位$C_i$可根据被加数、加数的第1到$i$位,再结合$C_0$即可确定。
+ 将$G_i=A_iB_i$$P_i=A_i\oplus B_i$,所以式子得到化简:$C_i=A_iB_i+(A_i\oplus B_i)C_{i-1}=G_i+P_iC_{i-1}$。
+ 所以$C_1=G_1+P_1C_0$$C_2=C_2+P_2C_1=G_2+P_2G_1+P_2P_1C_0$$C_3=G_3+P_3C_2=G_3+P_3G_2+P_3P_2G_1+P_3P_2P_1C_0$……所以一直到最后面每个$C_i$都可以用对应的$G_i$和$P_i$计算,这时候$C_i$可以不用递归来计算,可以用一开始就知道的$P_i$、$G_i$和$C_0$计算得到,从而这时候每一位的计算都可以一开始就同时进行了而不用依赖前面的计算。
+ 各级进位信号同时形成,又称为先行进位、同时进位。
+ $G_i$称为进位产生函数,因为$G_i$是通过$A_i$和$B_i$相与只有同时为1才会产生1。
+ $P_i$称为进位传递函数,$P_i$是通过$A_i$和$B_i$异或,实际上$P_i$为1时只有此时$C_{i-1}$才能为1否则为0。
#### 单级先行进位并行加法器
+ 称为组内并行、组间串行进位方式。
+ 由于逻辑表达式越长就代表电路实现越复杂所以一般会最多用4个FA和一些新的线路、运算逻辑组成一个运算单元进行串联进位计算。
+ 组内的信息可以并行同时得到,但是组件信息需要串行进位。这时虽然实现简单,但是效率对比并行进位并行加法器还是下降了。
+ 为了解决这个问题按照并行进位并行加法器的思路继续对每一组的数据进行计算。
+ 令$G_1^*=G_4+P_4G_3+P_4P_3G_2+P_4P_3P_2G_1$$P_1^*=P_4P_3P_2P_1$。