Go中的bit位和位运算符

海生 · · 3800 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

一.二进制长什么样

bit比特是计算机的最小单元,是一个二进制位1或者0
t.Log("start")
t.Logf("%b", 0) //0
t.Logf("%b", 1) //1
t.Logf("%b", 2) //10
t.Logf("%b", 3) //11
/*
    int是带符号的,表示范围是:-2147483648到2147483648,即-2^31到2^31次方。
    uint则是不带符号的,表示范围是:2^32即0到4294967295。
*/
var one uint
one = 10000
t.Logf("%b", one) //10011100010000  13位,uint最多是32位

二.运算符

主要有下面几种运算符

&      位运算 AND
|      位运算 OR
^      位运算 XOR
&^     位清空 (AND NOT)
<<     左移
>>     右移

1.<<和>>左移和右移运算符

左移 i << n; 对i的所有位向左移n次
var i int64
t.Logf("%b", i) //0
i = 1
t.Logf("%b %d", i, i)       // 1 1
t.Logf("%b %d", i<<1, i<<1) //10 2  左移动 每个移位位置代表2的幂,左移动增加
t.Logf("%b %d", i<<2, i<<2) // 100 4
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) 左移动10位  2的10次方=1024
  MB  // 1<<(10*2)
  GB  // 1<<(10*3)
  TB     // 1<<(10*4)
  PB //  1<<(10*5)
)

2.位运算 & AND

同一位上都是1 才1 否咋0
c, d := 1, 1
t.Logf("c&d %b %b %b", c&d, c, d) //c&d 1 1 1
c, d = 1, 0
t.Logf("c&d %b %b %b", c&d, c, d) //c&d 0 1 0
c, d = 5, 3
t.Logf("c&d %b %b %b", c&d, c, d) //c&d 1 101 011
c, d = 5, 4
t.Logf("c&d %b %b %b", c&d, c, d) //c&d 100 101 100  十进制4
c, d = 50, 43
t.Logf("c&d %b %b %b", c&d, c, d) //c&d 100010 110010 101011 十进制34

1.使用案例 判断奇偶数

odd number :指不能被2整除的数 ,数学表达形式为:2k+1, 奇数可以分为正奇数和负奇
func IsOdd(i int)bool{
  return (i & 1) == 1 //i是否为奇数取决于二进制的最后一位是1还是0 是1则为奇数 0则为偶数
}

2.使用案例 计算数值的二进制位有多少个1

很容易想到只要与1进行&运算,第一位如果为0结果为0 第一位如果结果为1 结果为1 利用这个特性数值右移一位 循环计算即可
func BitCheck(i int)(count int){
  for i>0 {
    count = count + (i&1)
    i >>= 1
  }
  return
}

2.位运算 | OR

同一位上有一个是1就1,只有都是0才0
c, d = 0, 0
t.Logf("c|d %b %b %b", c|d, c, d) //c|d 0 0 0
c, d = 1, 1
t.Logf("c|d %b %b %b", c|d, c, d) //c|d 1 1 1
c, d = 1, 0
t.Logf("c|d %b %b %b", c|d, c, d) //c|d 1 1 0
c, d = 5, 3
t.Logf("c|d %b %b %b", c|d, c, d) //c|d 111 101 011  十进制7
c, d = 5, 4
t.Logf("c|d %b %b %b", c|d, c, d) //c|d 101 101 100  十进制5
c, d = 50, 43
t.Logf("c|d %b %b %b", c|d, c, d) //c|d 111011 110010 101011  十进制59

3.异或运算符 ^ XOR

^即可作为二元运算符,也可作为一元运算符。
作为二元运算符,^是异或运算符。
即两个数的二进制位不同时,当前位才置1 否则置0
有个很明显的规律 任何数和本身异或 结果为0, 0和任意数异或 结果为其本身
a, b := 2, 3
t.Logf("%b %b", a, b) //10 11
a ^= b
t.Logf("%b %b", a, b) // 1 11
4 ^ 15 = 11
---------------
00000100 ^
00001111 =
00001011 //10进制值位11

1.使用案例 数值交换

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互相抵消 完成了值的交换

4.位清空运算符 &^ AND NOT

4 &^ 15 = 0
---------------
00000100 &^
00001111
00000000
=0

三.二元运算符号

 a |= b  ----->  a = a | b  , a 或者 b 只要有一个为 1, 那么,a 的最终结果就为 1
 a &= b  ----->  a = a & b  , a 和 b 二者必须都为 1, 那么,a 的最终结果才为 1
 a ^= b  ----->  a = a ^ b  , 当且仅当 a 和 b 的值不一致时,a 的最终结果才为1,否则为0
a, b := 1, 0
a |= b
t.Logf("%b %b", a, b) // 1 0
a, b = 1, 0
a &= b
t.Logf("%b %b", a, b) // 0 0
a, b = 1, 0
a ^= b
t.Logf("%b %b", a, b) //  1 0
a, b = 2, 3
t.Logf("%b %b", a, b) //10 11
a |= b
t.Logf("%b %b", a, b) //11 11
a, b = 2, 3
a &= b
t.Logf("%b %b", a, b) // 10 11
a, b = 2, 3
a ^= b
t.Logf("%b %b", a, b) // 1 11

使用案例参考了作者niceshot
网页 https://juejin.im/post/5d9094...


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:海生

查看原文:Go中的bit位和位运算符

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3800 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传