🌈个人主页:小新_-
🎈个人座右铭:“成功者不是从不失败的人,而是从不放弃的人!”🎈
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
🏆所属专栏: 计算机组成原理 欢迎订阅,持续更新中~~~
✨让小新带着你快乐的学习吧~✨
目录
一、C语言中的数据类型及转换
(一)计算机中的数据类型
- 计算机中的数据以二进制的形式存储在寄存器或者存储器中。
【举例】
机器怎么知道这些数据是定点数还是浮点数?
如果是定点数,是有符号数还是无符号数?
- 汇编语言中的数据类型取决于指令操作码。
- 存储在寄存器、存储器中的操作数本身没有数据类型,对该数进行何种数据类型的操作完全取决于指令。
- 同一个操作数,既可以当做有符号数,也可以当做无符号数;既可以是定点数,也可以是浮点数
-
高级语言具有数据类型,下面以C语言为例进行介绍。
C语言中整型变量的取值范围(以char型变量为例)
无论是无符号数还是有符号数,C语言程序并不检测数据在加减乘除运算中产生的溢出现象
- 程序员赢尽量避免出现这种情况,所编制的应用程序应具有对溢出进行判断的功能。
(二)C语言中的数据类型转换
C语言中不同类型对数据可以相互进行强制类型转换。
- 基本原则是尽量保持数的真值不变。
1、整型数据之间的转换
char、short、int、long这4种整型数据的表示范围不一样,很可能数据转换后精度缺失,此时就只能尽量保持转换前后的机器码相同或机器码部分相同。
(1)相同字长之间的转换
【举例】以char------>unsigned char 为例
我们知道char类型数据的范围为【-128,127】,unsighed char类型的数据范围是【0,255】,它们的交集为【0,127】,如图所示。
【char---->unsigned char且数值在它们的交集中】
如图,我们定义了一个char类型变量c,补码如图所示,当被强制转化为unsigned char类型时,原来的机器码是8位补码,现在被编译器解析为8位二进制无符号数,其相应的十进制数为126。我们发现转化后的数值与原值相同。
【unsigned char---->char且数值在它们的交集中】
如图,我们定义了一个unsigned char类型变量uc(赋值为16),unsigned char型为无符号数,机器内部就是用该无符号数的二进制数表示。当被强制转化为char类型时,编译器会保持原来的机器码不变,但是由于变量c为char型,是有符号整数。原来的8位二进制数被解析为8位二进制补码,则高位作为符号位,剩余位为数值位。正数的原反补码都相同,可将该补码看作原码,并写出原码对应的真值,其对应的数值为16,转化后的数值与原值相同。
【char---->unsigned char且数值在它们的交集左侧】
如图,我们定义了一个char类型变量c(赋值为-127),补码如图所示,当被强制转化为unsigned char类型时,原来的机器码是8位补码,现在被编译器解析为8位二进制无符号数,其相应的十进制数为129。我们发现转化后的数值与原值不同,相当于给原值加上256。
【unsigned char---->char且数值在它们的交集右侧】
如图,我们定义了一个unsigned char类型变量uc(赋值为255),unsigned char型为无符号数,机器内部就是用该无符号数的二进制数表示。当被强制转化为char类型时,编译器会保持原来的机器码不变,但是由于变量c为char型,是有符号整数。原来的8位二进制数被解析为8位二进制补码,则高位作为符号位,剩余位为数值位。负数的原反补码都不相同,可将该补码转化为原码,并写出原码对应的真值,其对应的数值为-1,转化后的数值与原值不同,相当于给原值减去256。
【例题】
(2)小字长转大字长
俩种类型:
- 原数据为无符号类型,进行0扩展
- 原数据为有符号类型,进行符号扩展
【unsigned char---->short】
如图我们定义一个unsigned char类型变量uc(赋值为254),uc为无符号数,在机器内部就是该数的8位二进制数11111110。将其强制类型转换为short,对于这种无符号类型的转换,编译器会对原机器码进行0扩展,在原来机器码前面加8个0(因为short为16位),另外,short是有符号短整型,编译器将16位机器码解析为补码,其真值表示为254,与原数值相同。
【 char---->short】
如图我们定义一个char类型变量c(赋值为-128),c为有符号数,在机器内部就是该数的8位二进制数补码10000000。将其强制类型转换为short,对于这种有符号类型的转换,编译器会对原机器码进行符号扩展,在原来机器码前面加8个符号位(因为short为16位),另外,short是有符号短整型,编译器将16位机器码解析为补码,其真值表示为-128,与原数值相同。
【unsigned char---->unsigned short】
如图我们定义一个unsigned char类型变量uc(赋值为126),uc为无符号数,在机器内部就是该数的8位二进制数01111110。将其强制类型转换为unsigned short,对于这种无符号类型的转换,编译器会对原机器码进行0扩展,在原来机器码前面加8个0(因为short为16位),另外,unsigned short是有符号短整型,编译器将16位机器码解析为16位二进制无符号数,其真值表示为126,与原数值相同。
【 char---->unsigned short】
如图我们定义一个char类型变量c(赋值为127),c为有符号数,在机器内部就是该数的8位二进制数补码01111111。将其强制类型转换为unsigned short,对于这种无符号类型的转换,编译器会对原机器码进行符号扩展,在原来机器码前面加8个符号位(因为short为16位),另外,short是有符号短整型,编译器将16位机器码解析为补码,其真值表示为127,与原数值相同。
【例题】
(3)大字长转小字长
一般情况下:
编译器会将机器码进行截短处理:会出现如下问题
- 表示范围缩小
- 很可能出错
很容易损失表示范围,大概率数据与原值不同
总结
2、int、float、double之间的转换
int、float、double之间也可以进行强制类型转换。
- 上述3种类型数据的机器码并不相同(int型数据是32位有符号整数,用补码表示;float和double型数据分别是32位和64位浮点数,它们的阶码用移码表示、尾数用原码表示)。
- 上述3种类型数据的表示范围和精度也不相同。
- 因此在转换过程中编译器只能保证数值尽量相等,大多数情况下只是近似值。
下面,我们讨论以下几种转换情况。
(1)float---->double
(2)double---->float
(3)float/double---->int
(4)int---->double
(5)int---->double
总结
二、移位运算
(一)逻辑移位
1、规则
逻辑移位对象:无符号数
逻辑移位规则:
- 逻辑左移:高位移除,低位补0; 逻辑右移:低位移除,高位补0;
2、应用举例
3、练习
(二)算术移位
1、规则
算术移位对象:有符号数象(针对定点数,包括定点整数和定点小数)
逻辑移位规则:
- 不论正数还是负数,符号位保持不变,仅对数值位进行移位(左移或者右移)。
- 对真值的原码、反码和补码进行算术移位后,它们各自所对应的新的真值应该保持一致。
- 当真值为正数时,真值的原反补码相同,因此,对它们进行算术移位后,它们各自所对应的新的真值自然是保持一致的。对于移位出现的空位,规定添补0。左移时,若最高位丢1,则结果出错;右移时,若最低位丢1,则精度缺失。
- 当真值为负数时,真值的原反补码不同,因此,对他们进行算术移位后,为了确保它们所对应的新的真值保持一致,对于移位后出现的空位,添补规则各不相同,后面会给出具体规则。
对于正数
【举例】假设机器字长为8位(含1位符号位),若真值x=+26,请写出x的原码、反码、补码各自算术左移1位、2位、3位后的表现形式以及对应的真值a、b、c,并对移位结果进行分析。
解析:
【练习1】假设机器字长为8位(含1位符号位),若真值x=+52,请写出x的补码各自算术左移1位、2位后的表现形式以及对应的真值a、b,并对移位结果进行分析。
【练习2】假设机器字长为8位(含1位符号位),若真值x=+52,请写出x的反码算术右移1位、2位、3位后的表现形式以及对应的真值a、b、c,并对移位结果进行分析。
对于负数
总结
2、有符号定点数补码的另一种算术移位方法
有符号定点数的补码的另一种算术移位方法,即"符号位也参与移位",具体规则如下:
- 左移:高位移除,低位添补0;移动前后若符号位发生变化,则发生溢出。
- 右移:低位移除,高位添补符号。
上述针对有符号定点数的补码的算术移位方法,具有如下优点:
- 左移时,有检测出发生溢出的方法:符号位发生变化可判断溢出。
- 符号位与数值位一起移位,方便ALU处理,也方便人们记忆。
【举例】假设机器数字长为8位(含1位符号位)◇若真值x=+26,请写出x的补码算术左移1位、2位、3位后的表示形式以及对应的真值a、b、c,并对移位结果进行分析。
3、应用举例
从本例得到启发,机器内部的乘法运算可由加法运算和算术移位来完成,因此可以不用专门设计乘法器,来降低硬件成本
4、C语言中的移位运算
至此,我们已经介绍了针对无符号数的逻辑移位、针对有符号定点数(包括定点整数和定点小数)的算术移位。
C语言中的移位运算操作符包括"<<"和">>"两种,分别表示左移和右移。
- 左移运算操作符"<<"对应汇编指令中的逻辑左移,即高位移除,低位补0。
- 右移运算操作符">>"则根据操作数是无符号还是有符号类型分别对应汇编指令中的逻辑右移和算术右移指令。
- 逻辑右移:将低位移除,高位补0。
- 算术右移:将低位移除,高位补原数据的符号位。
(三)循环移位
循环移位的对象:无符号数
- 将无符号数二进制形式中的各个位向左或向右移动,被移出的位会重新出现在另一端,形成循环。
在很多处理器架构中,循环移位指令会影响状态寄存器中的进位标志CF(Carry Flag)位,CF标志位用于标识在执行算术或逻辑操作时是否发生了进位。
根据CF标志位是否加入循环移位过程,循环移位可分为以下四种:
- 不带CF标志位的循环右移 小循环
- 不带CF标志位的循环左移
- 带CF标志位的循环右移 大循环
- 带CF标志位的循环左移
1、不带CF标志位的循环右移
2、不带CF标志位的循环左移
3、带CF标志位的循环右移
4、带CF标志位的循环左移
5、循环移位的应用
循环移位的应用主要有:加密算法、哈希函数、优化算法
- 加密算法:通过循环移位可以实现数据的混淆和置换,增强加密算法的安全性。
- 哈希函数:通过循环移位可以用来改变输入数据的排列顺序,以产生不同的哈希值,有利于增强哈希函数的混淆性和扩散性。
- 优化算法:在某些算法中,循环移位可以用于优化性能和节省资源。例如,在图形处理和数字信号处理中,循环移位可以用于加速算法的执行。
6、循环移位的C语言实现
C语言中并没有直接提供循环移位操作符。
通常情况下,可以使用移位运算操作符(例如:左移"<<"或右移">>")和位运算操作符(例如:或运算"I")来实现。
三、定点数的加减运算
1、补码加减法运算公式
进过之前的学习我们知道,定点数(定点整数和定点小数)在计算机内部采用补码表示原因如下:
- 补码的符号位可以和数值位一起参与运算。————> 运算规则简单,易于实现
- 采用补码可将减法运算转化为加法运算。————>运算规则简单,易于实现
补码加法和减法运算的公式如下:
【例题与练习】
2、补码加减法的溢出检测
1、溢出的概念
定点数补码加减运算判断溢出的方法主要有以下3种:
方法1 根据操作数的符号位与运算结果的符号位是否一致进行判断
方法2 根据运算过程中最高数值位的进位与符号位的进位是否一致进行判断(不同可判定为产生溢出,相同判定为没有产生溢出)
方法3 利用变形补码(具有2位符号位的补码)的符号位进行判断
判断方法:
【408真题挑战】
3、逻辑代数与逻辑门
1、基本逻辑运算与逻辑门
1)与运算和与门
2)或运算和或门
3)非运算与非门
2、复合逻辑运算与复合逻辑门
1)与非运算和与非门
2)或非运算与或非门
3)异或运算与异或门
4)同或运算域同或门
4、一位全加器的硬件逻辑实现
1、回忆手工二进制加法的过程
2、用逻辑门电路实现一位加法
5、串行进位加法器的硬件逻辑实现
1、串行进位加法器的硬件逻辑实现
以8位二进制数的加法运算为例进行介绍:
2、串行进位加法器的性能
6、先行进位加法器的硬件逻辑实现
1、构建先行进位电路
可使用n个一位全加器FA通过进位串联得到n位串行进位加法器
2、4位快速加法器与4位串行进位加法器性能比较
3、使用4为快速加法器构建更大位宽的加法器电路
我们将四个四位快速加法器通过进位串联方式进行连接
四、定点数的乘除运算
1、无符号数乘法运算的硬件逻辑实现
1、笔算乘法的分析
2、无符号数乘法运算的硬件逻辑实现
1、原码一位乘法运算的硬件逻辑实现
3、补码乘法运算的硬件逻辑实现
由于计算机中采用补码表示数据,如果用原码乘法计算俩个数的乘积。则运算前需要将补码转化为原码、运算后还需要将原码转化为补码,这样会增加许多操作。为了减少处理过程,英国布斯(Booth)夫妇与1950年提出一种补码乘法,又称为Booth算法
1、Booth算法的推导和分析
2、Booth算法的硬件逻辑实现
4、无符号阵列乘法器
原码、补码一位乘法的硬件逻辑实现,需要在时钟节拍下、通过控制逻辑的控制,执行相应轮次的“加法、右移”操作来实现,速度较慢。为了提高速度,可以采用组合逻辑电路以专用硬件方式构建列阵乘法器。构建列阵乘法器的基本思想是模仿二进制乘法的笔算方法。
5、补码阵列乘法器
由于计算机中采用补码表示数据,因此,这节我们设法基于无符号阵列乘法器设计补码阵列乘法器
首先回忆一下上节补码阵列乘法器,并基于它来实现补码阵列乘法器。
- 如果不考虑原码符号位,则原码数值位可看做是无符号数。
- 如果将原码的符号位单独处理,则原码乘法运算,可将被乘数原码的数值位和乘数原码的数值位直接带入无符号阵列乘法器进行处理。
- 得到的结果为无符号乘积,在其前面添加单独处理的符号位,即可得到原码乘法的结果。
- 我们还知道,原码和补码可以相互转换
- 如果将补码的符号位单独处理,将补码的数值位转化成原码的数值位,就可以利用无符号阵列乘法器进行运算。
- 得到的结果为无符号乘积,将其转换成补码的数值位,然后在其前面添加单独处理的符号位,即可得到补码乘法的结果。
6、原码除法运算——恢复余数法
由于原码表示与无符号数非常类似,仅比无符号数多一个符号,因此,进行原码除法运算时,可将符号位与数值部分分开处理。
■商的符号:由被除数和除数各自的符号进行异或运算求得;
■商的数值部分:由被除数和除数各自的数值部分(即真值的绝对值)相除求得。
同理,定点整数原码除法的条件为|x|>=|y|
综上所述,我们给出原码除法法则
【举例】设被除数x=0.1001,除数y=0.1011,模仿十进制除法的笔算方法,求x÷y。
解析:
通过本例,我们可以画出计算机内部实现原码除法运算的流程图
接下来,我们通过流程图,来设法找出相应的硬件逻辑实现方法
从流程图中我们可以看出,需要使用加法运算和移位运算,这使我们想到之前介绍的原码乘法运算的硬件逻辑实现,不同在于,移位运算为左移;还可以看出,我们需要使用减法和判断正负的方法,让我们想到,如果采用补码表示,就可以将减法转化为加法运算,并且可以根据补码的符号位来判断正负,所以我们只需要在原来原码乘法的硬件逻辑实现的基础上添加相应的求补电路和上商控制电路就可以构建出原码除法的硬件逻辑实现了。
接下来,我们再给出一个原码除法的例子。这次,我们从硬件逻辑实现的角度来完成。
对于除法运算,操作数x用于存放除数,累加器ACC用于存放被除数和余数,乘商寄存器MQ用于存放商
7、原码除法运算——不恢复余数法
分析恢复余数法,以便对其进行改进
五、浮点数的运算
1、浮点加减法运算
首先学习本节课前,建议大家复习之前学的浮点数的表示形式和表示范围以及浮点数的规格化中有关阶码,尾数,上溢,下溢,左规,右规等概念。
【引例】
- 在尾数右规时,尾数末位的几位会因超出计算机字长而被丢弃,从而产生误差。此时,计算机可以按选定的方式进行舍入操作。
- 在尾数规格化和尾数舍入时,可能会对结果的阶码执行加、减运算。因此,必须考虑结果的阶码出现溢出的问题。
- 由于浮点数中阶码的位数决定了浮点数的表示范围,因此,对于浮点运算,当阶码出现溢出时,表示运算结果出现溢出。
接下来,我们通过俩个例子来帮助理解浮点加减运算步骤,以及所涉及到的溢出问题
【例1】设x=2^-101*(-0.101011),y=2^-010*0.001110,x和y的阶码和尾数都用双符号补码表示,阶码为三位,尾数为6位(均不含符号位),请按照浮点数加减法运算步骤计算x+y。
2、IEEE 754浮点加减运算
建议大家先复习一下IEEE 754浮点数标准的内容
■ IEEE 754 浮点数的阶码采用移码表示,尾数采用原码表示,并且尾数的最高位隐藏。
■ 因此,IEEE 754浮点数的加减运算与(上节课介绍的)基于补码表示的浮点数的加减运算有如下不同:
1、在对阶和结果规格化过程中,涉及到阶码的加减运算时采用移码的加减运算规则。
2、尾数运算采用原码运算规则且隐藏位要参与尾数运算。
3、隐藏位参与尾数规格化判断和规格化过程。
- 若尾数形式为1.……,则为规格化尾数
- 若尾数形式为0..……,则需要进行左规(将尾数左移1位,相应地将阶码减1),直到尾数规格化为止;
- 若尾数形式为1b.……,则需要进行1次右规(将尾数右移1位,相应地将阶码加1)。
4、舍入处理:
- 就近舍入:舍入为可表示的最近的数,如果数据正好处于两个可表示的数的中间,则向偶数舍入。
- 朝正∞方向舍入:总是取右侧可表示的最近的数。
- 朝负∞方向舍入:总是取左侧可表示的最近的数。
- 截断处理:直接丢弃多余位,朝0方向舍入。
5、溢出判断:
- 浮点运算的溢出可通过阶码的溢出来判断。对应IEEE 754单精度浮点数而言,向右规格化使得阶码全为1(即11111111,真值为-128)时发生规格化上溢;向左规格化使得阶码全为0时发生规格化下溢。
2、浮点乘法运算
3、浮点除法运算
最后,感谢大家的观看!