文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Golang中的位操作方法有哪些

2023-07-05 06:32

关注

这篇文章主要讲解了“Golang中的位操作方法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang中的位操作方法有哪些”吧!

在计算机内存昂贵,处理能力有限的美好旧时光里,用比较黑客范的位运算方式去处理信息是首选方式(某些情况下只能如此)。时至今日,直接使用位运算仍然是很多计算领域中不可或缺的部分,例如底层系统编程,图形处理,密码学等。

Go 编程语言支持以下按位运算符:

&   bitwise AND |   bitwise OR ^   bitwise XOR&^   AND NOT<<   left shift>>   right shift

本文的余下部分详述了每个操作符以及它们如何使用的案例。

& 运算符

在 Go 中,  & 运算符在两个整型操作数中执行按位 AND 操作。AND 操作具有以下属性:

Given operands a, bAND(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 的时候,那他就是奇数。我们可以用一个数字和 1 进行 & 操作,然后在和 1 做 AND 运算,如果的到的结果是 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)        }    }}

在  Playground  上运行上面的例子

| 操作符

| 对其整型操作数执行按位操作。回想一下操作符具备以下性质:

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

我们可以利用按位操作符为给定的整数有选择地设置单个位。例如,在如下示例中我们使用按位将示例数(从低位到高位(MSB))中的第 3 ,第 7 和第 8 位置为 1 。

func main() {    var a uint8 = 0    a |= 196    fmt.Printf("%b", a)}// 打印结果  11000100            ^^   ^

练习场中可运行范例。

在使用位掩码技术为给定的整型数字设置任意位时,运算非常有用。例如,我们可以扩展之前的程序为变量 a 存储的值设置更多的位。

func main() {    var a uint8 = 0    a |= 196    a |= 3    fmt.Printf("%b", a)}// 打印结果 11000111

在练习场中可以运行范例。

在前面的程序里,不仅要按位设置十进制的 196,而且要设置低位上的十进制 3。我们还可以继续(上更多的值)设置完所有的位。

位运算的配置用法

现在,回顾一下 AND(a, 1) = a 当且仅当 a = 1。 我们可以利用这个特性去查询其设置位的值。例如,在上述代码中 a & 196 会返回 196 是因为这几位的值在 a 中确实都存在。所以我们可以结合使用 OR 和  AND 运算的方式来分别设置和读取某位的配置值。.

接下来的源码片段演示了这个操作。函数 procstr 会转换字符串的内容。它需要两个参数:第一个, 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 {    // 反转字符串    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)    }    // 查询配置中的位操作    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}

在 Playground上面运行代码.

上面的 procstr("HELLO PEOPLE!", LOWER|REV|CAP) 方法会把字符串变成小写,然后反转字符串,最后把字符串里面的单词首字母变成大写。这个功能是通过设置 conf 里的第二,三,四位的值为 14 来完成的。然后代码使用连续的 if 语句块来获取这些位操作进行对应的字符串转换。

^ 操作符

在 Go 中  按位 异或 操作是用 ^ 来表示的。 异或运算符有如下的特点:

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

异或运算的这个特性可以用来把二进制位的一个值变成另外一个值。举个例子,给到一个 16 进制的值,我们可以使用以下代码切换前8位(从 MSB 开始)的值。

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

在前面的代码片段中,与 1 进行异或的位被翻转(从 0 到 1 或从 1 到  0)。异或 运算的一个实际用途,例如,可以利用 异或运算去比较两个数字的符号是否一样。当 (a ^ b) ≥ 0 (或相反符号的 (a ^ b) < 0 )为 true 的时候,两个整数 a,b 具有相同的符号,如下面的程序所示:

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

在 Go 的 Playground运行代码。

当执行上面这个程序的时候,将会打印出:a and b have same sign? false。在 Go Playground 上修改程序里 a ,b 的符号,以便看到不同的结果。

^ 作为取反位运算符 (非)

不像其他语言 (c/c++,Java,Python,Javascript,等), Go 没有专门的一元取反位运算符。取而代之的是,XOR 运算符 ^,也可作为一元取反运算符作用于一个数字。对于给定位 x,在 Go 中 x = 1 ^ x 可以翻转该位。在以下的代码段中我们可以看到使用 ^a 获取变量 a 的取反值的操作。

func main() {    var a byte = 0x0F    fmt.Printf("%08b\n", a)    fmt.Printf("%08b\n", ^a)}// 打印结果00001111     // var a11110000     // ^a

在练习场中可以运行范例。

&^ 操作符

&^ 操作符意为 与非,是 操作符的简写形式,它们定义如下。

Given operands a, bAND_NOT(a, b) = AND(a, NOT(b))

如果第二个操作数为 1 那么它则具有清除第一个操作数中的位的趣味特性。

AND_NOT(a, 1) = 0; clears aAND_NOT(a, 0) = a;

接下来的代码片段使用 AND NOT 操作符,将变量值1010 1011变为 1010 0000,清除了操作数上的低四位。

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

在练习场中运行范例。

<< 和 >> 操作符

与其他 C 的衍生语言类似, Go 使用 <<>> 来表示左移运算符和右移运算符,如下所示:

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

例如,在下面的代码片段中变量 a00000011)的值将会左移位运算符分别移动三次。每次输出结果都是为了说明左移的目的。

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)}// 输出的结果:00000011000001100000110000011000

在 Playground 运行代码

注意每次移动都会将低位右侧补零。相对应,使用右移位操作符进行运算时,每个位均向右方移动,空出的高位补零,如下示例 (有符号数除外,参考下面的算术移位注释)。

func main() { var a uint8 = 120 fmt.Printf("%08b\n", a) fmt.Printf("%08b\n", a>>1) fmt.Printf("%08b\n", a>>2)}// 打印:011110000011110000011110

在 练习场中可以运行范例。

可以利用左移和右移运算中,每次移动都表示一个数的 2 次幂这个特性,来作为某些乘法和除法运算的小技巧。例如,如下代码中,我们可以使用右移运算将 200(存储在变量 a 中)除以 2 。

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

在 练习场 中可以运行范例。

或是通过左移 2 位,将一个数乘以4:

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

在 练习场 中可以运行范例。

位移运算符提供了有趣的方式处理二进制值中特定位置的值。例如,下列的代码中,|<< 用于设置变量 a 的第三个 bit 位。

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

可以在 练习场 中运行代码示例。

或者,您可以组合位移运算符和 & 测试是否设置了第n位,如下面示例所示:

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

在 练习场中运行代码。

使用  &^ 和位移运算符,我们可以取消设置一个值的某个位。例如,下面的示例将变量 a 的第三位置为 0 :

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

在 练习场 中运行代码。

关于算术位移运算的笔记

当要位移的值(左操作数)是有符号值时,Go 自动应用算术位移。在右移操作期间,复制(或扩展)二进制补码符号位以填充位移的空隙。

感谢各位的阅读,以上就是“Golang中的位操作方法有哪些”的内容了,经过本文的学习后,相信大家对Golang中的位操作方法有哪些这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯