编程基础认知重建_位运算符

type
Post
status
Published
date
Feb 18, 2025
slug
2025021801
summary
tags
编程
category
编程学习
icon
password
0b 是一种前缀,用于表示一个数字是 二进制(Binary) 格式的字面量。它是许多编程语言(如 Python、C、C++、Java 等)中的一种约定,用来明确地告诉编译器或解释器,后面的数字是以二进制形式书写的。 常见的数字表示方式:0b 表示二进制(Binary),其中 b 是 "binary" 的缩写。 0o 或 0 表示八进制(Octal),其中 o 是 "octal" 的缩写。 0x 表示十六进制(Hexadecimal),其中 x 是 "hex" 的象征。
结合二进制(0和1两种状态)来记忆位运算符:
  • |(按位或)--> 有11
  • &(按位与)--> 有00
  • ^(按位异或)--> 不同才1
  • ~(按位取反) --> 01, 10
  • <<(左移)--> 向左移位, 用0补空
  • >>(带符号右移)--> 左边根据符号位填充(正数补 0,负数补 1
  • >>>(无符号右移)--> 左边始终补 0
通过实际运用来理解:

按位或 |

很常见的用法就是 标志位管理 ,比如操作用户权限 假设用8位二进制表示用户权限,每一位表示一种权限(如读、写、执行等),初始时用户权限为空:
定义一个读取权限的掩码,假设第二位数字代表读取:
如果要给用户添加读取权限,那么就可以使用 按位或(|):
可以看出,不管用户权限第二位原来是什么值,只要与掩码或之后,都会是1,

按位与 ~

按位与 &

承接上文,如果我们要清楚用户的读取权限,就可以将 按位与(&)和按位取反(~)两者结合使用:
首先将掩码取反,这样读取权限对应的第二位就是0,这样不管用户权限的第二位是什么值,与之后都是0
最后我们可以通过 按位与(&)检查用户的读取权限
因为非零值会被视为“真”(true),而零值会被视为“假”(false),掩码中只有读取权限位上1,所以只要用户权限的该位不为1,那结果就是0,判定为false.
同时 & 还可以很方便的判断奇偶性 在二进制中,除0以外,只要末尾是1的就是奇数,末尾是0就是偶数,与1即可判断:
0b0001 = 1, 0b0010 = 2, 0b0011 = 3, 0b0100 = 4

按位异或 ^

使用 按位异或(^)可以在不使用临时变量的情况下交换两个变量的值。
比如:交换两个整数ab的值:
利用这个神奇的交换特性就能解决一道很经典的问题: 找出数组中唯一出现一次的数字:
同样也可以快速的判断两数是否相等:

左移 <<

右移 >>

<<>> 实际上就是在二进制位数上平移
  • 幂级乘除 左移操作相当于将数值乘以2的幂
右移操作相当于将数值除以2的幂(整数除法)
  • 移位 假设需要存储8个开关的状态(开/关),每个开关用1位表示
是不是很像前面提到的掩码?

无符号右移 (>>>)

这里没有必要过分强调 原码 反码 补码 的概念, 我认为这只会增加理解的难度
提到符号, 首先需要理解二进制是如何表示负数的.
理论上正数和负数应该在数学空间上是对称分布的, 以 8 位二进制为例,能表示2^8=256 个不同的数值, 如果我们将这些数值平均分配给正数和负数, 那必须去掉128, 因为0需要占用一个正数:
  • 正数范围:0 ~ 127(共 128 个数)
  • 负数范围:1 ~ -128(共 128 个数)
最直观的想法就是直接将正数取反来表示负数, 并且直接用第一位作为符号位(0 表示正数,1 表示负数).这样会导致存在两个 0+000000000)和 -010000000
为了解决上述问题,计算机采用了补码 的设计方案取反后加一
  • 例如,5 的计算过程:
    • 正数 5 的二进制:00000101
    • 取反:11111010
    • 111111011
    • 最终结果:5 的补码为 11111011
这样+0-0 都被统一为 00000000,避免了歧义
补码的设计使得加法和减法可以用同一种电路实现,化了硬件实现,并提高了运算效率。例如,A - B 等价于 A + (-B),其中 -BB 的补码
在某些语言中(如 Java 和 JavaScript),整数类型是有符号的,默认使用补码表示负数。当需要将一个有符号整数当作无符号整数处理时,带符号右移(>>)会保留符号位,导致结果不符合预期。使用无符号右移(>>>)可以忽略符号位,确保高位始终用 0 填充。
对比一下:

这是重建编程认知的一个尝试,希望能有不错的效果
 
上一篇
我怎么看AI
下一篇
边缘
Loading...