go语言位运算

一、6 种位运算符及用途

运算符 语法 功能 典型应用场景
& a & b 按位与 掩码操作、判断奇偶、权限检查
` ` `a b`
^ a ^ b 按位异或 交换变量、数据加密、去重
&^ a &^ b 位清空(AND NOT) 清除指定标志位
<< a << n 左移 快速乘2ⁿ、位掩码生成
>> a >> n 右移 快速除2ⁿ、提取高位数据

💡 关键:

  • ^ 作为单目运算符时表示按位取反(如 ^0b1010 = 0b0101)
  • &^ 是 Go 特有操作:结果为 a & (^b)

二、4 类实战应用

1. 高效状态管理(权限系统)

go 复制代码
const (
    Read    = 1 << iota // 0b001 (1)
    Write               // 0b010 (2)
    Execute             // 0b100 (4)
)

// 添加权限:user |= Read | Write
// 检查权限:(user & Read) != 0
// 清除权限:user &^= Write

2. 算法优化(高频题目)

  • 判断奇偶:n & 1 == 0 比 n % 2 == 0 快 3~5 倍

  • 交换变量(无临时变量):

go 复制代码
a ^= b
b ^= a
a ^= b
  • 2 的幂判断:n & (n-1) == 0

  • 只出现一次的数字(LeetCode 136):

go 复制代码
func singleNumber(nums []int) int {
    result := 0
    for _, num := range nums {
        result ^= num // 利用 a ^ a = 0 的性质
    }
    return result
}

3. 内存压缩(位图 Bitmap)

go 复制代码
type Bitmap struct {
    bits []uint64
}

// 设置第 n 位为 1
func (b *Bitmap) Set(n int) {
    index, offset := n/64, uint(n%64)
    b.bits[index] |= 1 << offset
}

// 检查第 n 位
func (b *Bitmap) Get(n int) bool {
    index, offset := n/64, uint(n%64)
    return (b.bits[index] & (1 << offset)) != 0
}

海量数据去重、快速检索(10亿数据仅需 125MB 内存)

4. 数据编解码

IP 地址转换:

go 复制代码
ip := 0xC0A80101 // 192.168.1.1
part1 := byte(ip >> 24) // 192
part2 := byte(ip >> 16) // 168

三、避坑指南

1. 运算符优先级问题

❌ 错误写法:

go 复制代码
if flags & Read != 0 { ... } // 等价于 flags & (Read != 0)

✅ 正确写法:

go 复制代码
if (flags & Read) != 0 { ... } // 必须加括号!

2. 移位溢出

go 复制代码
var a uint8 = 255
b := a << 1 // 结果为 254(而非 510),uint8 溢出

移位长度不能超过类型位数(如 int32 最多移 31 位)

3. 负数右移

go 复制代码
var a int8 = -8   // 二进制: 11111000
b := a >> 2       // 结果: -2 (11111110)

右移负数时高位补 1(符号位扩展)

四、性能优化证据

操作 位运算实现 传统实现 性能提升
乘 2 n << 1 n * 2 3~5 倍
除 2(向下取整) n >> 1 n / 2 2~4 倍
奇偶判断 n & 1 n % 2 4~6 倍
取模 2 k 2^k 2k n & (k-1) n % k 10 倍+

⚠️ 注意:现代编译器可能自动优化简单算术,但位运算在复杂表达式和底层系统中仍具优势。

五、灵魂问题

  1. Q:x & (x-1) 有什么深层用途?

    A:

    判断是否为 2 的幂(结果为 0 则是)

    计算二进制中 1 的个数(循环直到 0)

    求最低位的 1(x & ^(x-1))

  2. Q:如何用位运算实现加法?

    A:

go 复制代码
func add(a, b int) int {
    for b != 0 {
        carry := a & b   // 计算进位
        a = a ^ b       // 无进位加法
        b = carry << 1  // 进位左移
    }
    return a
}

六、真题

题目 :实现函数 func reverseBits(num uint32) uint32(翻转二进制位)
答案

go 复制代码
func reverseBits(num uint32) uint32 {
    result := uint32(0)
    for i := 0; i < 32; i++ {
        // 取 num 的最低位,放到 result 的对应高位
        result = (result << 1) | (num & 1)
        num >>= 1
    }
    return result
}

💡 注意点:

  • 明确位运算优先级(用括号避免歧义)
  • 处理负数时说明符号位行为
  • 强调位运算在内存敏感场景(嵌入式/高频交易)的价值
相关推荐
祀爱3 分钟前
定时任务之BackgroundService的详细教程
后端·c#·asp.net
AgentOPC4 分钟前
Cerebras WSE-3 vs Nvidia H100/H200/B200:详细技术对比——谁才是 AI 时代真正的“芯片之王“
开发语言·人工智能·nvidia
qq_2518364578 分钟前
基于java 汽车检修管理系统设计与实现 论文
java·开发语言·汽车
lbaihao8 分钟前
LLVM Cpu0 调用规则解析
开发语言·前端·python·llvm
基德爆肝c语言10 分钟前
Qt系统相关
开发语言·qt
redaijufeng13 分钟前
C/C++程序从编译到链接的过程
c语言·开发语言·c++
E等于MC平方15 分钟前
用 Rust 写一个工业级 POSP 支付系统
后端·rust·消费·8583·交易·posp·银联
木子墨51617 分钟前
系统设计面试 | 实现一个限流器:滑动窗口 → 令牌桶 → 漏桶
java·开发语言·数据结构·数据库·面试·职场和发展
程序员阿明37 分钟前
spring boot + vue3 实现RSA加密解密
java·spring boot·后端
明月_清风41 分钟前
Redis 数据类型全景解析:从基础到高阶,一文掌握九大核心结构与应用场景
redis·后端