数字电子技术基础 1.2 二进制算术运算及常用编码

Konten Video AsliPerluas Video
  • 上节课提到的数制转换
  • 二进制的算术运算特点
  • 加减乘除的进位与借位
  • 补码及反码的转换
  • 常用编码类型及其应用

上节课我们讲到了不同进制之间的一个转换。
那么作为一个数来说,实际上它最主要的就是参与各种各样的算术运算。
那么二进制数作为一个计算机里边最常用的进制,它也不例外。
下面我们就来看一下二进制的算术运算有什么特点。

那么算术运算最基本的实际上就是加减乘除。
对于加法运算来说,我们可以看到因为是二进制,所以说只有0和1。
如果是两个0,那么加起来等于0;如果有一个1,加起来等于1;如果同时出现两个1,加1就等于2。
那么二进制分二进一就会产生进位。
那么加法运算可以看起来是非常简单的一类运算。

而减法运算的话,它主要就是需要进行一个借位。
也就是说如果下边的数不够的话,需要向高位进行借位。
然后还有可能就是大数和小数之间的关系出现一个负数的问题。

那么对于乘法运算来说,看起来是比较复杂的,但是实际上我们去一行一行的去看。
比如说第一行实际上第一行它应该是最低位的1乘以10。
由于乘数为1,所以说我们直接把10挪下来保持不动就可以了。
第二行它是由0去和10相乘,乘数为0的话直接就是0了。
那么乘完之后0需要向左边移动一位。
第三行同样是这个道理,先相乘,乘完之后呢,背乘数10再向左挪一位,在之前的基础上再挪一位。
也就是说总共要向左移动两位。

最后一位呢也是一样的,要向左移动三位。
也就是说乘法运算在前边计算的过程中会出现一位的操作。
最后我们再把这4个数相加,也就是说一位和相加就构成了我们的乘法运算。

最后还有一个减法运算。我们发现减法运算实际上仍然是移位和相减的组合。
就比如说第一个10要减去01,那么在这个时候除数不移动,直接相减就可以了。
接下来再减01的时候,就要把01向右移动,移位再减。
再减的话就需要向右移动两位了。
那么持续下去我们就可以计算完除法。
也就是说除法运算包括了移位和相减的操作。

那么我们就可以看到二进制的运算实际上跟我们的普通的实进制运算还是有所区别的。
对于正常的算术运算来说,加减乘除实际上呢是分开的,也就是说它们不能够很容易的合并到一块去。
而对于二进制的运算呢,加法可以保持不变,减法也保持不变,
而乘法我们可以拿加法和移位进行替换,
除法我们可以变成减法和移位的操作。

但有三类运算实际上对于我们的电路来说还是相对比较复杂的。
我们更期望的是一个比较理想的二进制运算。
那么在这个运算中,最简单的加法运算保留一位运算保留,
那么减法运算我们考虑通过某些方法把它转化为加法。
这样的话在我们的电路中就只剩下了相加和一位这两类操作。
那么我们的运算电路就可以大大的减化。
这也是我们数字电路普遍采用二进制的一个主要原因。

具体减法怎么转化为加法我们接下去看。
首先我们看一下减法的一个计算流程。
就比如说我们有a和b两个数,拿a减去b。
那么首先我们要判断的是相减完之后是正数还是负数。
如果a大于b,那就是正数;否则的话我们得到的就是一个负数。
那么确定正负之后,我们还需要确定就是数值的绝对值的大小。
如果a大于b,那么我们就拿a减去b;反过来呢我们就拿b减去a。
也就是说我们是拿大数减去小数。

总结下来就是说,我们的减法运算需要一个是数值比较,确定正负,一个是计算绝对值,大数减去小数。
那么我们需要数值比较电路和减法运算电路,这样子的话我们的电路就会变得比较复杂。

那么怎么样才能够把减法转换为加法呢?
我们就提出了圆码、补码、反码的概念。
由于我们的减法运算中会出现小数减大数,也就是说会出现负数的问题。
所以说我们首先来看如何去表示一个负数。
这时候我们就涉及到两类表示方法或者说两种数,一种是不带符号的,另外一种是有符号的。

没有符号的话,它默认都是正数,也就是说都是大于0的数,没有负数。
而有符号的数就是专门加了一个符号位去定义该数它是正数还是负数。
那么无符号数,比如说有n位,那么这n位都是用来存储数值的。
如果是一个十进制的无符号数,它可以存放0到10的n次方减1个数,减1一共10的n次方个数。
而二进制数一共可以存放2的n次方个数。
反过来,有符号数那么其中最高位它就是一个符号位,它的0和1代表了我们数的正还是负。
而剩下的n-1位才是用于存放数值的。
由于我们相比于上边无符号数少了一位,所以说它存的数的个数要比上边要少。
比如说十进制它只能存放10的n-1次方个数,而二进制只能存放2的n-1次方个数。

那么这一类表示方法,我们把它称之为叫做圆码,也就是说这个是最初始的一个数码。
下边我们来看一个例子,如果是一个4位的实境之数,那么它是一个无符号数,也就是说整个4位都是用来存放数值的。
那么它总共可以存放从0到9共1万个数,有10的4次方个数。
如果它是一个有符号数,那么我们需要把最高位腾出来用作符号位,而存放数值的只有3位。
于是它存的数只能是从正的0到正的9、负的0到负的9,共19个数。

如果是一个4位的二进制数,那么如果它没有符号位,这时候四位都用来存放数值了。
那么我们可以存放从0开始到1结束,共2的四次方16个数。
如果带了符号,那么同样的道理,最高位有一位是符号位,剩余的三位做数值位,这时候它存的数只能是从正的0到正的1,从负的0到负的1,共15个数。

如果我们给一个实际印制数,那么我们是不是可以得到它的源码呢?当然是可以的。
比如说我们现在给了一个14这样的一个实进制数,我们通过前边的进制转换可以把它变成10这样的一个二进制数。
如果我们想表示是一个正的14,那么我们就在10的前边加一个0,代表正数;
也就是说我们用01表示正14。
同样的话,如果是-14,那么我们也是在最高位的前边加一个1,代表负数。
因此的话-14用二进制数去表示就是1110。

如果我们有一个二进制数,我们希望把它转化为十进制数,这时候我们需要考虑的是,它是一个有符号的数还是没有符号的数。
如果是一个无符号数,那么10整个它都是用来表示数的大小的。那么我们转化为十进制,它就是我们的十进制里的10了。
如果是有符号数,那么它的最高位1实际上就是代表了它的正负,也就是说它是一个负数。
而剩下的01代表的是它的数值的大小,那么我们转换为实际因子数就是负2。
这样的话,我们就可以把十进制数与二进制数有符号、无符号通过最高位的符号位去进行了决定。
那么我们把负数表示出来了。

下边的话我们就去看一下减法运算究竟怎么样才能够变成加法运算。
比如说我们现在有一个十进制数,它只有一位,比如说就是6。
那么我们用6减去4,结果等于2。
另外一个,我们可以拿6加上个6,结果等于12。
由于我们现在的只有一位十进制数,也就是说它的进位会被自动舍弃掉,最终只留下一个2。
结果我们就会发现,对于我们的这两个运算来说,6减去4和6加上6的运算结果是相同的。

而且我们发现,4和6相加等于10。
也就是说我们一位实际因素能够表示的一个范围。
于是的话,我们就称6是负4对模相当于是说我们加6和减4相对于模式来说效果是一样的。
那么对应的运算思路就是这个思路,6-4等于6加上-4,等于6加上-4的一个补码,而-4的补码是6。
所以说最终6-4就变成了6加上6的一个运算,我们就把一个减法变成了加法运算。

同样的话,我们再往下看,比如说我们有一个两位的实进制数,一共可以表示10个数。
就比如说6,那么6-4等于2,6加上56等于12。
由于现在只有两位,所以说近位的1捨弃,最后只剩下2。
也就是说,我们发现,对于6来说,-4和加上56的结果是相同的。

同时我们发现4和56相加正好等于我们两位实际因子数能够表示的数量10。
于是的话,我们就称56是-4对模10的补码。
那么这个运算的转换思路就是66-44转化为6加上负的4,
转化为6加上负的4的补码,而负4的补码是56。
所以说最终变成6加上56,也是从6-4的减法运算变成了6加56的一个加法运算。

那么十进制有这样的特点,实际上呢,对于二进制来说同样也适用。
就比如说我们现在有一个四位的二进制数,一共可以表示16个数。
那么10减去01的时候呢,等于01,而10加上个10,最终呢等于10100。
由于只有四位,所以说最高位也被舍弃了。
那么最终我们发现减和加得到的结果都是01。
也就是说01加上10正好等于10,也就是16。
于是的话我们就可以称10是负01对模16的一个补码。
那么计算的一个转换思路就是下边,我们10减去01变成了加上负的01,
变成了加上负01的一个补码,变成了加上10。
二进制的一个减法运算通过补码就变成了一个加法运算。

如果我们去外推,或者说我们把这样子的一个运算推广到n位的二进制数,比如说M这样的一个数。
我们做一个减法运算M-B,我们只需要去找b加c等于2的n次方,然后求c等于2的n次方减b。
那么c实际上就是-b的一个对于模2的n次方的补码。
那么我们就可以把m减去b变成m加上c。
于是的话,我们通过这样子的一个思路就把所有的二进制的减法运算通过补码变成加法运算。

那么我们怎么来去计算补码呢,下边给出了补码的计算公式。
那么这个地方需要注意的是补码运算只针对于数值位,符号位是不参与补码运算的。
下边是补码运算的公式。如果是一个正数,那么补码等于原码;
如果m是一个负数,那么补码就是2的n次方减去m。
那么这个地方我们就会涉及到一个问题:为什么正数它在做补码运算的时候保持不变呢?
这和我们最初始的思路有关系。
我们要解决的是减法运算的一个问题,那么加法运算它本身就比较简单,是不需要动的。
所以说对于正数,都是加上一个正数的时候,我们不需要去管它,直接保持原状就可以了。

而对于负数来说,我们需要通过2的n次方减m把它变成加法运算。所以说正数保持不变,负数要变成补码。
但是我们发现公式里边的一个最大问题就是补码计算的时候要用2的n次方减去m,这是一个减法运算,而我们现在是要用补码去解决减法运算的一个复杂性。
因此的话,我们不可能再用减法运算,所以说我们一般来说不会去直接求。
那么怎么样才能够更快更简单的把补码求出来,我们提出来一个新的叫做反码的东西。

所谓反码,从名字上我们也可以知道它相当于是一个取反的操作。那么对于一个数值位为n位的一个数来说,
我们符号位不参与反码运算,数值位0变为1,1变为0就可以得到反码。
就比如说下边我们有10,我们把0变为1变为0,最终得到的是0101。
那么我们观察它们之间的一个特点,会发现这两个数相加正好等于2的4次方减1。
也就是说如果我们是n类,它应该是2的n次方减1。于是的话我们就得到反码的一个运算法则。

同样的话,我们对于正数来说仍然是保持不变,因为我们不需要对它进行一个操作。
而对于负数,我们可以用2的n次方减1再减去m这样子的公式来表达。
虽然公式看起来很复杂,但是实际上我们操作的时候仅仅是把每一位的数从0变为1,加1变为0。
这样子的话我们在求反码的时候是非常方便的。

那么我们提出反码主要是解决补码的一个问题。
于是的话我们就去对照一下补码和反码,它们之间有什么关系。
那么我们会发现对于m大于等于0,也就是说正数来说,原码、补码、反码,它都是同一个数,它们之间是相同的。
而对于小于0的数来说,一个是2的n次方减去m,一个是2的n次方减1再减去m,它们之间差了个1。
也就是说我们的反码加上1就等于它的补码。
那么这个地方需要注意的就是加1,它是讲的是整个数值类的最后一位去加1,并非整数位的最后一位。
也就是说这个数如果有小数是在小数的最后一位去进行加一操作。

那么通过反码运算我们可以间接的获得补码,从而避免前边直接求补码的时候出现的一个减法运算。
下面我们对原码、反码、补码做一个总结。
比如说有n加1位的圆码,其中符号位1位,数值位n位。那么模数为2的n次方,也就是说最多数值位可以表示2的n次方个数。
那么我们去看圆码符号位,如果取为0,我们可以判定该数为一个正数,这时候呢对应的圆码、反码、补码是相等的。
如果我们发现符号位等于1,也就是说该数为一个负数,那么我们就需要先求反码,
求反码的过程中符号位保持不变,然后呢数值位0变为1,变为0。
接下来我们再求补码,仍然是符号位保持不变,数值位最后一位加1就可以得到相应的补码。

下边我们来看几个例子。
那么比如说我们现在是一个正10,它对应的圆码最高位是符号位,由于是正数,所以说最高位符号位为0,
证实呢等于01,于是的话呢对应的有符号的证实我们可以写成01。
由于该数是一个正数,所以说反码和补码与原码完全相同,我们直接照抄下来就可以了。

接下来是负的10。那么我们表示的时候仍然是直接把10的二进字写出来。
最高位再加一位1,代表负数,于是负10的原码就是10。
由于它是一个负数,所以说我们在求反码的时候就需要把数值位进行取反。
那么符号位仍然是1保持不变,数值位0变1变0,于是反码就变成了10。
求补码的时候呢,我们需要在最低位加1,于是就变成了110110。

同样的道理,如果是一个5.7的正数,那么仍然是我们在正常的二进制数10.的前方加一个0代表正的正的5.7。
由于是正数,所以说它的圆码、反码、补码是完全相同的。
如果是一个负的5.7,那么我们仍然是在10.的二进制数的基础之上最前边加一个1,就是符号位,代表它是一个负数。
负数的话,我们求反码就需要保持符号位不变,数值位取反0变1变0,所以说负的5.7它的反码就是10。
那么后边的两个0是不可以省略的。
而补码呢,就是在最后一位加1。我们发现现在的最后一位实际上是小数点后的第二类,所以说我们是在.00后边加一个0.1,相当于,于是的话变成了补码是10。

那么补码究竟是怎么去用的呢?我们来看一下,对于我们现实中来说,我们常用的是一个实进制的数,
而且我们习惯于用原码进行操作。但是对于我们的数字电路来说,它的运算都是以二进制数来进行的。
所以说我们需要把外界的十进制数原码变成数字电路内部的二进制数的原码。
然后呢我们再做一个补码的操作,把二进制的原码变成补码。
变成补码之后呢,我们就可以进行相应的算术运算了。

那么由于我们在变为补码之后,把减法变成了加法,所以说基本的算术运算就只有一位和加法两类操作了。
那么在做完算术运算之后生成的结果是一个二进制的补码的结果。
对于我们想要输出的话,我们还需要把补码的结果变成圆码的结果。
然后便于我们观看,我们还需要把二进制的源码结果变成十进制的源码的结果。
那么这就是一个整个计算的一个流程。

在此过程中,外部和电路内部我们需要做二进制和十进制之间的一个相互转换,
而在电路内部,源码和补码之间我们是需要做补码运算的一个操作。
那么最核心的实际上是一个加法补码的加法。
那么补码的加法,我们不需要去单独考虑符号位,而是直接以符号位作为一起,然后相加就可以了。
也就是说符号位和数值位不需要区分,直接相加就可以得到正确的结果。

下边的话我们就来看几个例子:
13加10,3减10,负的13加10,负的13减10。
那么我们提前把相应的数的圆码和补码都算出来了。下边我们就来看第一个13加10。
我们实际上是在算正的13加上正的10,因为我们现在是代符号的数,所以说我们前面加一个正号。
这时候我们就去查正13的补码是01,正10的补码是001010。
那么我们前面讲了加法运算直接连符号位代数值位一起加就行了。
所以说我们可以算出这两个数相加的结果是01,我们就会发现最高位符号位仍然是一个0,也就是说得到的结果是一个正数。

那么我们去查这个表会发现对应的补码对应的是正的23。
那么我们再把补码转化为原码,就得到了相应的计算结果。
同理的话,我们在算13减去10的时候,实际上我们在算的是正的13加上负的10。
那么同样我们去把相应的补码写出来,正的13,0,负的10,最高位为1,0。
然后直接这两个数相加,我们就会发现它产生了进位,但是这个进位会被直接舍弃掉,
最后我们得到的是01这样子的一个数。

那么我们同样去查表看一下01究竟代表哪个数,我们就会发现它实际上对应的是一个正三。
接下来我们再看-13加10,我们把它变成了-13加上证实的一个操作,同样-13的补码是10,证实的补码是01。
两个直接相加得到的是10这样子的一个数。那么我们发现最高位为1,也就是说得到的结果是一个负数。
然后我们通过查表可以发现对应的是负3的一个补码,
于是的话我们就可以把对应的结果的一个圆码以及实境制的一个结果写出来。

最后一个是负的13减去10,我们实际上做的是负的13加上负10的一个操作。
-13对应的是10,负10对应的是10,然后两式直接相加。
同样产生了一个进位,但是会被舍弃,最后只剩下10这样的一个数。
那么仍然是一个负数,我们再去查表可以发现它对应的是负的23。
于是的话我们就可以得到结果的一个圆码以及实境制的结果。

可以看到我们通过补码运算,大大的简化了我们电路中这个运算的一个复杂度,从而使我们数字电路它的结构变得相对非常简单。

最后呢,我们再来了解一下几种常用的编码。
第一类编码呢就是我们针对于实进制数的一个编码。
我们呢可以拿4位的二进制数去表示实进制数,但是呢4位二进制数是2的4次方,一共16个数。
实际上我们的0到9只有10个,也就是说我们只需要选10个数出来就可以表示了。
那么剩下的6个数是没有用的,那么我们根据编码的规则可以分下边这么5类:

第一类是BCD码,也称8421码;
第二类是241码;
第三类是521码;
后边是余三码和余三循环码。

那么首先我们看八四二一码、二四二一码、五二一一码。这三类编码实际上它都属于横全的一个码。
也就是说对应的每一位的全,它是恒定不变的。
那么八四二一码的意思就是说我对应的这四位,它的全是八四二一。
那么我们怎么样去对它进行编码,或者说我们拿到一个代码之后,我们如何去知道它对应的实际因子数呢?
实际上我们只需要把每一位数和它对应的权重相乘,然后把结果累积求和就可以算出来。
比如说我们的241码里边的10,那么我们直接拿241这个权和对应的数码1101分别相乘得到的结果分别是2401,
然后我们再把这4个数相加得到的是一个7。
也就是说在241码里边10对应的是实进制数的7。
那么对应的求实进制数的方法对于8421码也是同样适用的。

那么余三码和余三循环码是另外一类,它们都属于非横全码。
也就是说每一位的权重它是在变化的。
那么为什么叫余三码呢?主要就是说如果我们把余三码看作一个四位的二进制数,
那么我们就会发现它的数值和它表示的实境之数要多三。
就比如说我们的余三码10,那么它对应的是10这样子的一个实境之数。
但是我们通过查表,我们会发现它表示的实境之数实际上是7。
也就是说它真实的7和它翻译成实进制数的10之间差了一个3。
因此的话它就被称之为叫做余三码。

那么余三循环码它是另外一类,它的主要特点就是说我们相邻的两个代码之间只有一位的状态发生变化。
也就是说它会出现一个循环的结构。

除了十进制数以外,我们还可以表示16进制数,
那么用4位的二进制数就可以进行表示了。
这么在16进制数里边我们最常用到的叫做格雷码。
那么格雷码如果我们仔细去观察,它的每一位都是有一定的规律的,它都是按照一定的顺序在循环的。
所以说格雷码我们也称之为叫做循环码。

那么格雷码主要的好处在于相邻的两个代码之间仅有一位发生变化。
也就是说代码转换的过程中更加平稳,不会出现噪声。
那么下边我就来看一下什么叫做过渡过程中的噪声。就比如说我们正常的二进制数5是00000101,6是00000110。
如果我们加1从5变到6,我们就会发现有两位要发生变化。
就比如说01变到01,在理想情况下这两位要同时发生变化,那么我们就可以直接过渡过去。
但是在真实的情况下这两个数,它的先后顺序肯定是不能够完全相同的。
有可能是第一位先改变,从01变成了01;
然后第二位再发生变化,再变到我们的最终结果0110。
还有可能第二位先发生改变,变成了01;
然后第一位再改变变回我们的01。
那么在变化的过程中我们就会发现,它实际上出现了两个我们不希望出现的数。
于是的话就相当于我们出现了噪声。

但是对于格雷码来说,我们从01变到01,我们就会发现只有最后一位在发生变化。
那么不管它有没有先后顺序,它永远都只有一种可能性,不会出现中间状态。
于是的话它就可以避免相应的过度噪声。

那么除此之外,我们常用到的还有另外一类叫做美国信息交换标准代码。
那么它是由美国国家标准化协会制定的一种信息代码,它主要实际上是由7位的二进制代码组成的。
那么2的7次方等于128,也就是说对应的这个ASCII码可以表示128个字符。
那么其中数字0到9占了10个,大小写的英文字母占了52个,
此外还有一些其他的各种符号32个,还有控制码34个,总计128个。
那么ASCII码现在是一个国际的通用代码,在我们的计算机和通信领域应用非常广泛。

那么下边就是一个ASCII码的一个表格,这个表格的话在我们的计算机系统里边应用非常广泛。
就比如说我们学C语言的时候,为什么把97输入进去,结果输出来是英文字母a,是小写的英文字母a。
实际上它里边就是内嵌了一个ASCII码的一个表格。