1. 前言
首先,在内存中,数都以反码表示,示例如下:
- 正数:+1:0,000,0001
- 负数:-1:1,111,1111
关于移位运算移,它包括循环移位、逻辑移位和算数移位(带符号),C语言中,移位运算方式与具体的C语言编译器有关,通常实现中,左移补0,右移运算与是否带有符号位有关:
- 无符号数:右移补0
- 有符号数:右移补符号位1
2. 基本位运算
位运算符 | 意义 | 特点 | 用处 | |
---|---|---|---|---|
& | and | 按位与 | 与1不变 与0变0 | 取位操作 |
| | or | 按位或 | 或0不变 或1变1 | 无条件赋值 |
^ | xor | 按位异或 | 异或0不变 异或1取反 | 取反操作 |
~ | not | 全取反 | ||
<< | shl | 左移补0 | ||
>> | shr | 右移补0 |
其他运算的位实现
-x
-x = ~x + 1 = ~(x-1)
-(~x) = x+1
~(-x) = x-1
+、-运算
x+y = x - ~y - 1 = (x|y)+(x&y)
x-y = x + ~y + 1 = (x|y)-(x&y)
按位运算
x^y = (x|y)-(x&y)
x|y = (x&~y)+y
x&y = (x|y)-x
逻辑运算
x==y: ~(x-y|y-x)
x!=y: x-y|y-x
x< y: (x-y)((xy)&((x-y)^x))
x<=y: (x|y)&((x^y)|(y-x))
x< y: (x&y)|((x|y)&(x-y))//无符号x,y比较
x<=y: (x|y)&((x^y)|(y-x))//无符号x,y比较
绝对值:求得原码并将符号取反
- 取的符号位:a>>31(正数:0, 负数:-1)
- x^(x>>31)-(x>>31):
- x>0,x^0-0 = |x|
- x<0,x^(-1)+1 = |x|
二进制快速求幂:a^11 = a(20 + 2^1 + 2^3)
对2的幂次取模:x&y取出x和y二进制位1的所有位。x^y>>1取出x,y只有一个二进制位1的并除以2
3. 基本位操作
3.1. 对数操作以及and、or、xor按位运算特性
操作 | 变化或特性 |
---|---|
-x | 0,110→1,010 |
x-1 | 0,100→0,011 |
x+1 | 0,011→0,100 |
and | 与1不变 与0变0 |
or | 或0不变 或1变1 |
xor | 异或0不变 异或1取反 |
3.2. 基本操作
操作含义 | 示例 | 运算 |
---|---|---|
最低位 1 保留,其余清0 | 0,110 and 1,010 = 0,010 | x and (-x) |
最低位 1 右置0,左置1 | 0,110 or 1,010 = 1,110 | x or (-x) |
最低位 1 且右置0,左置1 | 0,110 xor 1,010 = 1,100 | x xor (-x) |
最低位 1 且右 -- 置 0 | 0,100 and 0,011 = 0,000 | x and (x-1) |
最低位 1 且右 -- 置 1 | 0,100 or 0,011 = 0,111 | x or (x-1) |
最低位 1 且右 -- 置 1,左置0 | 0,100 xor 0,011 = 0,111 | x xor (x-1) |
最低位 0 且右 -- 置 0 | 0,011 and 0,100 = 0,000 | x and (x+1) |
最低位 0 且右 -- 置 1 | 0,011 or 0,100 = 0,111 | x or (x+1) |
最低位 0 且右 -- 置 1,左置0 | 0,011 xor 0,100 = 0,111 | x xor (x+1) |
3.3基本操作应用示例
取右侧连续的 1 (100101111->1111) :(x xor (x+1)) shr 1
取第一个1的右侧 (100101000->1000) :(x xor (x-1)) and x
4. 二进制分治
4.1 二进制中的 1 有奇数个还是偶数个
8位整数为例:奇数个结果为1,偶数个结果为0
x=x xor (x shr 1);
x=x xor (x shr 2);
x=x xor (x shr 4);
其中右起第 i 位上的数表示原数中第 i 和 i+1 位上有奇数个 1 还是偶数个 1
4.2 计算二进制中的 1 的个数
以8位整数为例:经过下面五次赋值后,x 的值就是原数的二进制表示中数字 1 的个数
x = (x and 0101 0101B ) + ((x shr 1) and 0101 0101B); //截取并将相邻两位加起来,得到里面的1的个数
x = (x and 0011 0011B) + ((x shr 2) and 0011 0011B); //继续相加
x = (x and 0000 1111B) + ((x shr 4) and 0000 1111B); //继续相加
4.3 将整数A转换为B,需要改变多少个bit位:计算A异或B之后这个数中1的个数
4.4 二进制逆序
x = (x and 0x55555555) << 1 or (x and 0xAAAAAAAA) shr 1;
x = (x and 0x33333333) << 2 or (x and 0xCCCCCCCC) shr 2;
x = (x and 0x0F0F0F0F) << 4 or (x and 0xF0F0F0F0) shr 4;
x = (x and 0x00FF00FF) << 8 or (x and 0xFF00FF00) shr 8;
x = (x and 0x0000FFFF) << 16 or (x and 0xFFFF0000) shr 16;
5. 其他运用
5.1 n个学生7位学号 ,一个学生没来:所有学号和来了的学号已知,求没来的学生的学号:
1.所有学号和-来了的学号和
2.全部异或
异或对信息有强有力的存储能力《==》交换律
5.2 不溢出地求平均值:(x&y)+((x^y)>>1)
5.3 求一个比n大的,并且是最小的2的幂:
int calc(int n)
{
n |= n>>1;
n |= n>>2;
n |= n>>4;
n |= n>>8;
n |= n>>16;
return n+1;
}