位运算学习笔记

基本知识

1.按位与&:把参与运算的两个数对应的二进制位相与,只有对应的二进制均为1时,结果的对应位才为1,不然为0。如:9&5中9能够写成(00001001),5能够写成(00000101),那么9&5的运算结果为0000 0001,输出结果是1。code

  1. 按位或|:把参与运算的两个数对应的二进制位相或,也就是只要对应的两个二进制位有一个为1时,其结果就为1。 如:9|5至关于00001001|00000101,运算结果是00001101,输出结果是13

3.按位异或^:把参与运算的两个数对应的二进制位相异或,当对应的二进制位上的数据字不相同时,结果对应为1时,不然为0。如:1^1=0,1^0=1,0^0=0,0^1=1 9^5至关于00001001^00000101,运算结果是00001100,输出结果是12get

4.取反~:把运算数的各个二进制位按位求反。如:~9至关于~(0000 1001),运算结果为1111 0110。it

5.左亿<<:把“<<”左边的运算数的各二进制位向左移若干位,“<<”右边的数是指定移动的位数,高位丢弃,低位补0。 如 :a<<4指把a的各二进位向左移动4位,如a=00000011(十进制为3),左移4位后为00110000(十进制48)。class

6.友谊>>:把“>>”左边的运算数的各二进制位所有右移若干位,“>>”右边的数是指定移动的位数。如:设a=15,a>>2表示把00001111右移为0000 0011(十进制为3)。效率

位运算的经常使用方法

乘以\(2\)运算

int mulTwo(int n) {  // 计算 n*2
  return n << 1;
}

除以\(2\)运算

int divTwo(int n) {  // 负奇数的运算不可用
  return n >> 1;     // 除以 2
}

乘以\(2\)\(m\)次方

int mulTwoPower(int n, int m) {  // 计算 n*(2^m)
  return n << m;
}

除以\(2\)\(m\)次方

int mulTwoPower(int n, int m) {  // 计算 n*(2^m)
  return n << m;
}

判断一个数的奇偶性。

bool isOddNumber(int n) 
{ 
    return n & 1;
}

取绝对值(某些机器上,效率比$ n > 0 ? n : -n$ 高)

int abs(int n) {
  return (n ^ (n >> 31)) - (n >> 31);
  /* n>>31 取得 n 的符号,若 n 为正数,n>>31 等于 0,若 n 为负数,n>>31 等于 - 1
     若 n 为正数 n^0=0, 数不变,若 n 为负数有 n^-1
     须要计算 n 和 - 1 的补码,而后进行异或运算,
     结果 n 变号而且为 n 的绝对值减 1,再减去 - 1 就是绝对值 */
}

取两个数的最大值(某些机器上,效率比 \(a > b ? a : b\) 高)

int max(int a, int b) {
  return b & ((a - b) >> 31) | a & (~(a - b) >> 31);
  /* 若是 a>=b,(a-b)>>31 为 0,不然为 - 1 */
}

取两个数的最小值(某些机器上,效率比$ a > b ? b : a $高)

int min(int a, int b) {
  return a & ((a - b) >> 31) | b & (~(a - b) >> 31);
  /* 若是 a>=b,(a-b)>>31 为 0,不然为 - 1 */
}

判断符号是否相同

bool isSameSign(int x, int y) {  // 有 0 的状况例外
  return (x ^ y) >=
         0;  // true 表示 x 和 y 有相同的符号,false 表示 x,y 有相反的符号。
}

计算\(2\)\(n\)次方

int getFactorialofTwo(int n) {  // n > 0
  return 1 << n;                // 2 的 n 次方
}

判断一个数是否是 2 的幂

bool isFactorialofTwo(int n) {
  return n > 0 ? (n & (n - 1)) == 0 : false;
  // 固然你也能够使用下面这种更为简便的写法:
  // return n > 0 && (n & (n - 1)) == 0;
  /* 若是是 2 的幂,n 必定是 100... n-1 就是 1111....
     因此作与运算结果为 0 */
}

\(2\)\(n\)次方取余

int quyu(int m, int n) {  // n 为 2 的次方
  return m & (n - 1);
  /* 若是是 2 的幂,n 必定是 100... n-1 就是 1111....
     因此作与运算结果保留 m 在 n 范围的非 0 的位 */
}

求两个整数的平均值

int getAverage(int x, int y) {
  return (x + y) >> 1;
 }

遍历一个集合的子集

int b = 0;
do {
  // process subset b
} while (b = (b - x) & x);

以上内容搬运自OI Wiki,只是为了之后好找遍历