补码之通透篇
补码之究极通透
写这个随笔的原因之一是因为刷题时候 调试运行下面这个语句的时候 懵逼了。。。。
int a = -1;a>>1;
你猜a等于什么?0?还是什么?
这里是java,int型都是四个字节,也就是32位表示的。
原码反码补码这方面其实大一C语言老师就讲过,问题是当时能记住后来就忘了。后来陆陆续续也看过几篇讲这个的文章,也记不太清了,今天就是为了记住这方面的知识,写一下。
网上有几票貌似在讲其背后原理的文章,但是看完也云里雾里,最后再看了一篇同余的文章后,突然懂了,这回彻底记住了。
Q:各种码的出现是为了什么?
A: 为了计算机能够完美支持 有符号整型的加减法运算
我们都知道,有符号整型最高位位符号位,1为负0为正。逻辑上的加减法呢只要是个小学生就会算。但是落实到计算机,是加法器。单片机中我们学过累加器,他们只能做单纯的add,就是1+1=0然后多的1需要进位,0+0等于0.......如果超出了他最大的表示范围,就只能溢出了比方说八位的累加器
11111111+1=00000000
,也就出错了,所以说非常的机械死板。。。。
然后,网上一票人对反码补码是这么解释的:
所以你人为的给最累加器最高位赋予了特殊的意义,加法器并不懂,还是直勾勾的进行add运算,对最高位的符号仍然看作一个普通的位。那这里就得想办法将错就错,或者各种弯弯绕的设计使得正负号参与运算之后依旧出正确结果。这个补码的出现就解决了这个问题,这是认为规定的一种方式(避免了-0的出现也避免了正数+负数会差一位)。
可其实,根本没有什么弯弯绕,没有复杂精妙的算法,没有什么设计师疯狂的设计,就是同余的思想,用一个较大的 正数代替了负数,他们是同余的。。mod最大量程的两倍,这样,高位溢出,和做减法起到了一样的效果、、、
知识点1
正数:三码同一。
负数:
反码:就是符号位以外的所有为,1变0,0变1.
补码:反码+1
老师让我们背的这个玩意,我总忘,,,,总忘了谁是反码谁是补码,+1还是-1。
知识点1(以上 记不住就忘了吧)
计算机都是以补码形式计算和存储的,结果如果是正数,自然就直接是本身,如果是负数需要把补码改回原码然后输出出来。
比方说:我要使得计算机里 的 1 + -1 等于0
如果’’ 1‘‘这么表示了 : 0000 0001
那么-1要是这么表示: 1000 0001
会得到 1000 0010 也就是 -2
而且这个最高位肯定还是1 不会变,结果按照认为定义的话肯定是个负数。。。。
这肯定不行,那么一般人肯定会这么想,如果利用加法器溢出的特性。。。。。会不会巧妙解决这个问题呢,,,,那么如何利用溢出的特性呢,,,,下面就瞜一眼他的数学原理。
2.1同余
这里我参考了一篇博文,补码就是 负数+最大量程(包括符号位的量程,java把符号位也算里就是231)的2倍 ,就像钟表一样,现在比方是4点,我想-2点 我可以逆时针拨2个小时,我也可以顺时针拨10个小时。因为量程就是12个小时
看下面几句话(对于8位的加法寄存器):
1. 为了使符号位参与运算,那么符号位和前边的若干位就必须代表正常的一个加数,比方说八位的加法器,那么最高位就代表128(而不是把他当成减法,这样设计简单).
2. 一个数只要大于255(1111 1111)就溢出了。(256 就是 1 0000 0000,)
3. 如果一个八位的累加器,让他运算一个 a+(-b),比方说b就是3,加法器减3,和让他+253是不是一个效果呢? 这个-b 现在变成了 +256 -3 。
对于一个八位累加器,最高位是128(黄色部分):
0 0 0 0 0 0 0 0
他加了256 实际上就是:
1 0 0 0 0 0 0 0 0
由于 256超过了这个加法器的最大表示数值 ,这个256会溢出的 :
再举栗子说一遍:
计算 a+(-b) ----------------> 10 + (-3)
-
如果-3 用256-3 也就是253表示了(1111 1101),那么最终的结果永远相差256 这个没毛病吧? 会比a-3 的值大256。
-
但是很不幸哈,,,他这一加就进位了。。。那第九位的1表示的256就无了!!!!最终结果就是 (a-3+256 )-256 就是a-3.
是不是就很巧妙了呢!
所以你看补码怎么来的,先别记什么反码+1。
3这么表示: 0 0 0 0 0 0 1 1
-3 用了256-3 也就是 b 用255 表示,也就是说,这个补码应该和 b(不是-b) 做和恰好为256。1 0 0 0 0 0 0 0 0
很显然3 按位取反是 1 1 1 1 1 1 0 0 和3 的和恰好是,1 1 1 1 1 1 1 1 (255) , 差一个是256
所以-3 应该再3按位取反之后再+1: 1 1 1 1 1 1 0 1
这样:
只要是发生了进位,就自动溢出了多加的256,就是正确的结果。
Q:那么没发生进位怎么办呢?
好说啊,没发生进位,那其结果一定多了 256 ,减去256即可啦。这就是所谓的 补码
如何减去256,那就是上边的逆操作被!比方说
a+(-b)这里的-b如果用 (256-b)表示了,计算结果结果还是“负数“(比0111 1111大的正数),说明结果多了的那256,还在里边,没溢出。
那就 -1 再取反咯。结果肯定是对的了。
所以说 : 不是说先有了符号位,再怎么怎么说服符号位的意义。
而是这这种设计下正数最高位一定是0的,用了比 0 111 1111大的数表示的负数。
这样的思路你过几遍,你就明白了:
- 为什么 -1 用 1111 1111 表示了。
- 为什么 -1 >>1 还是-1了
- 补码就是 负数多了“256“参与运算。所以是按位取反再+1
- 计算机都以补码的形式计算和存储 这个意思是(结果都是多了“256“的)
- 正数的补码是本身(最高位不是1,说明要么多出的“256”溢出了(结果正确),要么是两个小正数做加法(结果正确)),但你说他是补码那也没毛病。
- 负数要把补码换成源码 结果是一个大于(0111 1111)的数必然有负数参与了,那结果需要减“256”,即-1取反操作。

浙公网安备 33010602011771号