文章目录
进位计数制
最古老的计数方法
十进制计数法
- 阿拉伯数字是古印度人发明的,由阿拉伯人传入欧洲
- 位权:由位置确定的权重
推广:r进制计数法
任意进制→十进制
二进制←→八进制/十六进制
- 注意这里如果需要补0的话,整数部分是补在头部,小数部分是补在尾部
各种进制的常见书写方式
十进制→任意进制
整数部分【除基取余法】
- 然后再重复上述步骤再除以r,依次得到K1、K2、…、Kn-1、Kn
- 然后再把所得到的各个Kn按相反的顺序排在一起即可
小数部分【乘基取整法】
- 然后再重复上述步骤再乘以r,依次得到K-1、K-2、…、K-m-1、K-m
- 然后再把所得到的各个K-n按相反的顺序排在一起即可
- 出现了重复的情况,表示我们现在用十进制表示的0.3没办法用二进制来精确表示,只能精确到小数点后5位
- 右边记录的是乘数结果的整数部分
十进制→二进制(拼凑法)
真值和机器数
- 真值:符合人类习惯的数字
- 机器数:数字实际存到机器里的形式,正负号需要被“数字化”
BCD码
- BCD:Binary-Coded Decimal,用二进制编码的十进制 【快速转换:一一对应】
BCD码
- 原理大致是:我们可以用4个二进制位,也就是4个比特的信息(24=16,最多可以表示16种状态,足够表示十进制里面的0-9)来对应一个十进制位,会有6种状态是冗余的,每4个二进制位对应1个十进制的字符
8421码
- 映射关系
- 加法运算
- 可以采用投机取巧用人工计算的方式,先用十进制计算出8+5=13,再把计算结果转化成对应的8421码即可
- 但如果是计算机的计算方法,分别把5和8的8421码表示出来,计算机把它们丢给ALU算术逻辑单元,进行加法运算得到结果
- 但是发现此时的结果不在合法的范围区间,没有意义
- 所以8421码有一个规则定义:当我们进行加法运算之后,如果结果落在了1010~1111(10-15)这个非法范围之内的话,我们可以【在这个运算结果的基础上再加上6(0110)】
- 因为4个二进制位只能表示0-15这么几个数,所以对于10-15的这几个数,我们再给它加上一个6,那么这4个二进制数肯定就会向高位进一个1,而低位留下的部分刚好就是我们所需要的个位的部分
余3码
- 就是在8421码的基础上再加上3(0011)
- 在8421码里面4个二进制位每个位的权值都是固定的【有权码】
- 但是在余3码里每个二进制位并没有一个固定的权值【无权码】
2421码
- 2421码也是一个有权码
- 和8421码不同,2421码改变了权值的定义,这4个二进制位表示的权值分别为2、4、2、1
- 0-4所有的数字,编码的第一位一定都是0
- 5-9所有的数字,编码的第一位一定都是1
- 这样做的好处是可以统一2421码的表示方式,比如5,用2421码的表示形式为1011,但是我们完全也可以用0101来表示5,这样可以避免歧义
无符号整数的表示和运算
无符号整数在计算机中的应用
- 无符号整数,即“自然数”,0、1、2、3、4…
- C语言中的无符号整数:
//前面的unsigned表示是个无符号整数,后面的变量类型规定了变量的大小 //位数不同,可表示数值范围不同 unsigned short a = 1; //无符号整数(短整型,2B) unsigned int b = 2; //无符号整数(整型,4B)
无符号整数的表示
- 全部二进制位都是数值位,没有符号位
- 第 i 位的位权是2i-1
- n bit无符号整数表示范围 0 ~ 2n-1,超出则溢出,意味着该计算机无法一次处理这么多位的数字
- 可以表示的最小的数 全0
- 可以表示的最大的数 全1
无符号整数的加法运算
- 计算机硬件如何做无符号整数的加法:从最低位开始,按位相加,并往更高位进位
无符号整数的减法运算
计算机硬件如何做无符号整数的减法:
- ”被减数“不变,”减数“【全部位】按位取反、末位+1,【减法变加法】
- 从最低位开始,按位相加,并往更高位进位
-
为什么要用加法电路来取代减法电路呢?
答:加法电路造假便宜,减法电路造价昂贵。若可将减法转变为加法,省钱! -
为什么全部位按位取反末位+1再相加会等价于减法操作呢?
答:涉及到【数论】的知识,在计算机组成原理这门课里面不过多地讨论。 -
减数B的变形:
-
变形后减法变加法:
带符号整数的表示和运算_原反补
带符号整数在计算机中的应用
- 带符号整数,即”整数“:-2、-1、0、1、2、3、4…
- C语言中的带符号整数:
//位数不同,可表示数值范围不同 short a = 1; //带符号整数(短整型,2B) int b = -2; //带符号整数(整形,4B)
- 带符号整数的表示有:原码、补码、反码
- 同一个含义,用不同的编码方式表示
带符号整数的表示
原码表示
- 符号位 ” 0 / 1 “ 对应 ” 正 / 负 “,剩余的数值位表示真值的绝对值
- 若机器字长 n+1 位,带符号整数的原码表示范围:-(2n-1) ≤ x ≤ 2n-1
- n+1 位,除去最高位的符号位,剩下n位表示数值位,n位可以表示的二进制范围是0~2n-1,再考虑上符号位的正负即可得出表示范围
- 真值 0 有两种形式:+0 和 -0 :[+0]原 = 0,0000000;[-0]原 = 1,0000000;
原码的缺点
- 符号位不能参与运算,需要设计复杂的硬件电路才能处理,费钱!贵!
- 用补码表示真值——符号位可以参与运算
原码→反码→补码的转换(机算)
- 原码更便于人类理解
- 反码处于尴尬的中间状态
- 补码更便于计算机愠怒四年
- 注意上图中原码转换为反码的箭头是双向的,但是反码转换为补码的箭头只是单向的
原码←→补码 快速转换技巧(手算)
- 我们机算的时候是所有的数值位全部按位取反,然后在末位+1
- 如果反码的最后一位是1,以及这个1前面一位还有其他的1,那么我们在末位+1之后就会导致不断地向前进位
- 直到前面的那一位是0,不会再往更高位进位了,此时的0也变成了1
- 则以这个位置为分界线,前面的部分应该是和反码保持一致,而后面的那一部分由于不断地进位1变0,0变1,所以和以前的原码是保持一致的
补码的加法运算
- 计算机硬件如何做【补码】的【加法】:从最低位开始,按位相加【符号位参与运算】,并往更高位进位
例1:+19+(-19)
例2:-19+(-19)
补码的减法运算
再次提醒:加法电路造价便宜,减法电路造价昂贵。若可将减法转变为加法,省钱!
如何快速求一个数对应的负值的补码表示
对比:无符号整数的减法运算
例3
- 计算机内部,所有带符号整数的加、减运算都要先转化为补码
原反补码的特性对比
主要考点:
- n+1 bit 的合法表示范围
- 最大的数怎么表示 / 最小的数怎么表示
- 真值 0 的表示
各种码的基本特性总结:
- 原码和反码的合法表示范围完全相同,都有两种方式表示真值 0
- 补码的合法表示范围必原码多1个负数,只有1种方式表示真值 0
- 由于补码可以比原码多表示1个负数,所以补码中更小的这个负数如果你想把它转化成位数相同的原码是不可能的,转不了,因为用相同位数的原码无法表示 -128 这个数
常见考点:
两个数A和B进行某种运算后,是否发生溢出?——手算做题可以带入十进制验证是否超出合法范围
带符号整数移码表示
原、反、补、移码的转换
移码
- 移码:补码的基础上将【符号位取反】就得到了移码
- 注意:【移码只能用于表示整数】,但是原反补码除了整数还可以表示小数
- 移码一般用于【浮点数的阶码】当中
几种码的基本特性总结
- 原码和反码的合法表示范围完全相同,都有两种方法表示真值 0
- 补码的合法表示范围比原码多一个负数,只有一种方法表示真值 0
- 移码的合法表示范围比原码多一个负数,只有一种方法表示真值 0
用几种码表示整数
小练习
定点小数表示和运算
定点整数、定点小数
- 定点:小数点的位置固定
区别:小数点默认的隐藏位置不同
原码
- 这里有一个小细节
- 如果是定点整数的话一般用一个逗号【 , 】来隔开符号位和数值位
- 如果是定点小数的话一般用一个圆点【 . 】来隔开符号位和数值位
定点小数原/反/补码的转换
定点小数的加/减运算
- 对于两个定点小数A和B进行加法/减法时,需要先转换位补码
- 计算机硬件如何做定点小数补码的加法:从最低位开始,按位相加(符号位参与运算),并往更高位进位
- 计算机硬件如何做定点小数补码的减法:“被减数”不变,“减数”全部位按位取反且末位+1,减法变加法
- 从最低位开始,按位相加,并往更高位进位
定点小数vs定点整数
- 特别注意:位数扩展时,拓展位置不一样【远离符号标点的那一端】
小数补码的加法运算
- 计算机硬件如何做补码的加法:从最低位开始,按位相加(符号位参与运算),并往更高位进位
例1
例2
整数补码的减法运算
- 计算机硬件如何做定点小数补码的减法:“被减数”不变,“减数”全部位按位取反且末位+1,减法变加法
- 从最低位开始,按位相加,并往更高位进位
例1
小数补码的减法运算
- 计算机硬件如何做定点小数补码的减法:“被减数”不变,“减数”全部位按位取反且末位+1,减法变加法
- 从最低位开始,按位相加,并往更高位进位
例1
奇偶校验码(大纲已删)
校验原理简介
奇偶校验码
- 奇校验码:整个校验码(有效信息位和校验位)中“1”的个数为奇数
- 偶校验码:整个校验码(有效信息位和校验位)中“1”的个数为偶数
算术逻辑单元—电路基本原理&加法器设计
算术逻辑单元ALU
- 74181是这块芯片的型号,是很经典的4位ALU
- 右边的 S1 S2 S3 S4 是来自CU的控制信号(控制单元会负责解析指令的含义,根据指令的含义发出一些0101的控制电信号)
- 右边的 M 表示的是当前ALU需要执行的是一个逻辑运算(M=1)还是一个算数运算(M=0)
- 下面的 B3 B2 B1 B0 和 A3 A2 A1 A0 表示的是输入的是B和A两个4 bit的数据,然后经过ALU的计算之后会有一个4bit的输出F,即上面的F3 F2 F1 F0 这里的机器字长就是4 bit
- 还有其他的输入输出信号,是为了和其它的芯片串联而设计的,这里先不深究它们有什么作用
最基本的逻辑运算(1 bit)
复合逻辑
- 同或:异或门的取反
回忆:奇偶校验码
用门电路求偶校验位
一位全加器
串行加法器
并行加法器(串行进位 / 行波进位)
- 虽然刚开始我们就可以把A和B这两个数各个数值位的信息同时输入进来,但是虽然电路实际的计算速度很快,然而这些电信号的传递依然是需要时间的
- 只有低位的计算进行完成之后我们才知道我们要往高位进一个什么样的进位,类比于上图的多米诺骨牌,第一块倒了第二块才会倒下
- 而且只要低位的进位发生了改变,就有极大的可能使高位的数值都发生改变
- 串行进位的并行加法器的运算速度很大程度上取决于我们每一位进位的产生速度
并行进位加法器(同时进位)
回忆:串行进位的并行加法器
如何更快地产生进位?
- 注意到这里的Ci的计算表达式有递归的性质,可以大胆地把递归进行下去
- 最后我们就可以递归到C0,并且C0是刚开始我们就拥有的信息
- 所以我们其实只要根据 Ai-A1、Bi-B1、C0 的信息即可计算得出最后 Ci 的结果
并行加法器的优化
补码加减运算器
加法器原理
- 上面的例子,如果把两个加法器给串起来,也就是在Cout处再连接一个加法器
- 这样的话右边的加法器向更高位产生的进位信息就可以被左边的加法器所接收
- 如果要实现8 bit和8 bit的加法运算就可以把两个加法器串起来,实现加法的位扩展,整体来看就可以支持更多bit的加法运算
补码加/减运算方法
补码加减运算器
补码加减运算器工作过程
补码加减运算器计算无符号整数的加/减法工作过程
- 补码加减运算和无符号整数的加减运算都可以用同一个电路来实现
- 但是二者判断溢出的方式有所不同,所以会导致有时计算出来的结果由于溢出而错误
标志位的生成
- OF标志位仅在有符号数的加减运算中有意义,无符号整数的加减运算中OF=1并不能说明此时发生了溢出
- 无符号整数的加减运算判断溢出得看CF标志位
- SF标志位同样只对有符号数的加减运算有意义,对无符号整数的加减运算是没有意义的
- CF标志位仅对无符号数加减法有意义,对于有符号数的加减法是没有意义的
移位运算
算数移位
原码的算数移位
反码的算数移位
补码的算数移位
算数移位总结
算数移位的应用举例
逻辑移位
逻辑移位的应用举例
循环移位
- 用途之一:大端存储(高-低)和小端存储(低-高)之间的相互转换
乘法运算
原码的乘法运算
手算乘法(十进制)
手算乘法(二进制)
原码一位乘法
-
把被乘数放在通用寄存器X,把乘数放在MQ寄存器上,在正式开始进行乘法运算之前还要把ACC置为0
-
当前位为1,(ACC) + (X) → (ACC),然后ACC和MQ里面的数值同时逻辑右移1位,高位补0,ACC的低位移到MQ,MQ寄存器移出的那个位之后用不到了,所以直接舍弃
-
当前位变为了乘数的次低位,位为1,(ACC) + (X) → (ACC),然后ACC和MQ里面的数值同时逻辑右移1位,高位补0,ACC的低位移到MQ,MQ寄存器移出的那个位之后用不到了,所以直接舍弃(ACC+MQ所有的位忽略乘数的剩余位其余的叫做“部分积”)
-
当前位为0,(ACC)+0 → (ACC),然后ACC和MQ里面的数值同时逻辑右移1位,高位补0,ACC的低位移到MQ,MQ寄存器移出的那个位之后用不到了,所以直接舍弃
-
当前位为1,(ACC) + (X) → (ACC),然后ACC和MQ里面的数值同时逻辑右移1位,高位补0,ACC的低位移到MQ,MQ寄存器移出的那个位之后用不到了,所以直接舍弃
-
当前位为0,但是由于此时的0表示的是乘数的符号位,而乘数的符号位是不用参与运算的,所以此时我们不需要让这个0参与位积的运算,所以在数值位有n位的情况下我们只需要重复n次加法和移位就可以完成乘法操作,不需要管符号位
-
根据X和Y符号位异或的结果修改符号位
- 原码一位乘法中的一位指的是每次都是移位一位
原码一位乘法(手算模拟)
补码的乘法运算
补码一位乘法
- 所谓的辅助位是把MQ寄存器的容量多扩展了一位,是用新扩展的这一位来存储的
- MQ共n+2位,1位符号位,n位数值位,1位辅助位
- 相应的ACC和X等所有寄存器都会采用n+2位,可以采用双符号位补码运算
补码一位乘法(手算模拟)
- 最后一次加法加什么是由原来乘数的符号位决定的,所以我们才说乘数的符号位也参与了运算
- 最后的加法运算得到的结果再拼接上MQ的前n位就是我们最终的结果
除法运算
定点数原码除法运算
手算除法(十进制)
手算除法(二进制)
回忆:运算器的基本组成
原码除法:恢复余数法
-
一开始MQ寄存器的值默认全0,被除数存放在ACC,除数存放在X
-
计算机都是先默认在MQ寄存器的末位商1,然后ACC里面的被除数补码加上除数的负数的补码,如果得出来的结果是负数,则会恢复余数,ACC里面的数加上除数的补码,然后在MQ末位商0,如果算出来的结果是正数则证明此时应该商1
-
计算完成之后只需要把ACC和MQ里面的数值全部统一逻辑左移1位,MQ低位补0
-
然后计算机开始下一位商的计算,默认在MQ寄存器的末位商1,然后ACC里面的被除数补码加上除数的负数的补码,如果得出来的结果是负数,则会恢复余数,ACC里面的数加上除数的补码,然后在MQ末位商0,如果算出来的结果是正数则证明此时应该商1
5. 计算完成之后只需要把ACC和MQ里面的数值全部统一逻辑左移1位,MQ低位补0
7. 重复上述步骤,直到商的位数等于MQ的位数,即n位机器字长
- 真实的余数还要在ACC的基础上乘 2-n
- 不要忘记符号位的计算
原码除法:恢复余数法(手算)
- 最后一次不用左移,所以左移的次数要比上商的次数少一次
原码除法:加减交替法(不恢复余数法)
- 加减交替法就是把恢复余数法中当余数为负数的时候的一系列操作把它统一为一步更简单的操作,是对恢复余数法的一个优化
- 注意:余数的正负性与商相同
- 最终可能还要多一次加法:因为最后若余数为负,需要商0并且加上除数的补码来得到正确的余数
- 所以加减交替法中,加减法总次数可能是n+1次或者n+2次,但逻辑左移只需要n次
- 我们探讨的是定点小数的除法运算,由于是定点小数所以我们最终得到的商肯定也只是一个定点小数,则证明除数肯定大于被除数,如若不然商的结果就会大于1,定点小数不能表示一个大于1的范围
- 硬件就是通过第一步的商来决定的,正常情况下我们被除数减除数的结果一定是一个负值,如果不是负值的话硬件电路就会检测出这个问题,直接停止这个除法的运算,因为这种除法是没办法用定点小数表示的
定点数补码除法运算
回忆下原码除法的加减交替法
补码除法:加减交替法
- 注意在补码的除法中我们写的并不是被除数和除数的绝对值,而是其带符号位的表示(注意和原码的加减交替法绝对值区分开来),符号位直接参与运算
- 步骤:
- 根据被除数和除数是否同号:如果被除数和除数同号,则被除数减去除数;如果被除数和除数异号,则被除数加上除数。上图同被除数和除数异号,所以我们需要被除数加上除数的补码,运算完成之后得到一个新的余数
- 我们得到一个余数之后,我们会根据此时余数和除数是否同号来确定此时我们应该商1或者商0:如果余数和除数同号,我们应该商1,然后让余数左移一位再减去除数;如果余数和除数异号,我们应该商0,然后余数左移一位再加上除数。这里我们得到的余数是负的,除数也是负的,同号商1,余数左移一位并且减掉除数
- 我们又得到一个新的余数,此时的余数是正的,和除数异号,所以我们当前的商应该商0,余数左移一位并且加上除数
- 接下来逻辑是一样的,同号-商1-余数左移1位-余数减掉除数
- 同逻辑,异号-商0-余数左移1位-余数加上除数
- 最后这个余数和除数是异号的,本来我们应该商0,但是在补码的加减交替法中,我们最后一位的商会进行一个比较特殊的处理:我们会把【最后一位的商恒置为1】,这么做的好处是省事,并且带来的误差也不会超过 2-n(结合位权),可以让硬件电路设计起来更简单一些
除法运算总结回顾
- 补码除法中加减次数只有n+1次的原因是末位恒置为1,并不需要原码除法中恢复余数的操作
C语言中的类型转换
强制类型转换
- C语言中定点整数是用【补码】存储的
- 无符号数与有符号数的转换:不改变数据内容,改变解释方式
- 长整数变短整数:高位截断,保留低位
- 短整数变长整数:符号扩展
数据的存储和排列
大小端模式
- 大端方式的存储更符合人类阅读的习惯
- 小端方式的存储更便于机器处理
边界对齐
- 一次读入一行
- 边界对齐方式是一种空间换时间的策略
浮点数的表示
定点数的局限性
从科学计数法理解浮点数
- 由于底数永远是10不变,所以我们可以将底数10省略,只记录阶数
- 阶符为正的话意味着我们要把小数点往后移
- 阶符为负的话意味着我们要把小数点往前移
- 阶码的数值部分又指示了我们的小数点要移动多少位
- 尾数的数值部分越短的话表示着我们能表示的数值的精度越低,如果我们能增加尾数数值部分的长度那么我们所表示的数的精度就上升了
浮点数的表示
- 浮点数:小数点的位数是会左右浮动的,不像定点数有一个确定的位置
- 这里1B的存储空间无法存储9位的数值,那么尾数的末位会被舍弃,此时浮点数的精度会下降
- 能不能把浮点数的表示进行优化,使得在存储空间不变的情况下尽可能地多保留浮点数的精度——浮点数尾数的规格化
浮点数尾数的规格化
- 左规:通过算数左移来把这个浮点数规格化,例如 +0.003 × 10+14 → +3.026 × 10+11
- 右规:通过算数右移来把这个浮点数规格化,例如 +302.6 × 10+9 → +3.026 × 10+11
IEEE 754
移码
IEEE 754标准
浮点数的运算
浮点数的加减运算
熟悉的十进制
机器补码浮点运算
浮点数的加减运算—舍入
强制类型转换
- 在32位机器的情况下,long型也是占32位的,64位机器long型占64位
- double型双精度浮点一定是占64位,其中有1位符号,11位阶码,52位尾数加上隐含的一个1,实际上double类型可以表示的尾数有效数值位应该是53位
- char → int → long → double 无损转换
- 默认long型只有32位,而double型的尾数实际上有53位,肯定能表示32位所能表示的任何一个精度,所以long型向double型的强制类型转换是不会丢失精度的
- 但是如果long型变量占64位,那么long型向double型的强制类型转换就会有精度的损失,53位肯定表示不了64位所能表示的那么多的精度
- float → double 不会损失精度
- float型它的尾数应该是1+23位,而double型是1+52位,float的阶码8位,double型的阶码11位
- 如果是32位的int向float的转换:int表示定点整数,有1个符号位,31个有效的数值位;float变量是1个符号位,8个阶码,23位的尾数(之前还会有一个隐含的1,实际上尾数实际有效数值应该是24位)显然用24位不能表示31位所能表示的精度,因此int型转float型肯定会有精度的损失,但考虑上float型的8位阶码导致float型所能表示的范围肯定比int型更大,所以int型向float型转换只会损失精度但是数字的范围并不会产生溢出,但是float转int不仅可能溢出(超出int所能表示的范围时)还可能会损失精度(当表示
0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111
这种小数转变为int的时候会把末尾全部截断,也就是转变成整数的0)