位运算

来源:互联网 发布:js单选按钮选中 编辑:程序博客网 时间:2024/06/04 19:53

在程序员圈子里有一个流传了很久的笑话,说世界上有10种人,一种人知道二进制,而另一种人不知道二进制。。

二进制的位运算总共5种:与、或、异或、左移和右移。

这里写图片描述

左移表示把某个数左移n位,左移n位的时候,最左边的n位将被丢弃,同时在最右边补上n个0。(一般情况下相当于x2,但是如果数字本身已经足够大而且是有符号整数时,继续左移会覆盖符号位,就会出现正数变成负数的情况)

这里写图片描述

右移表示把某个数右移n位,最右边的n位被丢弃。如果数字是无符号整数则直接用0补齐最左边的n位。如果是一个有符号整数,则用数字的符号位填补最左边的n位。也就是如果原先数字是一个正数,右移左边补n个0;如果是负数,右移左边补n个1。

这里写图片描述

但是!在C++中,int属于有符号整数,正数最高位必然为0,所以最大值是2^31-1(也就是0后面31个1)。而负数最高位必为1,所以负数最小值是-2^31(因为最高位作为1,进位仍然有效)。在C++中,正数以原码形式存在(因为正数补码和原码一样),负数是以补码的形式存在(原码除符号位均取反,然后+1得到补码)。
例如:先取-1的原码:10000000 00000000 00000000 00000001
得反码: 11111111 11111111 11111111 11111110(除符号位按位取反)
得补码: 11111111 11111111 11111111 11111111
参考链接:http://blog.sina.com.cn/s/blog_798f21a00100wz22.html
而C++的左移、右移都是在补码的基础上,所以-1右移多少位都是-1。

二进制中1的个数
输入一个整数,输出该数二进制表示中1的个数。例如9表示成二进制是1001,有2位是1。输入9,输出2。

分析:
1.如果每次和1进行与运算然后右移,就能判断其中一位是不是1,但是如果数字是负数,右移就会产生多个1,所以不能移动原数,但是可以对1进行左移。
2.给定数字i,首先i和1做与运算,判断其最低位是不是1。接着把1左移1位得到2,再和i做与运算就能判断次低位是不是1……反复左移,每次都能判断其中一位是不是1。int型数字为32位,只需要循环32次。

//判断一个数用二进制表示有多少个1int NumberOf1(int n){    int count = 0;    unsigned int flag = 1;    while (flag)    {        if (n & flag)            count++;        flag = flag << 1;    }    return count;}

3.考虑把一个数减去一个1的情况。如果一个整数不等于0,那么该整数的二进制表示中至少有一位是1。假设这个数最右边一位是1,那么减去1时,最后一位变成0而其他所有位都保持不变。也就是最后一位做了取反操作,由1变成0。如果最后一位不是1而是0,那么减1后最右边的1位变成0,它右边的0全变成1,它左边都保持不变。接下来把一个整数和它减去1的结果做位运算,相当于把它最右边的1变成0。如1100,减去1是1011,把1100和1011做与运算得到1000,相当于把1100最右边的1变成了0。所以,把一个整数减去1,再和原整数做位与运算,会把该整数最右边的一个1变成0,那么一个整数的二进制有多少个1,就会进行多少次这样的操作,循环次数为1的个数。

int NumberOf1Improve(int n){    int count = 0;    while (n)    {        count++;        n = (n - 1) & n;    }    return count;}

相关:
判断一个整数是不是2的整数次方。一个整数如果是2的整数次方,那么它的二进制表示中有且只有一位是1,只要把整个整数减去1后再和它自己做位与运算。
输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n。先求m和n的异或,然后统计异或结果中1的个数。

0 0
原创粉丝点击