位运算及应用

位运算:

&  | ~ ^异或

<< 左移,相当与*2

>> 右移,正数高位补0,负数由计算机决定

>>>右移,正数高位补0,负数亦补0

循环左移k (x<<k) | (x >> (32-k)),

循环右移k (x>>k) | (x << (32-k))

 

清零取反要用与,某位置一可用或

若要取反和交换,轻轻松松用异或

 

应用:

字符改变大小写:

原理:小写字符比对应的大写字符在数值上大32, 而32 = 0010 0000=0x20

 inline char lower(char c) { return (char)(c&~'0x20'); }

 inline char upper(char c) { return (char)(c| '0x20'); } 

交换两个数(字符),不用第三个变量就可以交换两个变量的值了:

用异或^,原理:两次异或能还原,即a = (a^b) ^ b

a = a^b; b = a^b; a = a^b;

当然不用位运算,也可以实现不用第三个变量交换两个数(可能数据溢出)

a = a+b; b = a-b; a = a-b; 

判断一个数是不是2的幂次:

原理:2的幂次的二进制表示中只有一位是1,其他位为0

x = x&(x-1)是让x的二进制码最右侧的1置为0,如果结果为0就表示原先x只有1位是1,其他位为0

inline bool is2pow(int x) { return (x&(x-1)==0 && (x!=0)); }

inline bool is2pow(int x) { return ( (x&-x)==x ); }

//4的倍数:二进制表示中只有一位为1的,而且此位为从右数的奇数位

int pow4(int n)

{

   //剩下非0了

   if(n == 0)      return 0;

   //剩下只有一位为1的了(2的幂次)

   if(n&(n-1))     return 0;

   //剩下的就是奇数位为1的了,0x55=0101

   return (n&0x55555555);

   //也可以 return ( (n&-n)==n );

}

8的幂次: (n!=0) &&(n&(n-1)==0) && (n%7==1)

16的幂次:(n!=0) &&(n&(n-1)==0) && (n%15==1)

32的幂次:(n!=0) &&(n&(n-1)==0) && (n%31==1) 

求一个整数有多少位是0:

原理同上。用x&(x-1)

 

二进制快速求幂:

 

 判断奇偶数:

原理:奇数最后一位1,偶数0

inline bool odd(int x) { return x&1; }

inline bool even(int x) {return !(x&1); } 

n%2 = n&1

n%4 = n&3

n%8 = n&7

……

x绝对值:

原理:x正数不做改为负取反加1

x正数y = 0 = 0000 0000 0000 0000

x为负y = -1 = 1111 1111 1111 1111

0异或是本身,跟1异或是取反

 

2次取模:

原理:x&y取出xy二进制位1的所有位。x^y>>1取出x,y只有一个二进制位1的并除以2

return (x&y) + (x^y)>>1);

不用位运算注意 (x+y)/2,有可能会溢出。

x向上取整到y,其中y=2^n (字节对齐用):

#define rund(x,y) ( ((x)+(y)-1)&~((y)-1) )

其他:

只有第k1的数 1 << (k-1)

k位为均为1的数 (1<<k)-1

x 的第k+1 x >> k &1

x的第k+1位置1 x >> k |(1 << k)

x的第k+1位置0 x >> k &~(1 << k) 

注意:左移1位再右移1位不一定原先的

原文地址:https://www.cnblogs.com/liyuxia713/p/2540733.html