二进制简述
二进制运算
与或异或
与 & | 或 | | 异或 ^ |
---|---|---|
0&0=0 | 0|0=0 | 0^0=0 |
0&1=0 | 0|1=1 | 0^1=1 |
1&0=0 | 1|0=1 | 1^0=1 |
1&1=1 | 1|1=1 | 1^1=0 |
左移
m<<n,表示把m左移n位。最左边的n位将被丢弃,右边补上n个0;
00001010<<2 = 00101000
10001010<<3 = 01010000
右移
m>>n,表示把m右移n位。右移的时候,右边的n位将被丢弃,左边补位的时候,要分情况。
- unsigned 无符号,补0
- signed,有符号,用符号位补。如果原来是正数,就补0,原来是负数,就补1.
00001010>>2 = 00000010
10001010>>3 = 11110001
补码的概念
在二进制码中,为了区分正负数,采用最高位是符号位的方法来区分,正数的符号位为0、负数的符号位为1.剩下的就是这个数的绝对值部分,可以采用原码、反码、补码3种形式来表示绝对值部分.
原码最简单,也最好理解.原码就是绝对值的二进制数形式:例如+7的8位二进制原码是00000111,-7的8位二进制原码是10000111.
但对于二进制运算而言,原码的运算不够方便,当两个数相加时,先要判断这两个数的符号是否相同,符号不同的话,还要判断哪一个数的绝对值更大.所以在计算机中,通常都是采用补码形式.
正整数的补码与原码形式相同,例如+7的8位二进制补码是00000111;
而负整数的补码则可以通过下列方式得到:
将这个负整数的绝对值求反加1,连同符号位1一起表示就可以了.
例如-7的8位二进制补码:将-7的绝对值7求反加1得1111001,连同符号位1一起就是11111001.
你也可以练习一下+13和-13的8位二进制补码:+13d=00001101,-13d=11110011. (按二进制看,是)
题目:二进制中1的个数
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
思路:
用一个flag,最低位先位1,然后用这个flag与整数做 与 操作,可得到 整数最低位是否为1,然后让flag左移1位,再与整数与操作,知道flag变0,记录与操作大于0的次数。
class Solution {
public:
int NumberOf1(int n) {
unsigned int flag = 1;
int count = 0;
while(flag)
{
if(n&flag)
count++;
flag=flag<<1;
}
return count;
}
};
重要特点!!
把一个整数和它减去1的结果做 位与 运算,相当于把它最右边的1变成0。
class Solution {
public:
int NumberOf1(int n) {
int count = 0;
while(n)
{
++count;
n = n & (n-1); //一个数与其减一的结果 位与,相当于把最右边的1变成0
}
return count;
}
};
一个数字和自己做异或,会变成0。
思考题
-
用一条语句判断一个整数n是不是2的整数次方。
一个数是2的整数次方的情况是,二进制中只有一个位是1,因此
bool is2Multiple =(n&(n-1)==0);
-
输入两个整数m, n,计算需要改变m的二进制中多少位才能得到n。
步骤1:对m 和 n求 异或,同0异1。1的个数就表示不同的位数
bool is2Multiple =(n&(n-1)==0);
-
输入两个整数m, n,计算需要改变m的二进制中多少位才能得到n。
步骤1:对m 和 n求 异或,同0异1。1的个数就表示不同的位数
步骤2:统计 异或结果中 1的位数。