计算机原本是就一堆 01010二进制的表达式,如何将这一堆二进制数映射为我们实际生活中的真值,比如+11,+22,-3,-4…… 这些叫做有符号数
为了用这些二进制数字表达出我们现实生活中的数字,人们设计三种不一样的编码
1。 第一种叫原码,
最高位的符号如果是0,表达这个数是一个正数,
如果最高位是1,表达这个数是一个负数
这种表达方式在做运算的时候是会出问题的,因为符号位的参与,导致得不到正确的结果。
在字长位4位的时候
4 = 0 1 0 0
-2 = 1 0 1 0
4 - 2 = 4 + (-2)= 0100+1010 = 1110 ==》 表示的是 -6
2。 第二种是反码。
反码符号位不变,各位取反。
至于反码所解决的问题,还没有弄清楚
3。第三种就是补码了。
补码的概念很多知乎上的答案写的很清楚了。
先说结论 -2 的补码是 1 110
0100+1110 = 1 0 010 ,这里1溢出了,舍去取0作为符号位,得到正确答案2
溢出舍去意味着走完一个周期,舍去的操作也可以理解成减去10000
溢出要从头开始,从头开始表达的状态和我们最终要求得的状态是一致的。
可以联想下时钟,时钟4点到2点,我可以选择逆时针拨动(2+12n)个格子
(2+12n)这个数字是无限的,不适用于现实中计算机的运算
计算机的运算通常有位数限制的!
时钟是一个很好理解补码的例子,时钟上的12个状态。
4-2表示4点拨到2点需要逆时针拨动2个格子
为了到达到2点,也可以顺时针拨动10个格子
如果规定顺时针是正方向,那么 状态等价 ==》 4 - 2 = 4 + (10)
补码给我的感觉,就是在有限的状态数中,达到相同状态的另外一个表达方式。
这里也可以联想一个数轴,往数轴上的一个方向一直跑,跑到一个值后,又得从头开始
也可以理解成一种周期的概念,周而复始
计算机可以如果是8位,可以保存2^8 = 256种状态。
但是 如果用原码 来表示有符号的数, 只能保存255个
因为 -0 = 1000 0000 , +0 = 0000 0000
这样我们现实中的数 0 (0是没有正负的),但是在原码中,我们这样说,
1000 0000表示的是0, 0000 0000也表示的是0 ,0占据了两种表达
但是如果是使用补码来存储的, -0和+0的补码都是 0000 0000
我们就可以说,0000 0000 表达的是0 (包括+0 -0),这个时候多出来一个1000 0000
人们就将这个1000 0000 表示成 -128,为了不浪费吧?
关于计算时候的溢出
溢出意味着这次计算越界了,需要从头开始。
他的表现是最高位的符号位发生了改变,变0变1都有可能
再次声明一下补码的概念,表示有限状态的一对数,注意是一对!
这个时候将溢出的数加上一个周期,或者减去一个周期,让他回到有限状态中
这个概念的实质就是求余,也叫做减去一个模,或者加上一个模。
来自CSAPP:
补码中的权重:第一位 i * (-2)^(n-1),针对整数
如果第一位i取0,那么他就没有这个负数的权重,表达一个正数,
如果取1,表示有负数的权重,那么他表达就 是一个负数
如果一个数的补码是1000 0000 ,那么他的真值就是 (-2)^7 = -128
还是挺自然的
-128是不能用原码表示的,8位原码的表示有符号数范围是 [-127, 127]
在定点小数的表示中,-1是不能用原码表示的,
因为8位原码的范围是-1+2^(-7) 到 1-2^(-7),就是不可能到达到1和-1
反过来想如果到达1和-1,那他就不是小数了嘛
但是如果我们想用补码来表示有符号的小数,
那就把1000 0000 拿过去表示 -1 就好了嘛
总结下:
1。将加减法运算当做一种达到状态的方式,在一个有限数中,是有两种办法达到同一个状态的,就是减法的运算本质上,在有限数中,是可以用加法得到的,可能会有溢出的情况,求余求回去就好了。
2。补码的表示的数字在左边的半轴延长了一位,整数是-2^n,小数是-1,就变成256个了,造成了原点的对称,原码和反码都是255个,关于原点对称
以上就是一些关于补码的思考,如果有错请大家指出哦!