二进制的补码
2016-11-17 18:03 ZengGW 阅读(31816) 评论(0) 编辑 收藏 举报今天在学习C Primer Plus(第五版)中文版.pdf的时候遇到这么个问题,先上代码:
#include <stdio.h> #define PAGES 336 #define WORDS 65618 int main(void) { short num = PAGES; short mnum = -PAGES; printf("num as short and unsigned short:%hd %hu\n",num,num); printf("-num as short and unsigned short:%hd %hu\n",mnum,mnum); printf("num as int and char:%d %c\n",num,num); printf("WORDS as int,short,and char:%d %hd %c\n",WORDS,WORDS,WORDS);return 0; }
结果:
num as short and unsigned short:336 336 -num as short and unsigned short:-336 65200 num as int and char:336 P WORDS as int,short,and char:65618 82 R
请看我标红的部分,其实我蛮想不明白的,为什么-336的无符号整数是65200呢?书上说是2的补码(书中描述):数字0到32767代表它们本身,而数字32768到65535则代表负数,65535代表-1,65534代表-2,依次类推,因此-336由65536-336,也即65200来表示;本宝宝表示真心没看懂啥意思,然后就在网上各种找二进制的补码是啥意思,下面咱们就来看看什么是二进制的补码
我试验的计算及环境假设是8位的,那接下来我就拿计算机是8位作基础来讲解:
一、负数在计算机中如何表示
之前我写了一篇博客,里面是计算c语言整数类型的取值范围的额,二进制中区分正负数的方法是看二进制的最高位是0还是1,1为负数,0为正数
比如:127的二进制是01111111,而-127的二进制是 10000001(011111111 - 先取反,再加1 ->10000000+1 = 10000001),从这里可以看出127的最高位是0,而-127的最高位是1
二、什么是二进制补码
取一个数的二进制补码需要两步:
1>.每个二进制位都取相反的值,也就是二进制位是1的,补码就是0,二进制位是0的,补码就是1
2>.再把取反的二进制数转换成十进制,加上1,最后的结果就是这个数的补码的十进制数
举例:取-127的二进制补码(8位机)
二进制数:01111111
补码:10000000
结果:补码 10000000 + 1 = 10000001(129)
也就是说-127在计算机(8位机)中10000001(写到这里,我突然有点明白C Primer Plus书中描述的啥意思:0-127代表它本身,128-255代表负数,那-127就等于256-127=129)
那可能很多人会说:为什么是这样啊?虽然知道怎么计算了,但是不知道为什么是这么计算的,那么接下来就来说说二进制补码的原理
三、二进制补码的原理
那大家都知道负数怎么来的,比如:A-B,那A比B小,结果就会是负数,这就有很多情况了,咱不讨论,就比如给你一个负数,那么最直接的你肯定会想到一个表达式了,比如给你个-127,那表达式就是0-127的来的,那我们把他转换成二进制来运算一下:
预想结果:-127
十进制表达式:0-127
二进制表达式:00000000(0) - 01111111(127)
以前小学数学当被减数大于减数的时候都要向上借一位来减的,那么接下来就是借位()
重点:这里计算的时候二进制的位数是有规定的,比如-127,它是1111111 由7个1的二进制,那同学就用7个0的二进制去减,结果借一位变成了10000000(128)-1111111(127) = 1,然后在加1等于2,结果-127的补码就是00000010(2),这样可是错的,一定要遵守一个标准,那就是当前计算机是多少位的就借多少位加1位,那么比如-10是1010,就是00001010,借位就得在第9位上借,也就是100000000,结果就是246(11110110)
借位进行运算:
1>.100000000(256) - 01111111(127) = 10000001(129)
2>.100000000(256) = 11111111(255) + 1;
11111111(255) - 01111111(127) = 10000000(128)
10000000(128) + 1 = 10000001(129)
上面就是二进制补码的简单计算过程
四、二进制补码有哪些好处呢?
感觉不就是一个负数而已,非要搞的这么弯弯绕,我反正是晕了,那接下来就看下二进制补码的好处
那我们之前说的判断最高位是1还是0来区分正负,那接下来我们就用两种表示法来计算作比较:
举例:-10
表达式:20 + (-10)
1>.最高位区分正负:-10的二进制数为10001010
二进制计算:00010100 + 10001010 = 10011110
10011110转换成十进制是30,根据最高位区分正负,结果就是-30
2>.再来看看二进制补码的方式进行计算:-10的二进制补码(11110101 + 1 = 11110110(246))
二进制计算:00010100 + 11110110 = 100001010
而咱们刚才已经说了,假设计算机是8位的,那么这个结果超过8位,第九位会被舍弃,也就是00001010,结果就是10
五、为什么正数加法适用于二进制补码呢?
接下来我们求证一下X-Y(x + (-Y))这个表达式,相信大家就明白了(8位机)
Y的二进制补码由上面的讲解大家都知道是:(11111111 - Y) + 1 ,所以也就是X加上Y的二进制补码,表达式可以写成如下格式:X + (11111111 - Y) + 1
得到这个表达式就好办了,接下来我们分成两种情况来解释:
1>.那就是X小于Y,那么结果肯定是个负数了,我们采用二进制的补码的逆运算,求出它对应的正绝对值,再在前面加一个负号就可以了
第一步:计算Z、X、Y的二进制补码的表达式 Z = -((11111111 - Z) + 1);X = (11111111 - X) + 1;Y = (11111111 - Y) + 1;
第二步:根据表达式X + (11111111 - Y) + 1来替换计算:-( ( ( 11111111 - X) + 1 ) - ( ( 11111111 - Y ) + 1 ) ) = -(11111111 - X + 1 - 11111111 + Y - 1) = -( -X + Y) = X - Y;
2>.X大于Y,那结果肯定是正数,那意味着Z肯定大于11111111,那根据8位机,第九位溢出了,就要舍去,表达式为(不太明白...):
Z = Z - 100000000 = X + (11111111 - Y) + 1 - 100000000 = X - Y;
文章出自:http://www.ruanyifeng.com/blog/2009/08/twos_complement.htm