一、补码原码知识正数的补码
http://baike.baidu.com/link?url=_phzRcw8zBt6L3jgzHnArDWs3ShfQgZ_TY2Jc3ws1Ui3qzCVxSm-BMDM-K-tsQUn
正整数的补码与 原码相同。
【例1】+9的补码是00001001。(备注:这个+9的补码是用8位2 进制来表示的,补码表示方式很多,还有16位二进制补码表示形式,以及32位二进制补码表示形式,64位进制补码表示形式等。每一种补码表示形式都只能表示有限的数字。)
负数的补码
求负整数的补码,符号位不变,数值位各位取反,最后整个数加1。
同一个数字在不同的补码表示形式中是不同的。比如-15的补码,在8位二 进制中是11110001,然而在16位二进制补码表示中,就是1111111111110001。以下都使用8位2 进制来表示。
【例2】求-5的补码。
因为给定数是负数,则符号位为“1”。
后七位:-5的原码(10000101)→符号位不变(10000101)→数值位取反(11111010)→加1(11111011)
所以-5的补码是11111011。
【例3】数0的补码表示是
唯一的。
[+0]补=[+0]反=[+0]原=00000000
[ -0]补=11111111+1=00000000
补码转化为原码
已知一个数的补码,求原码的操作其实就是对该补码再求补码:
⑴如果补码的符号位为“0”,表示是一个正数,其原码就是补码。
⑵如果补码的符号位为“1”,表示是一个负数,那么求给定的这个补码的补码就是要求的原码。
【例4】已知一个补码为11111001,则原码是10000111(-7)。
因为符号位为“1”,表示是一个负数,所以该位不变,仍为“1”。
其余七位1111001取反后为0000110;
再加1,所以是10000111。
补码的绝对值(称为真值)
【例5】-65的补码是10111111
若直接将10111111转换成十进制,发现结果并不是-65,而是191。
事实上,在计算机内,如果是一个 二进制数,其最左边的位是1,则我们可以判定它为负数,并且是用补码表示。
若要得到一个负二进制补码的真值(原来的数值),只要对其求补码,就可得到真值。
如:二进制值:10111111(-65的补码)
各位取反(除符号位):11000000
加1:11000001(-65)
二、编程之美:求二进制中1的个数
http://www.cnblogs.com/biyeymyhjob/archive/2012/08/16/2642309.html
解法1:利用十进制和二进制相互转化的规则,依次除余操作的结果是否为1 代码如下:
int Count1(unsigned int v)
{
int num = 0;
while(v)
{
if(v % 2 == 1)
{
num++;
}
v = v/2;
}
return num;
}
解法2:向右移位操作同样可以达到相同的目的,唯一不同的是,移位之后如何来判断是否有1存在。对于这个问题,举例:10100001,在向右移位的过程中,我们会把最后一位丢弃,因此需要判断最后一位是否为1,这个需要与00000001进行位“与”操作,看结果是否为1,如果为1,则表示当前最后八位最后一位为1,否则为0,解法代码实现如下,时间复杂度为O(log2v)。
int Count2(unsigned int v)
{
unsigned int num = 0;
while(v)
{
num += v & 0x01;
v >>= 1;
}
return num;
}
解法3:利用"与"操作,不断清除n的二进制表示中最右边的1,同时累加计数器,直至n为0,这种方法速度比较快,其运算次数与输入n的大小无关,只与n中1的个数有关。如果n的二进制表示中有M个1,那么这个方法只需要循环k次即可,所以其时间复杂度O(M),代码实现如下:
int Count3(unsigned int v)
{
int num = 0;
while(v)
{
v &= (v-1);
num++;
}
return num;
}