按位非在不同语言的实现差异
1 简介
Go 中按位非(^x)的过程,按位非把二进制表示的数字每一位翻转:0→1,1→0,并且在该类型的位宽内进行。
a : 01011010
^a : 10100101 => 0xA5 = 165
无符号示例(uint8)
package main
import "fmt"
func main() {
var a uint8 = 0b01011010 // 0x5A = 90
r := ^a // 在 8 位内翻转
fmt.Printf("a = %08b (%d)\n", a, a) // 01011010 (90)
fmt.Printf("^a = %08b (%d)\n", r, r) // 10100101 (165)
}
逐位过程(仅 8 位):
a : 01011010
^a : 10100101 => 0xA5 = 165
有符号示例(int8)
package main
import "fmt"
func main() {
var b int8 = 6 // 二补码 00000110
c := ^b // 在 8 位内翻转 → 11111001,对应 int8 的 -7
// 想看“原始比特”,把有符号转成无符号再打印
fmt.Printf("b bits: %08b (val=%d)\n", uint8(b), b) // 00000110 (6)
fmt.Printf("^b bits: %08b (val=%d)\n", uint8(c), c) // 11111001 (-7)
}
要点: Go 的有符号整数用定宽二补码。在 N 位内,^x == -x-1 (mod 2^N)。
2 Python 中的对应操作
Python 的按位非是 ~x,且 int 是任意精度大整数。
~x 的数学恒等式:
~x == -x-1(无限二补码语义)。
因为是“无限位”,不自动截断到 8/32/64 位。
a = 0b01011010 # 90
print(~a) # -91 (不是 165!因为没有按 8 位截断)
如果你想模拟“在 8 位内取反”(等价 Go 的 uint8 效果),要加屏蔽:
a = 0b01011010 # 90
r8 = (~a) & 0xFF # 截到 8 位
print(r8) # 165
print(f"{r8:08b}") # 10100101
同理,要看 int8 的比特模式,用 & 0xFF 再格式化:
b = 6
c = ~b # -7
print(c) # -7
print(f"{c & 0xFF:08b}") # 11111001 (与 Go 的 int8 结果比特一致)
3 对比差异:数值模型与实现
维度 Go Python
运算符 一元 ^x = 按位非;二元 a ^ b = 异或 ~x = 按位非;a ^ b = 异或
整数模型 定宽(int8/16/32/64/uint*;int 依平台 32/64 位),二补码 任意精度大整数(位数按需增长),逻辑上“无限二补码”
取反结果 在类型位宽内翻转,高位受位宽限制;^x == -x-1 (mod 2^N) 无限位语义,直接得到数学值 -x-1,不会自动截到 N 位
查看比特 负数打印比特需转无符号(如 uint8(x)) 负数格式化会带负号;要看 N 位比特需 & ((1<<N)-1)
性能/实现 贴近硬件:对原生整型通常就是单条 CPU 指令 在大整数“字数组”(limbs)上逐块取反,再规范化符号;灵活但开销更高
大数支持 超过原生位宽需 math/big,用 (*Int).Not/组合 内建 int 就是大数
小贴士:
清位(bit clear): Go 有专门的 &^(AND NOT):x &^ mask。Python 用 x & ~mask。
跨语言移植: 需要明确位宽(8/16/32/64…),在 Python 侧用 & ((1<<N)-1) 进行屏蔽。
- 常见用法对照
A) 清除若干标志位
const (
R = 1 << 0
W = 1 << 1
X = 1 << 2
)
var perm uint8 = R | W | X // 0b111
perm = perm &^ (W | X) // 清除 W、X
// perm == R
Python:
R, W, X = 1<<0, 1<<1, 1<<2
perm = R | W | X # 0b111
perm = perm & ~(W | X) # 清除 W、X
perm == R
B) 有符号取反恒等式验证
Go(以 int32 为例)
var x int32 = 123
y := ^x
z := -x - 1
fmt.Println(y == z) // true
Python
x = 123
print(~x == -x - 1) # True
4 注意事项
Python 中 ^ 不是取反:从Go迁移到python 的用户 ^ 直接带到 Python,用成按位非,结果得到的是“异或”。
位宽差异:Go 是定宽,Python 是无限位。要在 Python 中复现 Go 的结果,务必加屏蔽:
def notN(x, N): # 在 N 位内取反
return (~x) & ((1<<N)-1)
打印比特表示:Go 的负数打印需要转无符号;Python 的负数需要 & ((1<<N)-1) 后再格式化。
布尔与集合:Go 的 ^ 不能用于 bool 或集合;Python 的 ^ 在 bool 上是异或、在 set 上是对称差,~ 只对整数有效。
常量溢出(Go):^ 作用于未类型化常量时可“无限精度”,一旦赋给定宽类型会按目标类型截断或在编译期报溢出。
4 小结
语义:按位非在两语言都是“逐位翻转”;
符号:Go 用一元 ^x,Python 用 ~x;
核心差异:Go 在固定位宽内翻转(贴近硬件),Python 采用无限二补码语义(得到 -x-1,不自动截断)。
实务:跨语言时明确位宽;Python 侧用掩码还原 Go 的定宽效果;清位在 Go 用 &^,在 Python 用 & ~
- 点赞
- 收藏
- 关注作者
评论(0)