Problem6728--学习系列 —— 位运算

6728: 学习系列 —— 位运算

[Creator : ]
Time Limit : 1.000 sec  Memory Limit : 256 MiB

Description

计算机中的进制

二进制 Binary Number

二进制数字,就是底数位 $2$ 的数字,使用 $2$ 个符号 $01$。
int n = 0b1010111100011100; // 44828

十六进制 Hexadecimal Number

十六进制数字,就是底数位 $16$ 的数字,使用 $16$ 个符号 $0123456789abcdef$。
int n = 0xaf1c; // 44828


位运算概述

位运算就是基于整数的二进制表示进行的运算。由于计算机内部就是以二进制来存储数据,位运算是相当快的。例如:
$(5)_{10}=(101)_2, (6)_{10}=(110)_2$
基本的位运算共 $6$ 种,分别为按位与、按位或、按位异或、按位反、左移和右移。
符号
描述
运算规则
& 按位与 两个位都为 $1$ 时,结果才为 $1$。
 | 按位或 两个位都为 $0$ 时,结果才为 $0$。
^ 按位异或 两个位相同为 $0$,相异为 $1$。
~ 按位反 $0$ 变 $1$,$1$ 变 $0$。
<< 左移 各二进位全部左移若干位,高位丢弃,低位补 $0$。
>> 右移 各二进位全部右移若干位,对无符号数,高位补 $0$,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补 $0$(逻辑右移)。


按位与

【运算规则】
x & y:同为 $1$ 时,结果为 $1$
3 & 4
3(0000 0011)
4(0000 0100)
-------------
0(0000 0000)
【作用】
1)清零
如果想将一个单元清零,即使其全部二进制位为 $0$ ,只要与一个各位都为零的数值相与,结果为零。
2)取一个数的指定位
比如取数 X=1010 1110 的低 $4$ 位,只需要另找一个数 Y,令 Y 的低 $4$ 位为 $1$,其余位为 $0$,即 Y=0000 1111,然后将 X 与 Y 进行按位与运算(X&Y=0000 1110)即可得到 X 的指定位。
3)判断奇偶
只要根据最未位是 $0$ 还是 $1$ 来决定,为 $0$ 就是偶数,为 $1$ 就是奇数。因此可以用 if ((a & 1) == 0) 代替 if (a % 2 == 0) 来判断 $a$ 是不是偶数。

按位或

【运算规则】
x | y:同为 $0$ 时,结果为 $0$
3 | 4
3(0000 0011)
4(0000 0100)
-------------
7(0000 0111)
【作用】
1)常用来对一个数据的某些位设置为 $1$
比如将数 X=1010 1110 的低 $4$ 位设置为 $1$,只需要另找一个数 Y,令 Y 的低 $4$ 位为 $1$,其余位为 $0$,即Y=0000 1111,然后将 X 与 Y 进行按位或运算(X|Y=1010 1111)即可得到。

按位异或

【运算规则】
x^y 相同为 $0$,不同为 $1$
3 ^ 4
3(0000 0011)
4(0000 0100)
-------------
7(0000 0111)
【作用】
1)翻转指定位
比如将数 X=1010 1110 的低 $4$ 位进行翻转,只需要另找一个数 Y,令 Y 的低 $4$ 位为 $1$,其余位为 $0$,即Y=0000 1111,然后将 X 与 Y 进行异或运算(X^Y=1010 0001)即可得到。
2)与0相异或值不变
例如:1010 1110 ^ 0000 0000 = 1010 1110
3)交换两个数
void Swap(int &a, int &b){
    if (a != b){
        a ^= b;
        b ^= a;
        a ^= b;
    }
}

按位反

【运算规则】
~x $0$ 变 $1$,$1$ 变 $0$
按位取反:二进制每一位取反,0变1,1变0。
~9的计算步骤: 
转二进制:0 1001 
计算补码:0 1001 
按位取反:1 0110
 
转为原码: 
按位取反:1 1001   
末位加一:1 1010
 
符号位为1是负数,即-10 
“~x”的结果为“-(x+1)”
【作用】
1)使一个数的最低位为零
使 a 的最低位为 $0$,可以表示为:a & ~1。~1 的值为 1111 1111 1111 1110,再按"与"运算,最低位一定为 $0$。因为" ~"运算符的优先级比算术运算符、关系运算符、逻辑运算符和其他运算符都高。

左移

【运算规则】
左移可看作整数 $m$ 乘以 $2^n$。
3<<4 
3(0000 0011)待移位的数字
 6(0000 0110)左移第一位,左移一位之后,最右边的将会缺失,所以不足位数,补一位0,最左边将会多出一位,所以舍掉一位
12(0000 1100)左移第二位,最右边再补一位0,最左边再舍掉一位
24(0001 1000)左移第三位,最右边再补一位0,最左边再舍掉一位
48(0011 0000)左移第四位,最右边再补一位0,最左边再舍掉一位
 
 = 3 * 2⁴ 
 = 3 * 16 
 = 48

右移

右移可看作整数 $m$ 除以 $2^n$。
8 >> 2
8(0000 1000)待右移的数字
4(0000 0100)右移第一位,最左边将会缺失一位,不足位数补一位0,最右边将会多出一位,所以舍掉最右边的一位
2(0000 0010)右移第二位,最左边再补一位0,最右边再舍掉一位
 
= 8 / 2²
= 8 / 4
= 2

备注

以"与运算"为例说明如下:我们假设在某个系统下 C++ 语言中 long 型占 $4$ 个字节,int 型占 $2$ 个字节,如果一个 long 型数据与一个 int 型数据进行"与运算",右端对齐后,左边不足的位依下面三种情况补足,
  • 1)如果整型数据为正数,左边补 $16$ 个 $0$。
  • 2)如果整型数据为负数,左边补 $16$ 个 $1$。
  • 3)如果整形数据为无符号数,左边也补 $16$ 个 $0$。
  • 如:long a=123;int b=1;计算a& b。 如:long a=123;int b=-1;计算a& b。
    如:long a=123;unsigned intb=1;计算a & b。

进一步应用

判断一个数字 $x$ 二进制下第 $i$ 位是不是等于 $1$

参考 6796

将一个数字 $x$ 二进制下第 $i$ 位更改成 $1$

参考 6788

将一个数字 $x$ 二进制下第 $i$ 位更改成 $0$

参考 6795

把一个数字二进制下最靠右的第一个 $1$ 去掉



Input

Source/Category