1.解决问题第一步
要想讲清楚-128这个问题,就像练北冥神功要先散功一样,先把你心中对原码,反码,补码的一套认识全部忘掉
2.补码的本质
首先灌输一个新的概念叫,模。什么是“模”?
想象日常使用的钟表,它可以显示0~12点的时间,假设现在是2点钟,请用手动拨动时针的方式将时间减4小时,你会怎么做?
有两种方式:
1.逆时针将时针拨4小时
2.顺时针将时针拨8(12-4)小时
这里要讲的是第二种方式,为什么顺时针拨12-4也可以达到和正常思维的第一种方式一样的位置。12就是模。
同样的,如果是十进制的两位数,80-10 和 80+90在不考虑百位数的基础上都是70。这里的90就是100-10得来的,这种情况下100就是模
模就好比是一个极限,在它的范围内,两个相加等于模的数互为补数,还是举100的例子
90和10, 55和45,68和32,互为补数
在模的范围内做减法,可以将X-Y
的减法变更为X+Y的补数
的加法,当然前提是不考虑百位数
思考题,上面举的例子是大数减小数,那么如果是小数减大数会怎么样呢?
如果是10-80,结果应该是-70,但如果按照10+(100-80),结果是30。
而很明显-70和30不是一回事,这里也没有百位数的问题,这种情况应该怎么破?
当初的那些先贤们想出来的办法很简单,就是把这两个数直接划上等号,正好顺便解决了负数的表达方式。再来仔细看看这两个数的关系:-70绝对值的补数就正好是30
所以在计算机中,负数的表达方式就是它绝对值的补数
但是问题又来了,看起来这个解决方式很完美了,但别忘了,30他已经代表了正数的30了,现在又要用来代表负数的-70,谁知道它出现的时候到底是代表哪个数?
为了解决这个问题,需要给这套规则划定一个范围,原来是0~99的正数,现在既然要用部分正数来代替负数了,那就要规定一个范围来使得一个数只代表一个含义,正好一人一半,0~49这个区间就代表正数,50~99的区间就用来代表各自补数的负值,例:98就代表-2
3.-128的真正含义
现在回到二进制的计算机世界,8位二进制数一共可以表示2的8次方,256个数,即0~255 (别忘了0也要占一位的),他们的极限就是256,即256是8位二进制数的模 ,应该不难理解吧,同上十进制的两位数0~99的模是100。
还是用二进制来说明清楚,8位二进制能表示的数的极限是
1 1 1 1 1 1 1 1
, 就是255,在这基础上加0 0 0 0 0 0 0 1
,出现了进一位 即 1 0 0 0 0 0 0 0 0
这个1 0 0 0 0 0 0 0 0
就是8位二进制数的模,256
同样按照第二步讲的逻辑,一半的数0~127,代表其正数本身,另一半的数 128~255,代表其补数的负值,即“-1~-128”的区间。而 “X-Y”的减法 就用 “X+Y的补数” 的加法来表示,完美! 唯一需要注意的事情是任何计算的输入值和输出结果值都需要严格遵守-128~127的范围,一旦溢出就会报错。
对于减法来说,按照上述讲解【-1模256=255】,也就是说,我们计算机需要做-1操作,直接加上-1的补码,也就是255的原码
那么根据上述的论述我是不是可以得出下面的公式:
一个负数的补码=模 - 该负数的绝对值对应的二进制(请自觉摒弃符号位这一概念,就是二进制)
对于这个公式我给你举个例子:
比如我们有-1这个操作,那么-1我们求解-1的补码就是
1 0000 0000
- 0000 0001
————————
1111 1111
那么-128的补码就是:
1 0000 0000
- 1000 0000
————————
1000 0000
这里请你摈弃128原码是0,1000 0000,即摒弃符号位这个概念,128原码就是1000 0000
转载知乎