玩转位运算
1 什么是位运算
程序中的所有数的加减乘除在内存中都是以二进制的形式储存和进行的。位运算就是直接对整数在内存中的二进制位进行操作。
常见的位运算操作有:与、或、异或、取反、左移、右移(分为带符号右移和不带符号右移)
2 二进制、反码、补码
2.1 二进制
CPU可以执行的指令表示方法,现代的计算机和依赖计算机的设备里都使用二进制,每个数字称为一个比特(Bit,Binary digit的缩写)。
2.2 反码
反码通常是用来由原码求补码或者由补码求原码的过渡码。
机器数的反码的整数和小数中“0”的表示形式各有2种,“+0”和“-0”不一样,以8位机器数为例,整数的“+0”原码为0,0000000,反码为0,0000000;整数的“-0”原码为1,0000000,反码为1,1111111;小数的“+0”原码为0.0000000,反码为0.0000000;小数的“-0”原码为1.0000000,小数的“-0”反码为1.1111111。
反码跟原码是正数时,一样;负数时,反码就是原码符号位除外,其他位按位取反。
2.3 补码
补码是计算机把减法运算转化为加法运算的关键编码。
补码的整数和小数中“0”的表示形式各只有1种,“+0”和“-0”一样,以8位机器数为例,整数的“+0”和“-0”补码为0,0000000;小数的“+0”和“-0”补码为0.0000000。因为根据定义x为“-0”,以8位机器数为例,为负数求补码,根据公式得2^8+(-0),即100000000+(-0),机器数位8位,所以为00000000,跟“+0”得到的补码一样。1,0000000补码,表示的数位-128。
3 Go语言位运算
3.1 将一个数字转化为32位二进制表示
func main() {
   i := 10
   to2num(i)
}
func to2num(n int) {
   for i := 31; i >= 0; i-- {
      if (n & (1 << i)) == 0 {
         fmt.Print("0")
      } else {
         fmt.Print("1")
      }
   }
   fmt.Println()
}执行结果:

3.2 操作
| 运算符 | 含义 | 
|---|---|
| << | 左移 | 
| >> | 右移 | 
| | | 或,有1取1 | 
| & | 与,都为1取1 | 
| ^ | 异或,如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。 | 
| &^ | 取反,如果右侧0左侧不变,如果右侧为1,左侧一定清零.a&b=a&(b) | 
注意点:
- <<、>>、^这三个操作可以针对数字的本身进行操作
- |、&、&^这三个操作需要两个数之间进行操作
代码演示(不为0的正数):
func main() {
   i := 10
   fmt.Println("i 初始值:", i)
   to2num(i)
   //左移
   j := i << 2
   //右移
   k := i >> 2
   //异或
   l := ^i
   fmt.Println("j 初始值:", j)
   to2num(j)
   fmt.Println("================================")
   fmt.Println("i 左移2位:", j)
   to2num(j)
   fmt.Println("i 右移2位:", k)
   to2num(k)
   fmt.Println("i 异或:", l)
   to2num(l)
   //或
   m := i | j
   //与
   n := i & j
   //取反
   o := i &^ j
   fmt.Println("i 或 j:", m)
   to2num(m)
   fmt.Println("i 与 j:", n)
   to2num(n)
   fmt.Println("i 取反 j:", o)
   to2num(o)
}
// 获取二进制数函数
func to2num(n int) {
   for i := 31; i >= 0; i-- {
      if (n & (1 << i)) == 0 {
         fmt.Print("0")
      } else {
         fmt.Print("1")
      }
   }
   fmt.Println()
}操作结果:

3.2.1 左移
概念:将32位二进制整体左移两位,后面补0

3.2.2 右移
概念:将32位二进制整体右移两位,前面补0

3.2.3 与
概念:两个数的二进制位都为1时结果取1

3.2.4 或
概念:两个数的二进制位任意一个为1时结果取1

3.2.5 异或
概念:如果i、j两个值不相同,则异或结果为1。如果i、j两个值相同,异或结果为0。针对元素本身是各个二进制位取反(1变0,0变1)。

3.2.6 取反
概念:如果i为0,j不变,如果j为1,i一定清零

4 总结
位运算虽然在我们平时的编程中不是很常见,但是拥有这极高效率的运算方式,在我们很多编译器和环境的源码以及框架源码中是非常常见的,因此还是要花些时间了解下为好。










