go 位操作

以下内容转载自 https://blog.csdn.net/benben_2015/article/details/79469325

Go的位操作

在计算机内存和处理能力都成本昂贵的时代,位操作是(在某些情况下是唯一的)一种被优先选择来处理信息的方式。即使在今天,直接的位操作在一些情况下同样也很重要。例如:低级系统编程,图像处理,密码学等。
Go编程语言支持以下几种位操作,包括:

&位与
|位或
^位异或
&^位清空
<<左移
>>右移

文章后面的部分将详细讨论每一种操作,以及举例说明它们如何使用。

&运算

在Go中,&操作表示两个整数按位AND运算。AND操作具有如下特性:

Given operands a,b
AND(a,b)=1;only if a=b=1
           else=0

AND操作可以有效的清除值为0的数位,例如,我们可以使用&操作来清除最后4个最低有效位(LSB),使其为0。

func main(){
    var x uint8=0xAC   //x=10101100
    x=x&0xF0           //x=10100000
}

所有的二进制操作都支持简短的复合赋值形式。例如上面的例子可以改写成:

func main(){
    var x uint8=0xAC   //x=10101100
    x&=0xF0            //x=10100000
}

另外一个小技巧就是用&操作来检测一个数是奇数还是偶数。这是因为奇数的最低有效位为1,而偶数的最低有效位为0。因此我们可以利用整数和数字1进行“与”运算,就可判断该数的奇偶性。

import (
    "fmt"
    "math/rand"
)

func main(){
    for x:=0;x<100;x++{
        num:=rand.Int()
        if num&1==1{
            fmt.Printf("%d is odd\n",num)
        }else{
            fmt.Printf("%d is even\n",num)
        }
    }
}

| 运算

|表示两个整数按位OROR操作具有如下特点。

Given operands a,b
OR(a,b)=1;when a=1 or b=1
          else=0

我们可以使用OR操作来有选择的设置给定整数的某个位。例如下面的例子,我们使用OR了设置MSB(最高有效位),第7位和第三位的值为1。

func main(){
    var a uint8=0
    a|=196
    fmt.Printf("%b",a)
}

使用位掩码技术对一个给定的整数值任意位设置时,OR相当有用。例如,我们可以扩展之前的程序。下面的程序使用十进制的196和3来设置对应位。

func main(){
    var a uint8=0
    a|=196
    a|=3
    fmt.Printf("%b",a)
}

位作为配置信息

我们可以结合ORAND两种操作符,作为指定配置值和分别读取它们的一种方法。下面的源代码简要的说明如何使用。函数procstr转化string类型的内容,它需要两个参数:第一个参数str表示待转换的字符串,第二个参数conf,是个整数。用来指定多个转化配置。

const (
    UPPER = 1
    LOWER = 2
    CAP   = 4 //首字母大写
    REV   = 8 //颠倒顺序
)

func main() {
    fmt.Println(procstr("HELLO PEOPLE!", LOWER|REV|CAP))
}

func procstr(str string, conf byte) string {
    //reverse string
    rev := func(s string) string {
        runes := []rune(s)
        n := len(runes)
        for i := 0; i < n/2; i++ {
            runes[i], runes[n-1-i] = runes[n-1-i], runes[i]
        }
        return string(runes)
    }

    //query config bits
    if (conf & UPPER) != 0 {
        str = strings.ToUpper(str)
    }
    if (conf & LOWER) != 0 {
        str = strings.ToLower(str)
    }
    if (conf & CAP) != 0 {
        str = strings.Title(str)
    }
    if (conf & REV) != 0 {
        str = rev(str)
    }
    return str
}

上面主函数中调用方法procstr(“HELLO PEOPLE”,LOWER|REV|CAP),将会把字符串“HELLO PEOPLE”转化为小写,单词首字母大写,然后颠倒字符串前后顺序。此时参数conf的值为14,它的第二,第三和第四位设置了转化的这些条件。然后,代码使用连续的if语句块来提取这些配置,并对字符串应用对应的字符串转化。

^操作

Go中用^表示XOR,它具有以下属性:

Given operands a,b
XOR(a,b)=1;only if a!=b
           else=0

异或定义的含义是它可以将一个值切换到另一个。例如,给定的16位值,我们可以使用下面代码切换前8位(从最高有效位开始)。

func main(){
    var a uint16=0xCEFF
    a^=0xFF00    //same a=a^0xFF00
}

// a = 0xCEFF   (11001110 11111111)
// a ^=0xFF00   (00110001 11111111)

XOR的一个实际用途就是判定符号,(a^b)>=0判定两个数的符号是否相同。

func main(){
    a,b:=-12,25
    fmt.Println("a and b have same sign?",(a^b)>=0)
}

/*prints:
a and b have same sign? false */

^作为按位补码(NOT)

与其他语言不同(c/c++,Java,Python,Javascript等),Go没有一个专门的一元补码操作符来对值取反,代替的是XOR操作符。

func main(){
    var a byte=0x0F
    fmt.Printf("%08b\n",a)
    fmt.Printf("%08b\n",^a)
}

/* prints:
00001111  //var a
11110000  //^a

&^操作

&^操作,也称AND NOT,它是一个使用ANDNOT的简写形式,具有以下特征:

Given operands a,b
AND_NOT(a,b)=AND(a,NOT(b))
  •  

它有一个有趣的特性,那就是当第二个数设置为1,它就会清除第一个数。

  •  

下面的代码使用AND NOT操作来清除变量a的四个最低有效位。

func main(){
    var a byte=0xAB
    fmt.Printf("%08b\n",a)
    a &^=0x0F
    fmt.Printf("%08b\n",a)
}

/* prints:
10101011
10100000 */

<<和>>操作

类似于其他c派生语言,Go使用<<>>来分别代表左移和右移操作。具体特点如下:

Given integer operands a and n,
a<<n;shifts all bits in a to the left n times
a>>n;shifts all bits in a to the right n times

例如下面的例子中将a的值左移了三次,每次都将其移动的结果打印出来说明他的用途。

func main(){
    var a int8=3
    fmt.Printf("%08b\n",a)
    fmt.Printf("%08b\n",a<<1)
    fmt.Printf("%08b\n",a<<2)
    fmt.Printf("%08b\n",a<<3)
}

/*prints:
00000011
00000110
00001100
00011000 */

记住每次移动,最低有效位用0填充,相反的,使用右移操作位时,最高有效位用0填充。(但是有符号位有些区别,详见文章后面的算数移位)

func main(){
    var a int8=120
    fmt.Printf("%08b\n",a)
    fmt.Printf("%08b\n",a>>1)
    fmt.Printf("%08b\n",a>>2)
    fmt.Printf("%08b\n",a>>3)
}

/*prints:
01111000
00111100
00011110
00001111 */

左移和右移操作的小技巧是可以在乘除法用算时,每次操作表示对原数进行乘以2或除以2例如下面将200右移一位,表示将其除以2。

func main(){
    a:=200
    fmt.Printf("%d\n",a>>1)
}

/*prints:
100 */

或者用左移2位,表示乘以4。例如

func main(){
    a:=12
    fmt.Printf("%d\n",a<<2)
}

/* prints:
48 */

位移操作给我们提供了一种有趣的方式来操作二进制值的指定位。例如下面的例子中用|<<操作来设置变量a的第三位。

func main(){
    var a int8=8
    fmt.Printf("%08b\n",a)
    a=a|(1<<2)
    fmt.Printf("%08b\n",a)
}

/*prints:
00001000
00001100 */

或者你可以将其与&操作结合起来,测试第n位的值是否被设置。

func main(){
    var a int8=12
    if a&(1<<2)!={
        fmt.Println("take action")
    }
}

/* prints:
take action */

利用&^和移位操作,我们将第n位的值不设置。例如下面的例子将变量a的第3位没有设置。

func main(){
    var a int8=13
    fmt.Printf("%04b\n",a)
    a=a&^(1<<2)
    fmt.Printf("%04b\n",a)
}

/* prints:
1101
1001 */

算数移位

当一个有符号值(左移)移位时,Go自动使用算数移位。在右移操作中,符号位被拷贝(或者扩展)来填充移动的位置。

结论

与其他现代语言一样,Go也支持所有的位操作。这篇文章仅仅提供了一些有关位操作的简单例子。你可以在由Sean Eron Anderson写的Bit Twiddling Hacks文章中发掘更多诀窍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值