1、& 与运算符 AND
当两个数二进制位同为1的时候当前位置1,否则置0。
4 & 15 = 4
---------------
00000100 &
00001111
00000100
=4
位运算的使用场景
判断奇偶数
常见的代码中可能是这样的
func IsOdd(i int)bool{
return i%2!=0
}
位运算判断
func IsOdd(i int)bool{
return (i & 1) == 1 //i是否为奇数取决于二进制的最后一位是1还是0 是1则为奇数 0则为偶数
}
计算数值的二进制位有多少个1
很容易想到只要与1进行&运算
,第一位如果为0结果为0 第一位如果结果为1 结果为1 利用这个特性数值右移一位 循环计算即可
func BitCheck(i int)(count int){
for i>0{
count = count + (i&1)
i >>= 1
}
return
}
如果数值中间有多个0 需要多次判断,优化方法是值x如果不为0 那么和x-1
进行与操作就会找出最低位的1
/*
10110001 & //初始值
10110000 //减1后
=10110000 & //找出最低位的1
10101111 //继续减1
=10100000 //找出最低位的1
.... //直到找不出1即为0
*/
func BitCheck(i int)(count int){
for i>0{
count += 1
i &= i-1
}
return
}
2、 | 或运算符 OR
当两个数二进制位有一个为1时当前位置1,同为0的时候当前位才会置0
4 | 15 = 15
---------------
00000100 |
00001111
00001111
=15
3、^ 异或运算符 XOR
^ 即可作为二元运算符,也可作为一元运算符。
作为二元运算符,^ 是异或运算符。
即两个数的二进制位不同时,当前位才置1 否则置0
有个很明显的规律 任何数和本身异或 结果为0, 0和任意数异或 结果为其本身
4 | 15 = 11
---------------
00000100 ^
00001111
00001011
=11
例子
数值交换
Go中数值交换可以直接通过a, b = b, a
这样的方式来直接交换,位运算是怎么实现交换的呢?
a ^= b // a = a^b
b ^= a // b = b^(a^b) b和b自己异或为0 相当于 b=a
a ^= b // a = (a^b)^a a在第一步中已经为a^b,现在的b 已经等于a a互相抵消 完成了值的交换
寻找列表中只出现一次的数字
假如一个列表中有2*N+1个数,其中一个数字只出现了一次。其他的数都出现了两次。如何寻找这个数字
利用任何数和自己异或的结果将为0的特性
func SingleNum(list []int)(target int){
target = list[0]
for _,val:=range list[1:]{
target ^= val
}
return
}
4、&^位清空运算符 AND NOT
看一个列子
4 &^ 15 = 11
---------------
00000100 &^
00001111
00000000
=0
位清空的意思是假如有 两个变量 var1 &^ var2 作位清空运算
- 如果var2变量的位为0 则取var1变量对应的位值作为结果位
- 如果var2变量的位为1 则结果位取0
5、<<和>>左移和右移运算符
两个运算符左侧总是为要进行位移操作的变量,右侧为需要移动的位数值。之前因为看到32<<0=32就有点懵,以为是0左移32位 不明白为什么结果为32,就是因为把32当做要位移的位数了。
1<<N = 2^N
-----------
1 左移多少位等于2的多少次方
1024>>N = 1024/2^N
---------------
右移N位 相当于除以2的N次方
关于左移、右移 , 有一个Go在写磁盘单位GB MB KB等大小定义的例子
在使用const
关键字的时候 可使用内置变量 iota
从0开始自动递增
在遇到下个常量块或者单个常量定义的时候 也就是再一次使用const关键字的时候 iota置0;
package main
type ByteSize float64
const(
B ByteSize = 1<<(10*iota) // 1<<(10*0)
KB // 1<<(10*1)
MB // 1<<(10*2)
GB // 1<<(10*3)
TB // 1<<(10*4)
PB // 1<<(10*5)
)