15.04.10-有意思的补码
最近在看《深入理解计算机系统》,学习编程的一些基本的东西,还是觉得很有意思的。
今天看到了补码编码这一节。
最常见的有符号数的计算机表示方式就是补码(two's-complement)形式。在这个定义中,将字的最高有效为解释为负权(negative weight).我们用函数B2Tw(Binary to Two's-complement的缩写,长度为w)来表示。
最高有效位xw-1也称为符号位,它的"权重"为-2w-1,是无符号表示中权重的负数。符号位被设置为1时,表示值为负,而当设置为0是,值为非负。
仔细看前面那个公式,尤其是前面的-xw-12w-1
那常见的32位整数来看,如果数值为
11111111 11111111 11111111 11111111
= -1*231 + 1*230 + 1*229 + 1*228 +...+ 1*21 + 1*20
=-231 + (231 - 1)//不要问这个结果怎么来的,XXX-_-||求和公式....
=-1
那好,其他的呢?
11111111 11100011 11011101 11110011
= -1*231 + 1*230 +...+ 1*221 + 1*217 +...+ 1*214 + 1*212 + 1*211 + 1*210 + 1*28+...+ 1*24+ 1*21+ 1*20//少了2/3/9/13/18/19/20
= -1*231 + (1*230 + 1*229 + 1*228 +...+ 1*21 + 1*20) - 22 - 23 - 29 - 213 - 218 - 219 - 220
=-231 + (231 - 1) - 22 - 23 - 29 - 213 - 218 - 219 - 220
=- 1 - 22 - 23 - 29 - 213 - 218 - 219 - 220
看到这里是不是想起了什么了?
对了,就是常用的负数的二进制表达式的写法。
37(int32)的二进制表达式为 00000000 00000000 00000000 00100101
-37的写法呢:
首先反码:11111111 11111111 11111111 11011010,值是多少?
11111111 11111111 11111111 11011010 = -1 - 20 - 22 - 25 = -37-1
所以在反码的基础上,我们还要+1,才能得到-37的二进制码:
11111111 11111111 11111111 11011011 = -1 - 22 - 25 = -37
关于负数的二进制表达式,刚看到补码非运算时看到另一个方法。
先说补码非:
上面的非可以理解成我们常说的负值。最后的公式可以看出,如果值为w位的最小值-2w-1,那么他的负数(求非)值为本身,其它的情况则为*-1的结果。
计算一个位级表示的值的补码非有几种聪明的方法。
1.对每一位求补,再对结果加1.(也就是我们常见的写负数的二进制表达式的方法。)
2.第二种方法是建立在将位向量分为两部分的基础之上。假设k是最右边的1的位置,从左至右,将位级表达式分为两部分,[xw-1,xw-2,...,xk+1]和[1,0,...,0]。值的非写成二进制格式就是前半部分[~xw-1,~xw-2,...,~xk+1]和[1,0,...,0],合起来就是[~xw-1,~xw-2,...,~xk+1,1,0,...,0]。也就是说从最右边的1往左(不包含这个1)所有位取反。
验证:
1100(-4) ---> 0100(4)
1000(-8) ---> 1000(-8)
0101(5) ---> 1011(-5)
0111(7) ---> 1001(-7)
32位:00000000 00000000 00110100 11101011(26859)
求非: 11111111 11111111 11001011 00010101(-26859)