最近学习计算机组成原理时,结合视频和我的理解作的一些笔记。可能文中有错误或者描述不恰当的地方,欢迎评论区指出。git
108D
为例,它对应的二进制数是 1101100
,这实际上也就是它的无符号数,能够看到全部的位都是数值位。00000000
到 11111111
,也就是 0 到 255定义:有符号数就是有体现正负号的数,整个机器字长的所有二进制位中,最高位做为符号位,0 表示正数,1 表示负数,其他位则是数值位。依然以108D
为例,它对应的二进制数是 1101100
,而对应的有符号数则要在最前面加上符号位 0,即它的有符号数是 01101100
.github
表示范围:以八位二进制数为准,范围应该是从负数到正数,即从 11111111
到 01111111
,也就是 -127 到 127ide
+108D
就是真值01101100
就是机器数。-156D
(真值)= 110011100B
(机器数)学习
简单点理解,原码就是符号位加上真值(二进制)的绝对值,同时用逗号将符号位和数值位隔开。好比,+1 就是 0,0000001
,-1 就是 1,0000001
。3d
原码的特色是简单、直观,可是原码在进行加法运算的时候会出现问题。正数加正数或者负数加负数是正常的,可是正数加负数就会出错。好比咱们如今想要计算 -1+3,咱们心想:-1 是 10000001
,+3 是 00000011
,加起来获得的是 10000100
,因此结果是 -4,但 -1+3 应该是等于 2,因此这个结果是错的。咱们发现,原本应该作的是加法运算,但实际上变成了减法运算(-1-3=-4)。code
咱们首先想到,能够经过将“正数加负数”转化为“正数减正数”来手动纠正这个错误。上面的例子就变成 00000011
减 00000001
,结果是 00000010
,也就是 2,这个结果是正确的。视频
可是每次都这样手动转化,计算起来仍是太麻烦了。因而咱们接着想:有没有一种方法,可让“正数加负数”中的负数等价于一个正数,从而确保始终进行的是相加操做呢?blog
因而这时候就引出了补码的概念。get
补数和模:理解补码以前,咱们先来理解两个概念:补数和模。 拿时钟举例,想要从10点拨到8点,有两种作法,一种是逆时针拨2个单位,记做-2;一种是顺时针拨10个单位,记做+10,这两种操做是等效的(有点负数等价于一个正数的意思)。这时候咱们就说,-2 是 +10 以 12 为模的补数,记做-2≡+10(mod 12)
,同理,-5 至关于 +7,-4 至关于 +8。it
那么怎么基于补数和模的概念将“正数加负数”转化为“正数加正数” —— 即怎么令负数等价于一个正数呢?假设咱们如今有一个寄存器能够存放四位二进制数(此时,模为16),咱们想要让 1011
变成 0000
,最容易想到的办法就是 1011-1011=0000
,注意这里是正数加负数。想要变成正数加正数,就要找到等价于 -1011
的正数,-1011
就是 -11,-11 以 16 为模的补数就是 +5,+5 就是 +0101
,这个正是咱们要找的那个等价正数,所以这时候,1011-1011
变成了 1011+0101
,其结果是 10000
,不要忘了寄存器只能存放四位,因此结果实际上是 0000
,刚好与咱们“正数加负数”时获得的结果无异。
接着引入补码的概念:
仍是上面的例子,1011-1011
,也就是11-11,咱们考虑+11和-11,+11的原码=补码=01011
,-11的原码是11011
,所以补码是10101
,那么01011+10101
就会等于100000
,由于寄存器是五位的,把前面的1去掉,那么结果就是00000
,也就是0,和上面的运算结果一致。
反码很好理解:
补码存在的问题是,仅从补码自己来看,很难比较两个数的大小,为此引入了移码的概念。移码指的是在真值(二进制)的基础上加上一个偏移量,一般这个偏移量是2^n。其中,n是数值位的位数。例如,对于-10101
,其移码是2^7+(-10101)=10000000+(010101)=0,1101011
。 固然,咱们有简单的方法能够计算一个数的移码:无论正数仍是负数,其移码都等于补码的符号位取反。
定点数的加减运算实际上就是补码的加减运算。咱们来看一个例子:
假设机器字长为 8 位(含1位符号位),A=15,B=-24,如今求 A+B 和 A-B。
A 的补码是 0,0001111
,B 的补码是 1,1101000
,那么 0,0001111+1,1101000=1,1110111
,转化为原码,再转化为真值,获得 -9,这是正确的。同理,A-B 就是 A+(-B),-B 的补码是 0,0011000
,那么 0,0001111+0,0011000=0,0100111
,最后转化为真值,获得 +39,这也是正确的。 咱们再来看另外一个例子:
假设机器字长为 8 位(含1位符号位),A=15,B=-24,C=124,如今求 A+C 和 B-C。
咱们一样按照上面的流程来进行计算,最后得出:A+C 结果是 -117,B-C 结果是 +108,这两个都是错误的。为何会出现这样的状况呢?
这种状况就叫溢出。出现的缘由,简单来讲就是:运算结果太大了,或者运算结果过小了。就上面的题而言,8 位二进制数所能表示的数字的范围是有限的,当正数加正数的时候,结果可能过大,超出了最大值,此时称为上溢;当负数加负数的时候,结果可能太小,够不到最小值,此时称为下溢。以下图所示:
咱们拿 3 位二进制数来理解这个问题。假设 3 位二进制数能够表示的范围以下:
如今咱们进行 2+2 操做,那么就是 010+010
,结果就是 100
,这已经超出了正数能够表示的最大范围,也就是发生了上溢。因此此时获得的是 -4,这是一个错误的结果。
前面说过,溢出的缘由要么是运算结果太大,要么是运算结果过小,其实从这句话咱们能够看出,正数和负数相加是不会发生溢出的,由于其结果必然在能够表示的范围内,惟一可能会发生溢出的状况,要么是正数加正数,要么是负数加负数。那么,如何判断在这两种状况下是否会发生溢出呢?有三个方法:
咱们仍是拿上面的第二个例子解释:
能够看到,A+C 中,两个操做数符号位都是 0,也就是都是正数,但结果数的符号位倒是 1 ,也就是负数,那么很明显它发生了上溢;
同理,B-C 中,两个操做数符号位都是 1,也就是都是负数,但结果数的符号位倒是 0,也就是正数,那么很明显它发生了下溢。
看第一个式子,进行运算的时候,符号位没有产生进位,可是最高数值位向前产生了进位,这时候判断它发生了上溢; 看第二个式子,进行运算的时候,最高数值位没有产生进位,可是符号位向前产生了进位,这时候判断它发生了下溢。
这种方法是将一位符号位改成两位符号位表示:正数符号为 00,负数符号为 11。那么前面的例子就会变为:
这时候,计算机只须要看结果数就能知道是否发生溢出 —— 只要结果数的两位符号位相异,那么就必定是发生了溢出。 同理,咱们回过头看第一个没有溢出的例子:
能够发现两次运算的结果数的两位符号位都是同样的,由此判断这两次运算都没有发生溢出。