我们进入第二章的学习,就是定点数的表示和运算。
那关于定点数呢我们分为两块内容,一块呢就是定点数的表示也就是我们这一节的内容,一块呢就是定点数的运算。这两块内容呢都非常的难,也都非常的重点。希望大家呢引起重视。
那么我们首先来介绍无符号数和有符号数。那么关于无符号数呢就是说,它是没有正负号的这些数据,那我们在进行编程的时候,在C语言当中,我们已经使用过无符号数。那么在我们这门课里呢就要讲解在计算机当中是如何存储和表示这个无符号数的。那么无符号数的存储和表示都非常的简单,因为它只有数值部分,所以我们只需要把它变换成二进制然后用计算机当中的寄存器或者是存储器按照规定的长度把它保存在计算机当中就可以了。
那么它的数值,我们之前讲过。就比如这个例子当中,10011100B二进制它就是用这个公式把它算出来,代表的是156就可以了。
那么寄存器的长度就直接地给出了或者说直接地反映出了无符号数的表示范围,那么就比如说我们的寄存器的长度如果是3位的话,那么就是8。如果它的这个寄存器的长度是4位的话,那就是16。
那比如说,那么这个存储器的长度就给出了它能够表示的无符号数的范围,就是0-2^n-1。那么这是无符号数的表示,是一个非常简单的,我们只需要保存它的数值位就可以了。
那么如果是一个有符号数的话,就不一样了。有符号数是什么意思呢?有符号数是指的,有正负号的这一些数,
也就是包含了它的符号位和它的数值位。那么有正号和负号,但是它的正号和符号怎么保存到计算机当中呢?我们就用0和1来表示它的符号。0和1,高电平和低电平这两种状态来表示数值的符号。
那么什么叫做真值呢?真值就是指数字真的值。也就是说,带有正负号的这个真实的值。那么什么叫机器数呢?机器数就是说,我们保存在计算机当中是怎么保存的?保存在计算机当中的这一个数我们就把它叫做机器数。那么这就是真值和机器数的概念。那么保存在计算机当中我们要保存什么呢?要保存这个数字的符号,还要保存这个数字的数值。那么还有一点,就是要保存小数点。
那么我们在计算机当中,用0来表示正号,用1来表示负号,那么这就是机器数。包括它后面的这些10011100我们可以直接放到这个计算机当中,但是小数点怎么办呢?这一点我们大家一定要清楚在计算机当中是没有专门的硬件用于表示小数点的,也就是说没有任何硬件是表示它是一个小数点。那么计算机当中,小数点呢是如何来保存的呢?我们都是以约定的方式给出的,所以就把它叫做定点数。
那么用约定的方式表示这个小数点呢,也就是隐含存储的话,那么我们就把它叫做定点数。而浮点数呢是指这个小数点按照规则进行一个浮动,我们将在下一节进行讲解。那么小数点呢它是没有专门的硬件来表示的,它就是以一个约定的方式给出它在哪儿。
那么如果我们这是一个纯小数的话,也就是定点小数的话,我们约定在符号位的后面,在数值位的前面它表示一个小数点。那么什么叫纯小数呢,也就是说它的范围是0-1的,它的范围就后面全是小数。它是0-1的,那么我们的符号位后面就是小数点的位置,那么后面就是小数点后面它的数值。
那么它所能表示的范围是什么呢?比如我们来看一下,正的0.75我们如何来表示呢?0.75首先把它转化为一个二进制数,然后正号呢我们用0来表示。
所以就是011。这就是我们在计算机中如何存储的。
那么如果是-0.75D的话,我们存储就是111。1代表的呢就是负号。
那么它所能表示的范围是多少?它最大能表示的绝对值就是K-1*(2^-1)+K-2*(2^-2)+K-m*(2^-m)。
如果在这一个例子当中,也就是说我们如果它的这个数值部分只有2位的话,那么它所能表示的范围就是从绝对值从0.00到0.11。
也就是从0到1-2^-2。因为它的这个数值部分只有两位,所以它最大能表示的呢就是1-2^-2,这是它的绝对值。
所以它所能表示数的范围就是从-1-2^-n到+1-2^-n,
这就是有n位尾数的定点小数,也就是纯小数。
那么我们的整数是如何表示它的小数点呢,
我们约定这个小数点呢是在最后的,也就是在数值部分的最后,那么这就是定点整数,我们约定小数点都在整数的最后。
比如我们的正3,+3D如果表示成这个二进制的话,就是11。然后前面添一个符号位就是0,所以它呢写起来就是011.那么这个.呢它是不保存的,我们只是约定这个小数点就在这个数值部分的最后,所以它储存的呢就是011。-3D同样的储存就是111。
那么它表示的范围呢就是从0-2^n-1。2^n-1,如果它的数值部分是n位的话,那么它的绝对值就是0-2^n-1。
那么如果把符号位考虑进来的话,就是从-(2^n-1)-+(2^n-1)。那么这就是有n位尾数的一个定点整数。那么定点数就是说我们的小数点是约定位置的,小数是在符号位的后面,数值位的前面(符号位和数值位的中间),然后这个整数就是在符号位和数值位的最后。它的表示范围呢大家也一定要清楚。
那么这一节的内容呢我们就讲完了,我们讲了什么,我们讲了无符号数是如何表示的,很简单,用存储它的数值位就可以了。然后我们还讲了真值和机器数,那么真值就代表它真正的值,包含符号位的这样一个值。机器数就是它是如何这个有符号数是如何存放在我们计算机当中的。以及我们的定点数是什么意思,定点数就是说我们的小数点是约定位置的。
实际上呢我们把符号数字化,或者符号数值化,就已经给出了一种机器数的表示方式,我们把这种方式呢就称为原码表示法。那么我们这一节的内容就是来讲解原码表示法。
那么我们讲解的呢就是有符号数它有四种表示方法,原码、补码、反码、移码。我们每一节讲解一种表示方法。
这一节的内容就是原码表示法,下面我们来看一下原码表示法的定义。
这个定义呢我们以数学的方式给出,我们区分整数和小数。我们首先看一下整数,如果这个数据、如果这个数值是大于等于0的,小于2^n。那这个n是代表的数值部分的位数。那么我们原码表示法呢就是0,这个0表示的就是符号位,说明这是一个正数或者说是一个大于等于0的数。那么x是增值部分的这个数值部分,如果是负号的话,如果它的符号位是负号的话,是负数,我们就把它的符号位呢变成1。整数的数值部分呢是n位,那么如果我们的符号位的部分是1,符号位的部分是1,那么相当于给这个数据的绝对值加上了2^n,为什么呢?因为我们符号位的位置是n+1位的。后面n位,前面再加1位符号位就是n+1位。那么,它的权值现在是1了,符号位是1,所以就是2^n。所以呢当我们的增值是小于等于0的时候,我们的就是2^n-x,表示的就是这一个原码表示法的定义。其中x是增值的数值部分,n呢是它增值位的位数,或者说我们整数的数据位的位数。那么在这里我们一定要注意一下我们的用的是大于号,在这个x呢是大于2^-n,这里是用的大于号没有等号,为什么呢?因为呢如果我们是n位的话也就是说如果我们的数据位全都是1,它能够表示的最大的整数也是2^n-1,当时我们已经讲过了。所以这时候我们是大于-2^n,是大于不是大于等于。它最大也达不了这个2^n。同样的这个如果是这样的我们是用的x是小于2^n,小于2^n,就是达不到2^n的。好的,我们表示的这个范围就是从大于-2^n到小于等于0。如果是正数它就从大于等于0到2^n。
比方说我们举个例子。如果x=+1110,我们用原码表示法定义的话,我们根据前面的这个定义,这个符号位的,因为它是个正的,所以我们先写个0,然后再写个逗号把它隔开。写个逗号,然后它因为是正数的话我们就直接照抄就可以了,也就是0,1110。那么如果是我们的这个x是等于-1110,根据我们前面的定义,我们假设,我们假设我们的数值部分是4位的,所以这时候n=4,因为它是一个小于0的一个数,所以我们就要用2^n-x来得到x的原码。所以呢2^n就是2^4-x,因为x是一个负值,因为是负值,-x就相当于+|x|。所以呢就是1,1110。就是用2^4-(-1110)也就是用2^4+(1110)也就是1,1110。而这就是我们一个例子,逗号是什么呢?逗号就是用来把符号位和数值位隔开的,只是为了读写方便,并不是说计算机当中真存了一个逗号,不是这样的,只是为了读写方便而已。如果我们前面举的例子以及我们数据的定义我们可以看出,如果增值是正值的话我们就用0来表示符号,0作为存储到计算机当中的这个数据的符号。同样的,如果是负号的话,我们符号位就是1,把1存储到计算机当中。因此呢原码表示法实际上是带符号的绝对值表示。带符号的绝对值表示,我们保存的呢是数据的绝对值,在符号位部分我们加上0和1来表示正数或者是负数。实际上呢就是我们的绝对值然后再加1个1或者0,这个符号呢也是被数值化的。这是我们的整数部分。
那么我们整数所能表示的最大的范围呢就是刚才也讲了,是2^n-1,达不到2^n,所以是2^n-1。然后最小的范围呢就是2^n-1加一个符号,-(2^n-1)。这是我们原码表示的整数的表示范围。它是关于原点对称的,因为它是就直接加一个绝对值然后再加一个它的这个符号位就可以了,非常的简单。
那么我们小数是如何表示的呢?小数啊,它的也就是0.x1x2..xn,注意是纯小数,就是我们之前讲的定点数嘛。那么它是如何表示的我们给出这样的一个定义。如果这个小数它的值在1和0之间,包括0不包括1,那么它的原码就是它本身,然后去掉这个符号。那么符号位呢我们用小数点前面的0表示它是一个正数,啊,直接就是x就可以了。那么如果它是一个负数的话,我们就把小数点前面的那一位作为符号位,也就是用1来表示它的符号位。数值位照抄,把它存放到寄存器当中。然后呢我们就是1-x,另外大家还要注意我们后边的这个符号啊,小数形式的0按照原码呢是有两种可能的,因为它在上面也可以在下面也可以,都有等号的。那么x是它的真值。
比方说,我们来举一个例子。如果x等于+1101,那么它的原码形式我们直接就用0.1101来表示。啊,注意这时候前面这个0和后面这个0意思不一样。前面的0表示它的数值,0.几的这个0,后面这个0是什么呀?后面这个0表示它的符号位,说明它是正的。那么这个点我们刚才也讲过了,这只是定点数的一种表示方法而已,在计算机当中是没有存储的。那么我们再来看一下如果是-0.1101的话,那么它的原码就是用1-(-0.1101)也就是1.1101。1.1101,这时候1代表的是什么呢?1代表是它的符号位,1101代表的是它的数值部分。同样的这是n=4的时候。如果n=8的话,那么我们还是用同样的方法来看,如果它是正的0.1000000,那么它的原码呢就直接用x来表示就可以了,前面的0和后面的0还是不一样的。那么如果是负的话还是用我们的定义,用1-(-0.1000000),就是1.1000000。这时候1代表的是什么呢?1代表的是它的符号位,是负的。那么我们这里的.是什么呢?这里的.,代表的是用符号位和数值位隔开的那个符号。这个无论是整数的逗号,还是小数的小数点,在计算机当中都是不需要进行存储的。因为这个逗号和点都是我们为了阅读和方便书写而加上去的,这一点我们要注意。那么其实这个真值和原码呀,是非常简单的。真值到原码的变化非常简单,如果是整数加1个符号位加1个逗号。如果是小数呢就加一个符号位加一个小数点就可以了。
那么这个小数的范围呢是从-(1-2^(-n))到1-2^(-n),从负的到正的,它也是关于原点对称的。那么,无论是整数的逗号和小数的小数点呢,在计算机当中都是不需要进行存储的,因为它仅仅是为了人阅读和书写方便而加上去的。这一点呢我们一定要注意。
那么原码呢,是非常简单的。所以它的特点就是简单、直观,如果是一个整数我们只需要加一个符号位然后呢再加一个逗号然后其他全部照抄,小数也是一样的,我们只需要加一个符号位再加一个小数点,其他全部照抄就可以了。它简单直观,它有这么多的好处,但是我们为什么还要有其他的这种什么反码、补码呢?它是会出现问题的。比如说我们要做两个正数进行加法运算,它们实际运算呢就是一个加法,所以它的符号,结果的符号也是正的。但是如果是一个正数加一个负数的话,我们实际操作是做一个减法,是做一个减法,然后符号位呢也可能正的也可能是负的,负的加正的同样呢也是做一个减法,结果呢也是可正可负的。两个负号呢进行加法的话,就是加法,所以它的结果还是负的。我们就想到它如果是要做一个加法的话,我们实际操作又是加又是减的,特别的麻烦,那么我们能否不做加法呢?或者说我们能否找到一个与负数等价的一个正数来代替这个负数来进行一个加法呢?我们这样呢就可以使得减法变成了加法。我们进行无论是正数和正数相加还是正数和负数相加,我们得到的结果呢都是进行加法运算,把减法运算呢就变成了加法运算,能不能如此呢?我们下面的这个补码,就解决了这样的一个问题。
我们来看补码表示法,
我们回顾上一节的最后我们提出的这样的一个问题。如果我们要进行加法运算的话,如果用原码表示会出现问题。我们来看这样的一个例子。如果我们用00001110+10001110的话,我们列竖式进行相加,那么二进制的加法和十进制的加法呢其实本质上还是一样的,只不过就是逢2进1,也就是1+1应该得到的是10,也就是写0再减1。那么得到的结果应该是10011100。这时候如果我们把它全部改成是无符号数的话,
我们得到的结果应该是14+142得到的就是156,
是没有任何问题的。
但是如果现在我们把它看成是有符号数的原码,这时候我们应该是14+-14,如果是这样的话呢我们本应该得到的是0,
但是现在我们却得到的是10011100,显然是不正确的。
那如果我们要进行这样的14+-14的话,应该怎么来进行运算呢?首先我们应该是这样的,14+-14,我们可以看成什么呢?我们经过,因为它是一个负数,我们看到它符号位是1嘛,所以我们现在应该把它做一个变化,
14+-14应该是14-14,也就是用00001110-00001110得到的就是0,
这样就没有任何问题了。但是有没有发现,如果要进行一个正数+一个负数,我们首先要把它变成正数-一个正数,是不是非常的麻烦啊。我们还要根据符号位去进行判断,再进行把加法变成减法。这时候是非常麻烦的,我们就想到了一个就是说我们能不能用一个方法去把减法统一成加法,就是加一个负数我们还是要进行加法而不是说根据它的符号位进行改变规则,把加负数变成减正数,这是我们不想要的。那么我们怎么样进行这样的一个变化呢,这样一个转化呢?
我们从生活当中的一个经验来出发。如果现在我们的钟码是十点,它走快了,我们现在要把它变成八点。
那么怎么进行变呢?我们有两种思路,第一种思路,我们去逆时针去拨两个小时,就是相当于我们就是向前去走了两个小时。就是因为它走快了,我们就逆时针地过两个小时。
就是这样。逆时针地去过。
逆时针地过相当于什么呢?相当于用10减掉了。我们得到了8点。那我们还有一种思路是什么呢?
我们还是按照顺序那样进行过,这时候应该怎么过呢?应该是向前去拨十个小时,那就是顺时针了,就相当于10+10得到的应该是20。这是我们得到的结果都是一样的,得到的都是八点。那么时钟为什么是这样的?有这样的一个现象存在呢?因为这是模12。就是说每经过一个12,它就会又变成了1,好,这是模12了。
这时候我们就说,-2可以用+10来代替,也就是说我们的减法可以变成加法了。减2就可以相当于加-2,所以呢我们就说-2和+10在模12的条件下是相等的。同样的,我们说-4和+8在模12的条件下是相等的。-5和+7呢也是在模12的情况下是一样的。也就是说,它们做减法和做加法操作,减掉5和加上7效果是完全等同的,因为时钟呢是以12为模的。
这时候我们就得到这样的了一个结论,是什么呢?就是说一个负数,如果加上一个模,就得到了这个负数的一个补数。就比如说刚才我们的-2,我们如果加上一个12,就是加上这个模啊,我们得到的是10。所以我们称10和-2是互补的,或者说10是-2的补数。那么一个正数和一个负数互为补数的时候,它们的绝对值之和就是一个模。就比如说刚才的-2和+10,它们的绝对值相加呢就是12。
这样我们就可以进行一个把负数变成正数的这样一个操作。那么计算机当中的数据存储,和时钟实际上还是相似的。我们举一个简单的例子,如果说我们现在要求放一个整数,我们规定啊这个存放这个正数的寄存位的位数是四位,那么寄存器在我们计数的时候,就是模16了。一旦我们的加法操作是它的值,大于或者等于16,那么进位部分将要被自动地舍掉。因为它只能存4位嘛,所以多出来的我们要被舍去。这一点呢和这个时钟非常相似。我们时钟是模12的。这时候我们在这个例子当中我们是模16的,因为是4位的。比如说我们现在是1011,我们要把它变成0,我们有两种方式。
第一种方式,大家很容易想到。就是用1011-1011得到的就是0。那么第二种方式呢?大家可能不容易想到。但是我们用刚才的时钟的思路来理解一下。我们应该是加什么呢?就是加1个数,加1个它的补数,加1个补数就变成了10000。这时候,我们刚才已经说了就是说它只有4位,我们多出来这个进位1将要被舍掉。这时候我们保存在计算机当中的还是0000,有没有发现。减掉1011,和加上0101,它其实是等价的,得到的结果都是0。所以呢我们就说,-1011和我们+0101实际上是等价的,实际上是互为补数的。我们这时候就很简单了,那么我们减法操作减掉的1011完全可以用加法操作加上0101来进行替换。
所以我们就继承什么呢?继承-1011,再模2^4,也就是模16的条件下和+0101是等价的,也就是它们是互为补数的。
这时候运用这个思想我们就提出了我们的补码计数码的概念。一个正数,它的补码和原码是相同的,因为一个正数它的补数还是正数,还是它自己,你不信你可以用刚才的这种方式验证一下。我们记住这个结论就可以了。补码,就是正数的补码和原码是一样的,也就是[x]补=[x]源。负数呢,负数是这样的规定,也就是说我们的原码的符号位不变,数值部分按位取反啊。按位取反,什么叫按位取反?每一位0变成1,1变成0,然后末尾再加1,也就是取反加1。然后这样的条件呢还是如果知道补码去求原码还是用这样的一个结论,还是用这样的一个算法。
这时候它有8位嘛,我们就用刚才的,和刚才的思维其实是等价的。我们就用在这个8位的条件下它的这个补数来进行替代就可以了。
我们的纯整数的补码,我们给出它的定义。我们其实这样的定义呢我们不记也没有关系,就用刚才我给出的两条算法就可以了。正数的补数还是它自己,它的数值部分如果是n位的话,那么所能表示的最大的值就是2^n-1,所以x呢是小于2^n-1的。那么它的补码我们就用0来作为它的符号位,然后加上一个逗号后面直接写出真值的数值部分。那么如果它是小于0,大于等于-2^n的话,注意这个当中我们两边都有了这个等号,都有了等号,因为我们的数值最小可以表示到-2^n,这时候我们就用2^(n+1)+x,注意这个x不是一个负数。或者呢我们就是用2^(n+1)去减掉x的绝对值,就是我们所在这个模下面它的补数,就可以得到它的补码了。其实我们的刚才已经分析过这个东西了。
好的我们来看一个例子,字长是8位,包含了符号位,也就是说我们这里的n应该=7,其实呢我们这是用我们的定义算出来的。如果我们不用减法,减法算起来还是比较麻烦的。如果我们就用刚才给出的结论,就是说数值部分按位取反,算下来的结果还是一样的为什么呢?因为它的数值部分是多少,是7位对吧,等于是0001010,按位取反变成了1110101,然后末尾再加1个1也就是说1110101+0000001就变成了1110110,然后前面再补一个符号位1,逗号,1,1110110。其实大家算补码的话,用这样的方式是更简单的,而不是要用这个定义来算。定义只不过是帮助你理解补码是如何产生的,但是如果要你求的话,你用这个方式呢,按位取反的方式,按位取反再加1的方式呢是更加的容易的。
那么如果我们知道它的补码,怎么求它的原码呢?其实还是一样的。还是按位取反再加1。一样的,还是按位取反再加1。
因为呢,这时候的补码就相当于[-x1]补。[-x1]补然后再求它的原码呢,就可以还是用按位取反再加1,得到的就是它的原码了。
我们看一下它表示的范围,刚才我也已经说过了,它能够表示的-2^n到2^n-1。它的最小的这样一个数是能够表示的-2^n,因为它可以加1。但是它最大的呢,最大的还是和我们原码的范围是一样的,2^n-1。那么我们可以看到啊,它能够表示到-2^n,那么它表示出来就是1,0000。这是我们完全可以表示的。
那么这是整数的,我们小数是如何表示的呢?
小数和整数其实还是异曲同工的,给出来的定义,如果是它的,如果它是正数的话就是x,如果它是负数的话就是2+x,也等于2-x的绝对值。小数它是补码,它是模2的啊。补码是模2的,所以这时候我们用2来减,2来加上这个x就可以了。
我们给这个例子,
那么x1它是一个正数,我们只需要用0.1001000把它补全了,因为它是数值位是7位,所以我们就要把后面再加几个0。然后因为它是一个正数,所以它的符号位是0就可以了。
那么x2呢,x2我们就要用2去加上x,这个x呢是个负的所以我们就用2减掉x的绝对值,也就是10.0000000-0.1001000得到的结果呢就是1.0111000。其实它的算法还是把它按位取反再加1就可以了,那么按位取反是什么呢?我们看到啊它的数值部分是1001000,我们按位取反变成了0110111,然后再加一个1就是0111000,还是一样的。我们有两种方法,一种呢就是根据公式来计算,一种呢就是按位取反再加1。按位取反再加1是比较容易理解的。
那么如果知道了它的补码,去求它的原码还是一样的。用这种方式,按位取反再加1。也就是0,这时候0111000按位取反变成了1000111,然后再加1就是1001000,还是一样的这种方法。
它的这个范围是从-1到1-2^-n。正数范围和原码是一样的,负数范围它可以表示到负1。那么-1它的补码也给出来了,应该是1.0000。好,这就是我们的补码。其实理解起来就是用我们的时钟进行理解,计算的话我们只要正数不变,负数就是按位取反再加1就可以了,公式只是帮助你理解的,你可以记住它,你不记也没有关系,我们只要知道它是怎么变的就可以了。
我们来看一下反码。
那么在补码的时候我们刚才说了什么呀,我们说是负数的话,符号位是1,后面呢数值位是按位取反再加1。那么反码呢?比补码要简单一点,我们把加1这个操作去掉就可以了。好的,正数的话我们的反码和原码还是一样的。我们注意到,正数它的原反补都是一模一样的,都是符号位是0,然后数值位和它不变,是什么就是什么,照抄就可以了。那么对于负数的话,原码符号位不变,原码的符号位是不变,还是1,数值部分按位取反。同样的规则也适用于已知反码求原码。还是一样的,符号位还是1,数值位按位取反,0变成1,1变成0就可以了。
表示范围和原码是一样的,因为它只是按位取反,并没有做任何操作,所以范围还是一样的。我们来看一下。纯整数,纯整数的它的这个如果是正数的话,就是0,x。如果是负数的话,就是(2^(n+1)-1)+x。为什么是这个样子的呢?我们是这样的,因为我们最后在那个计算反码的时候,我们计算补码的时候是要加1的。而计算反码呢不需要加1了,这时候我们2的n+1次方就要减掉1。这时候它的模,之前是模2的n+1次方,现在我们不加1了,就是模2的n+1次方去减1就可以了。这个2的n+1次方减1就是这么来的。因为我们算补码的时候是按位取反再加1,而这时候我们不需要加1了就要把它减掉了。这时候就是根据补码来推这个反码的它的公式是这样的。其实这个公式大家不一定要记住,只是告诉你可以这么算。但是这样的公式呢我们只是了解一下就行了,其实我们真正进行计算的时候还是用这样一个规则就行了也就是按位取反就可以了。
比如说我们x1=+1011,x2=-1011,字长是8位也就是有1位符号位,7位数值位。它的反码是如何表示的呢?
如果是正数的话,就是0,0001011。那么x2呢,我们如果用公式算的话就是用2^(n+1)-1。2^(n+1)减1呢就是1,1111111,然后减掉我们的x2,减掉我们x2的绝对值,得到的就是x2的反码。其实还是不需要这样计算,我们只需要用这样的规则就可以了。我们的x2因为有7位,所以我们前面要补3个0,也就是0001011。然后按位取反,就变成了1110100。好,这就是我们的反码。
如果已知反码去求原码还是一样的。我们的符号位不变,然后呢按位取反。0001011,我们可以看到是一一对应的。
如果字长是n+1的话,那么字长是n+1,有1位是符号位,也就是数值位是n的话,那么反码的表示范围和原码是一模一样的,是关于原点对称的。
纯小数还是一样的。纯小数因为我们还是加1不加了,加1不加了我们模就是2-2^(-n),公式了解一下即可,我们只需要知道它是怎么变换的就可以了。例子我们再看一下。如果x1是正的0110,x2是负的0.0110,那么x1是正的话我们直接和它的原码是一样的。0,这里的0,第一个0代表是它的符号位,是正的。然后它的反码呢如果我们用公式计算的话是这样的,其实我们不需要用公式计算,我们用这样的一个规则就可以了,就是按位取反,按位取反。因为它是0.0110,它只有4位,这时候它的数值位只有4位,我们需要在它后面再补3个0,就是0110000。然后我们再按位取反,就变成了1001111,这就是我们x2的一个反码,然后前面再添一个符号位1就可以了。已知反码求原码其实还是一样的过程。我们还是符号位是1,后面呢按位取反,1001111按位取反变成了什么,就是0110000。它的表示范围和原码是一模一样的,还是从-1+2^(-n)到1-2^(-n),是关于原点对称的。好的,这就是我们的反码是如何计算的。其实最难计算的应该是我们的补码,原码和反码呢其实在一定程度上是一一对应的,就是按位取反就可以了。而这样的补码就比较困难了,补码呢就是要在反码的基础上再加1个1就可以了。
我们来看原、补、反相互的转化。我们最高位都是它的符号位,如果是整数的话我们用逗号隔开,如果是小数的话我们用小数点隔开。对于正数,原码=补码=反码。就是正数,它的原码、补码、反码都一样,都是0,一个数值。那么对于负数的话,符号位肯定都是1,那么它的数值部分呢,原码除了符号位以外的数值部分按位取反再加1得到补码,那么原码如果除了符号位以外都是1以外,然后数值部分按位取反得到的就是反码,这也是反码这个名称的由来。好,这是我们之间的一个相互转化。知道这个就可以了,那么我们最重要的还是补码的计算。补码的计算大家一定要记住。
我们之前已经讲完了原码、补码和反码以及它们之间的相互转化。我们最后再讲一个叫做移码的概念。那么移码是用来干什么的呢?为什么还要再引入一个移码的概念。我们来看这样的一个问题。
也就是说我们的补码是很难表示真值大小的,也就是说它谁大谁小我们是看不出来的,一下子是看不出来的。也就是说我们一下子是看不出来,如果直接看补码的话,看不出来哪个大哪个小的。就比如说我们的+21和-21,我如果用补码表示的话是010101,在计算机内部这个逗号是没有的。然后-21的话是101011。我们可以看到,下面的比上面的大,显然是不对的。再比如说+31和-31,如果用补码表示的话一个是011111,一个是100001。显然还是下面的比上面的大。如果直接看它的数值的话,那么是很难直接判断哪个大哪个小的如果用补码表示的话。这时候,如果我们在它的基础上加上一个2^5的话,加上一个2^5也就是加上1后面5个0的话,我们就可以看到就是如果进行了如果有溢出的话,什么叫溢出我们在后面再来讲,也就是如果它有进位的话我们把进位全部舍掉,只保留最后的那6位。我们可以看到,上面的是比下面的要大的,显然一眼就能看出来了,那么这就是移码。
移码就是说我们在真值X上加一个常数,加一个偏置的一个值,把它加上一个数之后把它进行一个移动,那么这个常数呢我们一般是取2^n,比如刚才我们就是取2^5,加上1个1后面5个0。
那么给出它的定义就是,不管是正数和负数,都是2^n+x它的真值,不管正负都是加上x。
我们数轴上是这么表示的。也就是说一个真值去就相当于整个地将它移动了一下,就变成了一个移码。只有整数才有移码,我们可以看到为什么呢?因为这是和它的用处是有关的。我们的移码是一般用来表示浮点数的阶码,那么什么是浮点数的阶码呢我们将来在浮点数那里进行讲解。反正你知道,因为为浮点数的阶码是整数,所以它是用来表示浮点数的阶码的。所以只有整数才有移码的。也就是说它在一个真值x上加一个常数,加一个偏置的值进行一个移动,就是相当于在数轴上向正方向移动了一些单位,那么这就是移码的意思。
我们来看两个例子。比如说x1=+10101,x2=-10101,如果字长是8位的话我们就在x1和x2的基础上都加上2^7,就可以得到它的移码了。x2同样的,不管是正数还是负数,都是加上2^7,得到的就是它的移码了。
好的我们来看这样的一个表格。我们给出了机器数,给出了如果把机器数看成无符号数的话它是多少,也就是0-255。如果是把它看成原码的话,也就是从+127到-127,并且正0和负0是有区别的。如果是反码的话呢,就是从-127到+127的,啊,还是一样的。正0和负0是有区别的,因为它和原码的表示范围是一样的。但是补码就不一样了,补码它的正0和负0都是0000 0000,然后它的范围呢是要比反码和原码要大一点的。是从-128到+127。
那么这就是我们移码的概念,我们只需要掌握它是如何计算的就可以了。然后移码有哪些特点呢?移码,它的0的表示是唯一的,0的表示是唯一的。因为正0和负0都表示成1后面n个0,也就是2^n-0,都一样的。因为它的真值是一样的,都是0,所以它们的移码呢也都一样。用2^n+0或者2^n-0,因为正0和负0是一样的。其次,一个真值的移码和它的补码只差一个符号位,也就是说我们的补码它的符号位取反就变成了我们的移码,这时候逻辑实现是非常简单的,我们只要有一个非门就可以把它实现出来了,就可以把它由移码变成补码或者由补码变成移码非常简单。如果移码全是0,移码全是0代表是什么?我们在这个图中就可以发现,移码全是0,它的真值就是-2^n。移码全是1,它的就是2^n-1,这是在数轴当中这个图当中可以看到。并且移码,我们之前在刚开始的时候就解释出了,就是移码它保留了数的大小顺序。也就是说我们可以一眼看出来哪个大哪个小,大的数它的移码也大,小的数它的移码也小,这就是我们给出移码、引出移码概念它是用来干什么的。我们就是这样而引出了移码的概念,它保留了这个数的大小顺序。这就是它的一个特点。好的,我们只要知道移码是怎么计算的就可以了。它不管正负数,都只要加一个偏置值就可以了,2^n+x就可以了。并且它的几个性质,大家都应该了解一下。
我们来看这张表格,我们就可以看出刚才我已经解释过了,就是说一个真值它的补码和它的移码只有符号位不同,其他位都是一样的。我们只要对这个符号位进行取反就可以了,用一个非门就可以实现了,逻辑实现非常简单。
好的,我们所有的定点数的表示都已经讲完了,我们来回顾一下。首先我们讲了无符号数它的数值是如何计算的,直接用二进制数和十进制数它的转换就可以了。并且它的范围是根据这个存储器它的长度来决定的,我们刚才也讲过了。那么真值和机器数它的意思是什么,它的定义是什么大家也要记住。真值表示的是它真的值,带有正负号的真实的值。机器数表示它在机器当中,在计算机内部如何表示的。然后我们的重点在于有符号数它是如何表示的,原码、补码、反码、移码它如何计算的,大家一定要记住它的算法。它的定义的公式我们可以不去考虑它,我们只要知道它是如何计算的就可以了。按位取反再加1,或者按位取反就可以了,公式只是帮助你理解的,你可以不把它记住。那么我们整个的这个定点数的表示就已经讲完了,那么我们下面的重点就是定点数的运算。运算也是一个非常难的部分,大家要提高警惕。
那么我们进入定点数的表示和运算的后半部分,也就是定点数的运算的部分。那么我们要讲哪些运算呢?
我们要讲一位加减法运算,溢出判断,乘除法运算以及强制类型转换,其中前三部分是重点,也就是我用红框框标出来的这部分,移位加减法以及溢出判断这是考试的重点,大家要打起精神。那么我们这一讲的内容呢就是移位运算。
那么关于什么是移位运算,我们小学的时候在学小学数学的时候就已经学过,比如像这个例子,15. m = 1500. cm.当时我们讲的时候呢,是没有考虑这个小数点的。我们知道因为它是一个整数,所以小数点应该是在数字的最后部分,所以我用红色的部分呢把小数点标出来了,其实大家在写的时候是不写这个小数点,那么我们就默认为这个小数点是在数字的后面的,因为它是一个整数,然后它是一个定点数。那么它代表着什么意思呢?在数学里呢我们就说小数点先右移了两位,我们可以看到原来是在5后面的,现在跑到了00后面,所以我们在数学里面我们是说小数点向右移了两位,但是这种说法在我们计算机里面是不成立的,为什么呢?因为我们的计算机里面是没有硬件来保存小数点的,也就是说我们没有一个专门的硬件是来表示它是一个小数点,所以我们就没有办法来表示小数点向右移了两位。
那么我们在计算机里是怎么表示呢?我们是说数据相对于小数点左移了两位。也就是说,这个15相对于这个小数点向左移动了两位。那么向左移动了两位之后空出来的部分我们都用0把它填出来。所以我们就说数据相对于小数点左移了两位,以后呢我们看到左移和右移都是小数点固定不动,都是在这个数字的最后的,然后数据相对于小数点向左或者向右移,大家要注意这一点,因为我们计算机里面是没有硬件专门用来表示小数点的,所以我们在计算机里面所说的左移和右移都是小数点固定不动,数据相对于小数点左移或者右移的。
那么我们可以看到,左移的时候呢,我们的绝对值是扩大的。比如像我们这里,15变成了1500,它的绝对值是扩大了。而右移呢,比如15变成了1.5,右移了一位,所以它的绝对值是缩小了。
那么我们来看一下这个r进制啊。那么在上一讲我们讲这个公式的时候就已经给出了这个公式它是怎么表示为十进制数的,怎么来算它的值,这里的值就是一个十进制的值。
如果一个r进制数右移了n位,我们就相当于除以了r的n次方。如果左移了n位,就相当于乘以了r的n次方。那么移位运算到底有什么用呢?我们可以看到它左移和右移相当于乘以了r的n次方和除以了r的n次方。
那么就可以由它和加减法结合起来使用,就实现了一个乘除法的功能。那么移位就是虽然简单,但是呢用处还是挺大的。
那么我们来看一下这个移位运算啊,它根据操作对象的不同可以分为算术移位和逻辑移位。那么我们首先讲的呢是算术移位,那么什么是算术移位呢?也就是说我们有符号数的移位称为算术移位。有符号数但是符号位是不参与移位的,符号是正的,移位结果还是正的。符号是负的话,移位结果还是负的。那么这样的移位运算呢,就叫做算术移位。
那么它的规则是怎样的?我们的正数,那么因为它是一个正数,它的原补码都是相同的。所以如果移位后面出现了空位,我们都以0添在后面。
如果移位向后移了,它的左边出现了空位了,那么我们也是用0把它填一下。也就是说,如果它是一个正数,因为它的原码、补码和反码都是一样的,所以不管它是左移和右移,我们出现的空位都用0填在那儿,这就是正数它移位的一个规则。因为它是原码、反码和补码我们之前讲过它都是一样的,所以不管它左移右移我们都填一个0。但是负数就不一样了,负数的原码我们如果是向左和向右呢我们还是添0,符号位是不动,符号位摆在那儿。如果是反码的话,因为反码和原码我们之前讲反码的概念的时候,反码的0就是原码的1,反码的1就是原码的0,那么我们如果向左还是向右的话,我们都是添1,都是添1。它和原码正好是相反的。但是补码就不太一样了,补码它的规则我们之前也讲过,是取反再加1。所以如果左移和右移,它就是不太一样。
我们来看一下这个例子。如果x=-0.x1x2.....xk100...000(后面是100...000)。现在我如果要求它的补码的话,我们根据上一节课我们讲过的规则,它的补码应该是符号位是1,符号位是1,小数点不动然后其余部分都是取反再加1。因为我们要取反再加1,所以我们把后面的1000...000取反之后变成了0111...111对吧。0111...111,然后再加1个1的话,产生了一个进位,所以就变成了1000...0000。所以后面的1000...0000还是1000...0000,你怎么得到的,刚才也讲过了,取反再加1得到的。取反变成了0111...111,再加一个1就变成了1000...0000。前面的x1x2...xk,全部变成0变成1,1变成0,就是这样。所以我们如果要左移的话,左移的话我们就要添0,因为它最后都是0。因为要保持和它的真值的一个对应关系,所以我们左移的话补码是添0的,但是右移的话真值的话右移前面应该添0的。但是呢因为要变成它的这一个补码形式,所以要取反就变成了1。所以我们的补码规则就是,如果左移的话在后面添0,如果右移的话在左边添1,这个规则大家应该要记住。好的我们再重复一次。如果是正数的话,它的原码、补码和反码都是一样的,所以不管是左移和右移,我们都是添0的。负数原码和反码,根据规则的话,如果是原码的话就添0,如果是反码的话是添1,这是没有疑问的。但是补码就比较复杂了,因为它要全部取反再加1,所以根据我们的这个规则的话,如果它是左移的话我们在它的后面添0,如果它是右移的话我们在它的左边添1,符号位保持不动,符号位不参与移位。好,这个规则大家都掌握了。
好的,如果它是一个二进制数的话,我们可以用这个规则来写一下。最高位是S也就是style也就是它的符号位,如果转换为十进制数的话也就是(-1)^S,如果是0的话它就是正的,如果是1的话它就是负的。所以后面呢还是用我们这个展开的规则。也就是S移位我们是有符号的这样一个移位。
但是呢符号位S是保持不动的,是摆在那儿的,不参与移位的。
那么如果是原码的话,我们是符号位、绝对值。
我们进入第二讲的学习,也就是加减运算。那么在加减运算里面我们还要讲符号拓展和溢出判断的内容。
我们再来看一下我们也就是定点数的运算的这一章,需要掌握的内容有移位运算,加减运算,乘除运算和强制类型转换。其中,上一讲的移位运算和这一章的加减运算、溢出判断,是本节的一个重点。而下一讲的乘除运算,强制类型转换呢,我们只要做一个大概的了解就可以了。会做题,看一下我们的题目就可以了。那么这一节的内容,和上一节的内容,大家一定要加以重视。
我们之前在讲补码的时候就已经讲过,为什么要引入补码的概念。是因为如果两个有符号数进行相加的时候,采用补码,我们不需要进行分类讨论。我们只需要对这两个数的补码进行运算就可以了,所以补码就是这样被引入来。所以我们的加减法它的运算思路也就是我们先把它全部转化为x+y的形式,把它全部转化为加法。然后我们再计算x的补码加上y的补码就可以得到我们的结果了。这样讲呢是比较抽象的,我们来看一道题就可以了。
我们设我们的机器字长是8位啊,我们所说的机器字长这8位,是含有1位的符号位的,那么有7位的数据位。A=15,B=-24,我们求A+B的补码,和A-B的补码。大家如果想到一个投机取巧的办就是我先把A+B算出来,等于-9,然后呢我再求-9的补码。然后呢我再算A-B,把它算出来,等于39,然后呢我再把39它的补码把它算出来。但是呢这样是,可以是可以,但是我们要讲的呢是我们的计算机是如何进行这样的加减法运算,所以呢我们就一步一步地来分析。首先呢,我们先要把它,之前我们讲过是怎样进行加法,全部把它们转化为X+Y的形式,然后再求X的补码和Y的补码。
我们先求A和B的补码。我们先把它表示为二进制的形式,那么A是15,15的话就是+1111。然后24,B=-24也就是-11000,啊这是它们的真值。真值也就是真正的值,带有符号的那个值,+15和-24。我们要把它表示为8位的一个补码,啊注意因为我们的机器字长是8位,所以我们不单单要把它转化为补码,我们还要把它变成一个8位的形式,所以我们有两种方式。第一种方式我们先求它的原码,它的原码怎么表示呢?是0,1111。然后,B是1,11000。也就是把正号变成了0,把负号变成了1,这是我们的第一步,先把它的原码表示出来。
然后我们进行符号拓展。因为我们要把它变成7位的形式,符号位保持不动,然后再在所有数的前面,都添0,啊都添0。因为它是一个原码的形式嘛,我们要保持它的数值位不变的话,我们只能添0。因为0放在它的高位上面是不起任何作用的。原码,所以它添0的话我们对它的数值没有造成任何改变。所以把它变成8位的形式就是0,0001111。B呢,是1,0011000。所以我们在它的前面添0,全部把它添0,变成一个七位的数据位。那么下面我们就对这样一个八位的东西,把它变成它的补码。如果是正式的话,原码和补码是一样的,所以我们不需要做任何变化,就是0,0001111。但是如果是负数的话,我们就要进行取反再加1。取反再加1变成什么?就变成了1,1101000。取反再加1,我们来看一下它的过程啊。原来是1,0011000,取反变成什么?变成1,符号位我们是不做任何变化的还是1。然后取反就变成了1,1100111。1100111,然后呢?在这最后加个1就变成了1101000,对吧,进了一位上去后面就是0。所以就是取反再加1。这样呢我们就把A和B的它的补码都求出来了。是不是非常简单,那么这是先求原码再求补码的形式。
如果我们直接求补码怎么求呢?A是正的1111,B是负的11000。
我们首先直接求出它的补码,啊直接求出它的补码。就是0,1111。B呢,就是1,01000。啊5位的形式,5位的形式求补码,取反再加1,就是00111再加1就变成了01000对吧。符号位是1,所以后面是01000。然后我们就要在前面添东西变成7位的数据位。那么怎么添呢?如果它是一个正数的话,我们在前面添0。如果它是一个负数的话,我们在前面添1。
也就是,