Ⅰ 进制
❶ 进位记数法
下面一起来了解一下如何用符号来表示数据,这里我们采用进位计数法这样的方法。
-
基数的介绍与区分
-
X进制中的X代表的是基数,也即每一个符号位所能够提供的符号数量,
比如二进制在每个符号位能提供2个符号数量(0与1),十六进制则能提供16个符号数量(0/1/2/3/4/5/6/7/8/9/A/B/C/D/E/F)。
-
为了区分不同基数下的计数,通常可以采用两种形式——
一种是下标形式:(1001)
2(4A)16另一种是在后面加上字母: 如H代表十六进制 3CH,B代表二进制 10001B
-
-
位权是什么?
比如任意一个r进制数,则一个符号所代表的权重与它离小数点的距离有关
(r^n^ , r^n-1^, ......r^0^, 小数点,r^-1^, r^-2^, ......r^-m^ )
-
计算机组成原理中的计数法
-
大基数与小基数的计数法在计算机组成原理中的差别:
基数大(十进制) 基数小(二进制) 位数(指相同的数据需要的表示位数) 少(5) 多(101) 机器要存储的运算规则数(乘法为例) 10*10=100 2*2=4 -
从上面的讨论可以看出基数大与基数小各有优劣,虽然十进制更加符合人类的习惯,但是在计算机中选择的是二进制,这是因为:0与1可以方便地对应到物理器件的状态,如高电平、低电平;开关的通和断;灯泡的亮和灭;以及一些磁体的磁场的方向,方便计算机的处理
-
❷ 进制转换
下面介绍两个最重要的进制——十进制与二进制——与任何进制之间的转换
1 十进制的转换
1️⃣ any to base10
为计算方便,可以记忆常见的2^n^次方
2️⃣ base10 to any
-
整数部分-除基取余法
-
小数部分-乘基取整法
注意,有可能乘不清,这个时候题目应该会规定保留位数
2 二进制的转换
1️⃣ base2 vs base 4/8/16
从四进制、八进制、十六进制写成二进制就是一个逆向的过程
2️⃣ base2 to base10 - BCD码
上面学习了任意进制转十进制的方法,当然也可以用于二进制转十进制,但是这种普适性的方法还是略显麻烦
对于二进制来说,还有更好、更快与十进制相互转换的编码方法——BCD码(Binary-Coded Decimal),这是一种快速转换、每1个十进制位对应4位二进制码的编码方法。
-
BCD码的映射关系
由于4个二进制位对应16种不同的状态,而BCD码只选取其中的10种来对应十进制的0~9,所以存在不同的映射方案,举例如下:
-
8421码:最常用的BCD码
-
余3码:8421码的平移3位版本 + (0011)
2 -
2421码:改变权值定义
由于权重中出现了两次2,故有一些十进制数可以对应2种编码,比如6既可以对应0110,又可以对应1100,取决于用哪个位上的2。
为了消除这种歧义,规定:0~4必须不使用最高位的2, 5~9必须使用最高位的2
-
-
BCD码的运算规则
以下规则以8421码为例
-
基本规则:直接使用二进制码运算
-
+6修正:如果算出的结果超出了8421的映射表范围,那么+6(0110)修正,这起到一个手动进位的作用。
-
3 真值与机器数
我们知道真实的值是有正负的,这种正负在计算机中用0/1来表示,这样真值就对应到了机器数。
- 但是如果要判断这个机器数是正或者负之后再分类讨论计算,会大大增加计算机的运算量,有没有什么办法可以不分类讨论正负直接运算能得到正确的结果呢?答案就是使用适应运算规则的原码、反码、补码、移码。
- 如果要扩大机器数的表示范围,就可以使用浮点数。
Ⅱ 编码
❶ 字符的编码
1 ASCII码
1️⃣ ASCII码的定义
将常用的数字、字母、符号共128个字符一一对应成7位 ( 2^7^=128 ) 二进制编码,这样就能把想要表达的符号转化成计算机所能理解的形式,而这些编码就叫做ASCII码。
2️⃣ ASCII映射表
3️⃣ ASCII的运算
运算这一块,基本只需要知道大写字母、小写字母、数字的编码是连续的即可
2 汉字的表示与编码
❷ 数据的编码
0 数据编码的对比
1️⃣ 定点整数与小数
2️⃣ 无符号与有符号整数
- 原码和反码的合法表示范围完全相同,都有两种方法表示真值0
- 补码与移码的合法表示范围完全相同,比原码和反码多一个负数,且只有一种方法表示真值0。
1 无符号整数的编码
1️⃣ 真值->原码
无符号整数只有一种基本的编码方式,我称之为无符号编码方式,其实就是最基本的二进制码
- 全部二进制都是数值位,没有符号位
- 计算机硬件能支持的无符号整数位数有上限,取决于机器字长(也即寄存器的位数),超出则溢出
2 定点整数的编码
同一个带符号整数,可以有三种编码方式:原码、补码、反码,真值与这三种编码方式之间可相互转换
1️⃣ 真值->原码
符号位 “0/1” 对应 “正/负” ,剩余的数值位表示真值绝对值的二进制码
需要注意以下几点:
-
原码的范围:要注意有符号数的原码数值位只有n-1位,但是相应的,可以取到负数范围
(假设机器字长均为n) 机器码的表示范围 无符号整数 0 ≤ x ≤ 2^n^ - 1 有符号整数:原码 -(2^n-1^ - 1) ≤ x ≤ (2^n-1^ - 1) -
原码的书写方式:可以在符号位与数值位之间加上一个逗号,以x=-19为例
- 若不给定机器字长: [-19]
原= 1, 10011 - 若给定机器字长(假如为8bit):需要补零, [-19]
原= 1, 0010011
- 若不给定机器字长: [-19]
-
真值0有两种形式: +0 与 -0,对应的原码也有两种 [+0]
原= 0, 0000000 , [-0]原= 1, 0000000
2️⃣ 原码->反码
-
对于符号位为正数的原码,其反码等于原码;对于符号位为负数的原码,其反码为符号位不变,数值位取反。
-
反码的意义是从原码到补码的一个中间态
3️⃣ 原码->补码
如果想要得到一个真值的补码,在已知原码的情况下,有以下两种方式:
-
基于反码的基本转换方法:
值得注意的是:
原码与反码互相转换的操作是完全一致的(都是符号位不变,数值位取反),
原码与补码的互相转换操作其实也是完全一致的(也就是说补码要转换成原码,也需要符号位不变、数值位取反、末位+1),只是图中没有表示出来!
-
跳过反码的快速转换法(常用计算技巧):
4️⃣ 原码->移码
移码的本质其实是真值 + 偏置值。注意:移码只能用于表示整数,不可以用于表示小数的。
-
假设偏置值为128D (便于理解)
这一偏置值,可以看做在补码的基础上将符号位取反
-
假设偏置值为127D(IEEE 754的段浮点数标准)
3 定点小数的编码
整体与定点整数相似,有些许细节不同。值得注意的是,定点小数没有移码。
1️⃣ 真值->原码
-
与定点整数相似点:
第一位是符号位,后面的是数值位。符号位 “0/1” 对应 “正/负” ,剩余的数值位表示真值绝对值的二进制码
-
与定点整数不同点:
-
位权不一样:由于隐含的小数点位置不同
比如机器码都为1 0010011
若这是定点整数的原码:真值 = -(1×2^4^+ 1×2^1^+ 1×2^0^)
若这是定点小数的原码:真值 = -(1×2^-3^+ 1×2^-6^+ 1×2^-7^)
-
书写方式不一样:定点整数的原码,符号位与数值位之间用逗号分隔,如1,0100000;定点小数的原码,符号位与数值位之间用小数点分隔,如1.010000。
-
位数拓展时,拓展的位置不一样。定点小数在数值位后面补零,定点整数在数值位前面补零
-
2️⃣ 原码->反码
与定点整数的转换一模一样
3️⃣ 原码->补码
与定点整数的转换一模一样
4 浮点数的编码
十进制数可以用科学计数法表示,从而能用较少位的数字表示很大的数值,比如302657264526 = +3.026×10^11^,只要存下+11 +3.026这两个数即可。
那么二进制数也可以仿照十进制,用两个较小的数来表示一个很大的数,二进制的科学计数法称为浮点数。
1️⃣ 浮点数的构成
① 概念
浮点数顾名思义,小数点是可以浮动的,这与定点小数的小数点是固定的形成鲜明对比。浮点数由阶码与尾数两部分组成:
- 阶码:用补码或者移码表示的定点整数,反映了数值大小,小数点浮动的位数与阶码的数值大小有关,浮动的方向与浮点数的阶码正负有关。
- 尾数:用补码或者原码表示的定点小数,反映了精度
② 实例
2️⃣ 浮点数的规格化
① 规格化的概念
看看上面的例子,在存储空间一定的情况下,如果我们希望最大程度减少的精度损失,应该怎么做呢?答案是浮点数的规格化。
同样借十进制的科学计数法来引入,同样一个普通计数法的数可以写成如下图两种科学计数法的数,很明显,上面的精度更大些,这是因为它的数值位都是有效位。
那么对于二进制的浮点数来说,减少精度损失的原理也是一样的,即:确保数值位都是有效位,比如对之前那个丢失精度位的例子进行浮点数的规格化,就能减少精度损失:
② 规格化的分类
浮点数的规格化分为左规与右规:
-
左规:用于减少尾数最低位溢出导致的精度损失,尾数算术左移一位,阶码减1
-
右规:用于减少尾数最高位溢出导致的精度损失,尾数算术右移一位,阶码加1
采用双符号位,可以在最高位溢出时挽救,因为更高的符号位还没有被溢出,是正确的符号位。
③ 规格化后浮点数的特点
浮点数用原码表示还是用补码表示,会影响规格化的规则。只要记住一句话:对原码来说有效位为1,对补码来说有效位为0,而规格化后的浮点数最高数值位一定为有效位。
3️⃣ IEEE标准
① 标准介绍
-
数符m
s:用于决定浮点数的正负,0为正,1为负。注意在IEEE标准下,数符与尾数并不相连,而且阶码部分由于用移码表示,不需要阶符
-
阶码E:IEEE标准下用偏移量为2^n-1^-1的移码表示(n为阶码的位数),全为0与全为1的阶码留作特殊用途,故在阶码可用真值范围内需排除。
-
尾数M:用原码表示,并且天然的完成了浮点数的规格化,隐藏了最高位1,即尾数实际为1.M
② 转换实例
③ 表示范围
-
基本表示范围
-
特殊表示范围
Q:如果上面的浮点数的表示范围还不能满足需求怎么办,比如要表示的数绝对值还要更小、或者无穷大等等
A:开启阶码全0或全1的特殊状态来表示
❹ 校验码
1 奇偶校验码
奇偶校验码的出现是基于通信方面的要求。我们知道通信在使用比较长的链路传递信息的时候,信道有各种各样的不理想的因素,会导致传递的信号发生跳变,所以为了使接收方能判断出信号发生了跳变,专家们搞出了奇偶校验这一套理论。
奇校验码:在添加奇偶校验位之后,使整个校验码(有效信息位和校验位)中**“1”的个数为奇数**。
偶校验码:在添加奇偶校验位之后,使整个校验码(有效信息位和校验位)中**“1”的个数为偶数**。
ps. 无论是奇校验码还是偶校验码,其局限在于只能检测出跳变个数为奇数的传输误差
题目没有告诉校验位,默认最高位是校验位,其余位是信息位
2 海明校验码
Ⅲ 运算
❷ 无符号整数的运算
1 加法运算
计算机硬件如何做无符号整数的加法:从最低位开始,按位相加,并往更高位进位
2 减法运算
计算机硬件如何做无符号整数的减法:不同于人类的借位减法方式。假设有一减法如下:
-
step1 - 将减法转变为加法:被减数不变,减数全部位按位取反、末位+1
-
原因:加法电路造价便宜,减法电路造价昂贵,若可将减法转变为加法,省钱!
-
原理:不要纠结为什么这么做就能加法变减法,因为涉及到数论知识,无需深究。
-
-
step2 - 回归加法模式:从最低位开始,按位相加,并往更高位进位
❸ 定点数的运算
1 定点数的加减法
0️⃣ 关于原码 - 缺点
- 如果基于原码进行计算,会出现如下情况:
- 如果直接简单相加,如下如所示,由于符号位不能参与运算的原因,最终会得到错误的结果,
- 如果设计复杂的硬件电路来专门处理符号位的问题,虽然能运算出正确的结果,但是费钱!贵!
- 补码是从原码的缺点上改进而来的一种编码方式,所以使用补码计算符号位可以直接参与运算,并得到正确的符号位结果,而不需要像原码一样把符号位摘出来分类讨论,大大节约了电路的经费。
1️⃣ 基于补码 - 加法运算
① 定点整数步骤实例
- step1 - 转换补码:先把加数与被加数都转换为补码
- step2 - 直接加:从最低位开始,按位相加(符号位参与运算),并往更高位进位
- step3 - 结果转换:将计算结果补码转换为原码,再算出真值结果
② 定点小数步骤实例
与定点整数一致
2️⃣ 基于补码 - 减法运算
① 定点整数步骤实例
-
step1 - 转换补码:先把被减数与减数都转换为补码
-
step2 - 将减法转变为加法:把A-B 看做 A+(-B)
转换思路:被减数的补码-减数的补码 = 被减数的补码+减数的负值的补码
接下来要解决的问题是:已知减数的补码,如何求减数的负值的补码?
相似的,这种运算也有简便方法:从右往左找到第一个1,这个1左边的所有位按位取反(注意这次不是仅数值位取反了)
-
step3 - 回归加法模式:计算被减数的补码+减数的负值的补码
-
step4 - 结果转换:将计算结果补码转换为原码,可进一步算出结果的真值
② 定点小数步骤实例
与定点整数一致
2 定点数的移位运算
1️⃣ 算术移位
对十进制数做移位操作,移位的是小数点,客观上实现了乘除的效果,如下图所示。
那么对于小数点是固定且隐藏的定点数来说,如何能通过移位实现乘除的效果呢?
虽然我们没办法挪动小数点的位置,但是山不就我我就山,由于移位操作的本质是改变每个符号与小数点的相对距离从而改变位权,于是可以通过对数值位移位的方法来达到相同目的。
答案是:符号位保持不变,仅对数值位进行移位。这种移位下,左移相当于×2,右移相当于÷2,完美实现了通过移位进行乘除的效果,称为算术移位,但是:
- 由于位数有限,无法用算术移位精确地等效乘除法(有溢出)
- 需要注意,不同的编码方式下,需要添补的代码不同
-
原码的算术移位
-
反码的算术移位
-
补码的算术移位
-
算术移位的应用
用一个例子来阐述算术移位在算术上的应用:
2️⃣ 逻辑移位
逻辑移位的基本特征:不区分符号位与数值位,整体移位,左移右移都补零,移出的位舍弃。
可以看做是对无符号数的算术移位
应用:用3Byte存储RGB,那么可以用逻辑移位实现
3️⃣ 循环移位
循环移位的基本特征:移位不会导致溢出,而是像循环队列一样,从一边出来,再从另一边进去。
循环移位的应用:适用于调换高位与低位bit,比如用于之前学过的字符串的大端存储与小端存储之间转换。
3 原补码乘除法
1️⃣ 原码 - 一位乘法运算
下面的解释以定点小数的原码作为例子,其实定点整数的乘法步骤与原理是一模一样的
-
乘法的本质原理
在探讨如何用计算机实现乘法前,先了解一下乘法的本质原理:如下如红框框起来的展开式,那个就是列竖式的基本原理支撑,而这些红色字体的×2^n^很明显可以用移位来实现,这给了我们设计思路,但是仍然存在几个问题:
- ① 我们这个例子中,使用两个正小数相乘,实际数字有正负,符号位如何处理?
- ② 由于展开式其实是位积之和,本例中只有四个位积还好,如果有64个位积呢?难道要把这些位积存储在64个寄存器里面再相加吗?
- ③ 乘积之后,结果位数扩大一倍,这很有可能超出寄存器的位数了,如何处理?
-
计算机对原码乘法的实现
① 解答:符号单独处理,仅仅取数值位进行乘法运算。
② 解答: 实时累加,算出来一个位积就立马加上去。
③ 解答: 乘积高位保存在ACC,乘积低位由于持续右移保存在MQ。
-
手算模拟
2️⃣ 补码 - 一位乘法运算
补码的乘法运算框架上来说与原码很相似,但是也有很多不同
-
与原码乘法区别
原码一位乘法 补码一位乘法 进行n轮加法、移位 进行n轮加法、移位,最后再多来一次加法 每次加法可能 +0 / +[|x|] 原码
(加什么取决于MQ的最低位)每次加法可能 +0 / +[x] 补码/ +[-x]补码
(加什么取决于辅助位-MQ最低位)每次移位是逻辑右移 每次移位是补码的算术右移 符号位不参与运算 符号位参与运算 寄存器位数为n+1
n+1= n(数值位)+1(符号位)寄存器位数为n+2
ACC与X:n+2=n(数值位)+1(符号位)+1(辅助位)
MQ:n+2=n(数值位)+2(双符号位) -
计算机对补码乘法的实现
-
手算模拟
可以看得出来,比起原码乘法最后多来一次加法,是因为符号位也参与运算
3️⃣ 原码 - 除法运算
原码的除法计算,符号位单独计算(被除数与除数符号位异或=商与余数的符号位),取数值位的绝对值进行除法计算,数值位的除法主要有以下两种方法:
-
恢复余数法
-
加减交替法
当确认当前余数是负数之后,由当前余数得到下一个余数需要先:1恢复余数 2左移 3减商
而这三个步骤,其实经如下图运算分析可以简化为两个步骤:1余数左移一位 2加上除数(图里写错了)
值得注意的是:如果最后余数为负,那么这个时候需要回到基本的恢复余数法,加上除数恢复余数并商0(图中这个情况是最后余数为正,那么就商1并结束计算即可)
4️⃣ 补码 - 除法运算
使用类似原码的加减法交替的框架,但是有差别,主要是图中三个框内的内容:
❷ 浮点数的运算
在考试中基本不会用IEEE标准计算,因为太长,具体标准题目会给出
1 加减运算
2 浮点数的舍入原则
在规格化(尤其是右规)或者一些其他情况运算时,可能需要用到浮点数的舍入问题
1️⃣ 0舍1入法
这种方法有再溢出风险,因为需要在末尾+1,自己想象这种连锁反应
2️⃣ 恒置1法
3 强制类型转换
由于主流教材年代久远,所以考试很可能是用32位机器的存储模式
什么是损失精度与溢出:
-
损失精度
转换前后,表示数值的位缩小了,那么就会产生精度损失
-
溢出
转换前后,该类型数据能存储的数值大小减小了,就可能溢出以及产生精度损失
类型转换前后可能出现:
-
不损失精度不溢出:范围、精度从小到大
char(8)->int(1+31)->long(1+31)->double(1+11+52(实际为53))
float->double
注意这里的long采取的是32位系统下的32位存储
-
只损失精度不溢出:范围从小到大,精度从大到小
int(1+31)->float(1+8+23(实际为24))
long(1+63)->double(1+11+52(实际为53))
注意这里的long采取的是64位系统下的64位存储
-
既溢出又损失精度:范围、精度从大到小
float(1+8+23(实际为24))->int(1+31)
Ⅳ 算术逻辑单元ALU
❶ ALU简介
1 ALU的基本概念
ALU(Arithmetic and Logic Unit),全称算术逻辑单元。ALU算术逻辑单元,按照字面意思就是进行算术和逻辑运算的,这是运算器的核心功能。主要采用的是控制逻辑的设计方式。
2 ALU的结构
ALU的抽象结构与具体结构分别如下图左右所示
此处详细解释一下右边的具体ALU结构:可以看见右边黄框里的MS
0S1S2S3就是来自控制单元CU的控制信号,用于控制ALU具体做哪一种运算。
- M用来区分运算的种类:是算术运算、逻辑运算还是辅助功能
- S
0S1S2S3用于区分该种类下具体做哪种运算:由于2^4^=16,每一个分类下可以做16种操作例如:M=1,代表做逻辑运算;S
0S1S2S3=1001,代表做逻辑运算分类下的异或运算。同时可以看出来这个ALU的机器字长为4,因为输入(下方)与输出(上方)的信号字长均为4
❷ 电路基础知识
1 逻辑运算
1️⃣ 基础逻辑运算
2️⃣ 复合逻辑运算
逻辑表达式是对电路的数字化描述
关于异或的实际表达式如下,异或可以用于二进制加法与奇偶校验。
同或就是异或的取反,不多赘述
2 门电路
❸ 加法器的实现
1 一位全加器的实现
2 多位全加器的实现
1️⃣ 串行加法器
- 原理:只有一个全加器来实现多位全加,数据逐位串行送入加法器中进行运算,进位触发器用来寄存进位信号,以便参与下一次运算。
- 局限:由于数据是串行进入的,如果操作数长n位,那么就需要这个全加器进行n次加法操作,每次产生1位和结果,计算n次最终产生n位和结果。这将耗费大量时间。
2️⃣ 串行进位的并行加法器
串行进位又称为行波进位,每一级进位直接依赖于前一级进位,形似多米诺骨牌。
- 原理:把n个全加器串接起来,上一个全加器算出的进位就可以作为另一个全加器的输入
- 局限:运算速度很大程度上取决于每一位进位的产生速度。
3️⃣ 并行进位的并行加法器
各级进位信号同时形成,又称为先行进位、同时进位
-
原理:为了避免等待进位所导致的时间消耗,故选择让每一个全加器都不等待进位信息,而是自己去算进位信息(虽然套娃是复杂了点吧,但是自己动手丰衣足食!等进位更慢)
找到套娃公式中反复出现的因子(A与B)以及(A异或B),公式可以进一步简化写为:
-
随着进位的逐渐深入,套娃会导致逻辑表达式越来越复杂,相应的电路也越来越复杂。
3 加减法运算器
1️⃣ nbit 加法运算器
n bit加法运算器可以看做将n个全加器组合而成的一个复合器件,这里将直接通过nbit的输入给出nbit的输出,至于其间的原理可以看做是封装的内容。
2️⃣ nbit 加减法运算器
下半部分将加减法统一为加法,上半部分则是一个基本的nbit加法运算器,无符号与有符号的加减法都可以用改该电路实现。
但是注意溢出的判断上,无符号数与有符号数存在显著差别
-
nbit加减法运算器用于无符号数的加减法
(由于是对有符号数的加减,注意X/Y输入时是原码)
-
nbit加减法运算器用于有符号数的加减法
(由于是对有符号数的加减,注意X/Y输入时已经是补码)
4 标志位
1️⃣ 标志位的生成
ALU除了输出相加结果F以外,还可以生成并输出标志位,用于提供一些关于结果状态的的信息,
每次运算结束后,这些标志位都会被自动存入PSW程序状态字寄存器(在intel系列cpu中被称为标志寄存器)。以intel的8086CPU为例,PSW寄存器有16个bit,OF/SF/ZF/CF的存储位置如下图。
标志位主要由OF/SF/ZF/CF四种,其作用分别为:
-
OF(溢出标志 Overflow Flag):用于判断有符号数的加减运算是否发生了溢出,OF=1时说明发生了溢出
OF在无符号数的加减法中无意义
-
SF(符号标志 Sign Flag):用于判断有符号数加减法运算的正负性,SF=0表示运算结果为正数,SF=1表示运算结果为负数
SF在无符号数的加减法中无意义
-
ZF(零标志 Zero Flag):表示运算结果是否为0,ZF=1表示运算结果为0,ZF=0表示运算结果非零
-
CF(进位/借位标志 Carry Flag):用于判断无符号数的加减法是否发生了进位或者错位(即溢出),当CF=1时,说明无符号数发生溢出。
CF在有符号数的加减法中无意义
2️⃣ 标志位的应用
-
判断是否溢出
由于OF、CF分别只对有符号数与无符号数有意义,所以如果某一个输出所对应的OF=1、CF=0,若计算的是有符号数,则发生了溢出,若计算的是无符号数,则没有。比如下面这个例子。
-
比较两个数的大小 cmp