408笔记系列(十)(PS:本人使用的是王道四本书和王道视频)
计算机组成原理:(二)数据表示和运算
前言
在了解计算机的硬件及软件组成后,我们知道计算机本身是只能识别机器语言的,而机器语言就是由很多0和1组成,这主要是物理元器件的性能决定的,但是我们在使用计算机时并不是使用二进制进行表示数据和运算的,通常我们会用十进制来表示数据和进行数据的运算;那么问题来了,我们日常生活使用十进制数据,他们在计算机内部又是怎样表示的呢?
一、简介
这里,我们首先会将数据分为定点数和浮点数两种,分别研究定点数和浮点数在计算机中的是如何表示的,以及他们的运算方式;
在此之前会有一个前置知识点:进制转换和校验码;
二、主要内容
1. 进制转换和校验码
1.1 进制转换
这里我们主要探究的是二进制、八进制、十进制和十六进制之间的转换,主要是二进制和十进制;
这里我们会介绍如何将十进制转换为二进制,十进制转换为二进制需要分为两个部分:整数部分和小数部分;整数部分使用的是除基取余的方法,小数部分使用的是乘基取整的方法;这里值得注意的是:任意二进制小数都可以用十进制小数表示,但是并不是任意十进制小数都可以用二进制小数表示;
除基取余法:
乘基取整法:
二进制转换为十进制,如图所示,可以直接加上所有1对应位置上的权值;
1.2 校验码
校验码的作用主要是在计算机网络中会有所涉及,但是这里既然介绍到了,那我们也说一下了!当我们在进行通信时,往往会因为外界的不可抗力因素导致我们传输的数据里面呢,会发生数据的丢失或者直接发生错误,为了保证在通信时信息的准确性,我们需要在一串数据中加入对该数据的验证码,验证码无误则表示该数据没有发生错误,有没有一种“天王盖地虎”——“宝塔镇河妖”的感觉!!!
校验码中我们最常见的有以下三种:奇偶校验码、海明校验码和CRC循环冗余码;
- 奇偶校验码:这也是最常见的一种校验码,他又分为奇校验码和偶校验码;奇校验码指的是整个校验码(包含信息位和校验位)中1的个数是奇数个,而偶校验码指的是整个校验码中1的个数为偶数个;
非常简单明了,但是我们需要知道奇偶校验码是具有局限性的,只能发现奇数位的错误,不能发现偶数位的错误而且不能纠正错误;
那为什么还会说它是最常见的呢?因为我们在通信最常发生的便是一位数据的错误了; - 海明校验码:海明码可就比奇偶校验码厉害得多了!海明码的特点有四个字:纠一检二;纠正一位错误,检测两位错误;海明码往往会在首部加上全检验进行偶校验码;
- CRC循环冗余码:循环冗余码应用的场景主要是有大量数据传输时,通过与生成多项式做模2运算得到一个新的二进制码;当接收端接收到数据时,再用相同的多项式进行模2运算,如果结果为0则表示数据没有错误;接收端检测时检测出一位数据错误后,纠正的方法包括:请求重发、删除数据以及通过余数值进行纠正;
2. 定点数
定点数指的是小数点位置保持不变;包含定点整数和定点小数,我们往往在这里探究的都是有符号的整数,针对无符号数只需要按照上面介绍的十进制转二进制方法即可;
2.1 定点数的表示
在计算机中表示一个定点数包括原码、补码、反码和移码;
- 原码:针对正数的原码,我们会在最高位添加0,针对负数,我们会在最高位添1,其他位按照无符号数处理即可;原码是有正零和负零之分的,因此定点整数原码的表示范围只是:-(2n-1)~2n-1(关于原点对称),定点小数也是一样;
- 补码:补码可以说是这些码中最重要的,因为在计算机中存储的定点数便是补码形式,首先我们要知道为什么需要补码,因为在计算机的内部进行加减运算时,我们会发现两个正数相加还好,通过加法器就能实现,但是当两个正数相减时,这个减法器可就不好设计了啊!那我们伟大的计算机科学家先辈们秉持着坚决不能浪费的原则,利用计算机的硬件特性发明了补码,使得计算机中的减法也可以由加法来实现!!!
那补码到底是怎样做到的呢?又是利用了怎样的计算机硬件特性呢?我们知道计算机硬件的位数是固定的,也就是寄存器中的位数是固定的,那么当两个数相加超过寄存器位数所能表示的最大整数时,其实就相当于进行了一次简单的模运算,打一个简单的比方:假设现在有三位寄存器,最大表示7(即111),我现在有两个数5(即101)和3(即011),两个数相加得到1000,但是因为寄存器只有三位,那么剩下的便只有000了,那如果变成了减法,其实5-3不就是5+(-3),结果2也可以表示成10,那么-3便也可以用5来替代;根据这一规律,我们发现负数是可以用与寄存器能够表示的最大数范围取模的正数表示的;
具体实现其实很简单,正数的补码和原码相同,负数的补码就是原码除了符号位取反加一;也可以直接直接找到原码最右边的1,1的右边不变,1的左边除了符号位全部取反;已知x补码,x相反数的补码就是找到补码最右边的1,带着符号位一起取反即可;
补码的范围需要注意的是,补码的-0即1000……(n+1位)用来表示的是-2n,范围是:-2n到2n-1;小数将-0用来表示了-1,范围是:-1到1-2-n; - 反码:反码身份最为卑微,因为他只是补码产生的一个衍生物,我们知道补码是原码取反加1,是的,你可能已经猜到了,原码不加1只取反便是反码了,当然这只是针对负数,正数就是用原码表示;范围同原码
- 移码:移码也十分简单,就是把补码的符号位取反;看似十分简单,但是移码非常有用的,因为移码保持了原有数据的大小顺序,所以,移码越大真值越大,当有找最大最小值或者大小比较问题时,我们首先需要想到移码;移码因为来自补码,所以范围同补码;
下图是5和-5的原码、反码和补码;补码变为原码和原码变为补码步骤是一样的;
介绍了定点数在计算机中的表示,那么我们来看一下定点数的运算是怎样的吧!
2.2 定点数的运算
定点数的运算主要分为逻辑运算和算术运算,其中又包括定点数的移位运算和加减法运算;
- 定点数的移位运算
移位运算分为三种:算术移位、逻辑移位和循环移位;
算术移位指的是移位时符号位保持不变,不同机器数算术移位添补规则如下图所示:
这里在对负数的补码进行算术移位时,只需将右边第一个1的左边视为反码所以右移需要添1,将1的右边是为原码,所以左移需要添0;
逻辑移位指的是将操作数视为无符号数,逻辑左移时,高位丢弃,低位添0,逻辑右移时,低位移走,高位添0;
循环移位分为带进位标志符的循环移位和不带进位标志符的循环位移,如下图所示:
- 定点数的加减运算
其实这里我们在介绍补码时也有提到,加减运算其实就是对两个数的补码进行相加便可以啦!这里的问题是溢出的问题,因为我们知道两个正数或者两个负数相加是很可能超过寄存器位数的表示范围的,那这个问题我们有什么解决方案呢?这里我们给出了三种方法:一位符号位、双符号位和一位符号位根据数据位的进位情况判断这三种情况;
一位符号位:如下图所示,其实非常容易理解,当A和B的符号为都为0时,即A、B都是正数,最后算出来的符号位为1,即算出来一个负数,那肯定是发生了溢出;两个负数同理;
双符号位:这里给每个机器数两个相同的符号位S1和S2,表示没有溢出,当进行加法运算后,S1和S2符号变成不同则表示发生了溢出;
一位符号位根据数据位的进位情况判断:这里主要看符号位的进位CS和最高数位的进位C1,若相同则没有溢出,否则就会发生溢出;
定点数乘法主要通过硬件自动完成n次加法和移位操作,通过控制逻辑控制循环次数;
定点数在存储时还需要注意大端方式和小端方式以及边界对齐方式;
大端方式指的是从最高有效字节到最低有效字节的顺序存储数据,即最高有效字节放在前面;小端方式按从最低有效字节到最高有效字节的顺序存储数据,及最低有效字节存放在最前面;而边界对齐指的是起始地址能够被自身整除的存储方式;
3. 浮点数
3.1 浮点数的表示
相较于定点数,浮点数可以说完全是另外一种存储方式了,但是依然会用到之前的原码和移码的知识;首先浮点数是什么?浮点数指的是小数点根据需要而发生浮动的数;跟我们十进制中的科学技术法非常像;
往往采用的是IEEE754标准,如下图所示:
其实第一位是符号位,与定点数一样,8位阶码位,23位尾数位;其中阶码代码着浮点数的范围,而尾数则代表着浮点数的精度,8位阶码用移码表示,但是移码的偏置位127,23位尾数用原码表示,但是隐藏了小数点前的1,如下图所示:
之所以阶码是127偏置值是因为特殊数用来表示特殊含义:
- 当阶码全为0,尾数不全为0,表示非规格化小数
- 当阶码全为0,尾数全为0,表示真值0
- 当阶码全为1,尾数全为1,表示无穷大
- 当阶码全为1,尾数不全为1,表示NaN
由此可以看出,32位单精度浮点数的范围是2-126~2127*(2-2-23)
3.2 浮点数的运算
浮点数主要针对的是加减运算,浮点数的运算分为以下几步:对阶—尾数求和—规格化—舍入—溢出判断;
- 对阶
对阶其实就是将两个浮点数的阶码保持一致,小阶向大阶看齐,阶码增加,尾数发生右移; - 尾数求和
对阶结束后,此时的尾数便保持在同一阶码上,以十进制科学计数法举例,可以理解为此时的两个数都已经是乘以10^n(n相同),那么便可以对小数部分进行相加减了;尾数因为是用原码表示,进行加减时需要转换为补码进行加减,这里就会出现我们在定点数时候出现的溢出问题;
浮点数的溢出主要分为上溢出和下溢出,如下图所示:
下溢指的是绝对值小于机器数所能表示的最小绝对值,包括正下溢和负下溢,正下溢和负下溢我们都按照机器数“零”进行处理,而上溢则是指超过最大数或者小于最小负数,我们会给出中断异常报错;
在尾数进行加减时,我们采用双符号位的方法,当尾数加减后得到的双符号位不同时,便需要进行下面会介绍的右规操作,并且在右规后也需要检查阶码是否溢出,详细见下面的规格化; - 规格化
规格化,可以说是在浮点数中所特有的,规格化的产生是为让浮点数可以增加数据的表示精度,规格化数如下表所示:
规格化分为左规和右规两种,左规时尾数左移一位,阶码减一,此时需要判断阶码是否下溢;右规时尾数右移一位,阶码加一,此时需要判断阶码是否上溢;
基数 | 原码 | 补码 |
---|---|---|
2 | 尾数最高位不为0 | 正数尾数最高位不为0;负数尾数最高位不为1 |
4 | 尾数最高两位不为全0 | 正数尾数最高两位不为00;负数尾数最高两位不为11 |
8 | 尾数最高三位不全为0 | 正数尾数最高三位不为000;负数尾数最高三位不为111 |
- 舍入
舍入也只有在浮点数所特有的,定点数中不包含舍入,浮点数的舍入是当我们规格化后发现尾数比规定位数还要长,此时需要考虑舍入,普遍使用的舍入有:0舍1入法和恒置1法;
0舍1入法时就像十进制的四舍五入法,在尾数右移时,被移去最高位的是0,则舍去;若移去的是1,则在尾数的末尾加1,这样做需要注意是否发生溢出;
恒置1法指的是无论移去的是0还是1,尾数的末尾都恒置1;
这里有浮点数运算的几点注意事项:
4. C语言中的强制转换
我们将强制转换也单独作为一部分的内容拿了出来,因为这在考试中也是经常会考察的一个点,尤其是浮点数与定点数之间的强制转换;
首先,我们看一下C语言不同数据类型的位数:
我们主要介绍以下几种情况的强制转换:
强制转换前 | 强制转换后 | 操作 |
---|---|---|
unsigned short | short | 无符号数变为有符号数,将无符号数的原码视为补码进行翻译即可 |
short | unsigned short | 有符号数变为无符号数,将有符号数的补码视为原码进行翻译即可 |
float | int | 1 float若为小数,转换为int会发生精度的丢失;2 判断float是否大于int表示的最大范围,若大于则也会出错 |
int | float | 浮点数用机器数表示,当超过24位时,便会发生最后一位舍入,且尾数加1,致使最后的数并不一样 |
三、常见题及易错题总结
计算机系统概述答案为:D、A、C、C、C、A、C、B、C、A、B、
答案见下一章!数据表示和运算这一章是在太多了,只能每天抽时间写啦!