位运算基础

153 阅读5分钟

心算二进制与十进制的转换

  1. 熟记二进制的特殊数字
十进制算法二进制
1282^71000 0000
192128 + 2^61100 0000
224192 + 2^51110 0000
240224 + 2^41111 0000
248240 + 2^31111 1000
252248 + 2^21111 1100
254248 + 2^11111 1110
255248 + 2^01111 1111

规律:从128-255,每两个数之间的差是递减的,分别是 2^62^52^42^32^22^12^0

十进制算法二进制
12^01
22^110
42^2100
82^31000
162^41 0000
322^510 0000
642^6100 0000
1282^71000 0000

规律:每个以 1 开头,后面全是 0 的二进制数字对应的十进制数字都是 2^n , n 表示从右往左数 “1” 的位数减一,例: 1000 中, “1” 为第 4 位,对应的十进制数字是 2^(4-1) = 8 2. 将 x (0 <= x < 256) 转为二进制,用以上的特殊数字计算哪些数加起来等于 x ,于是用到了哪些数字,就在对应的位置上写 1 ,其他为 0 3. 例子:

3.1. 将 129 转换为二进制

129 = 128 + 1 ,因为 128 是第 8 位为 11 是第一位为 1 ,因此 129 的二进制数为 `1000 0001`

3.2. 将 185 转换为二进制

185 = 128 + 32 + 16 + 8 + 1 ,因此 185 的二进制为 `1011 1001`

3.3. 将 244 转换为二进制

244 = 240 + 4 ,因此 244 的二进制为 `1111 0100`

参考:理论讲解:帮助你快速懂得心算十进制转二进制------------一做就会一讲就废系列

与 (&)

计算式 a & b , a、b 各位中同为 1 才为 1 ,否则为 0

n & (n - 1) 表示将n的二进制表示中的最低位为1的改为0

// 求某一个数的二进制表示中1的个数
while (n > 0) {
  count++
  n &= (n - 1)
}
// 判断一个数是否是二次幂
n > 0 && (n & (n - 1)) === 0

因为 n 的二次幂的二进制数第一位都是 1 ,其后都是 0 ,因此通过 n & (n - 1) 消除掉二进制的 1 之后,自然就变成了 0

一些二进制比较特殊的数字

0x55555555: 0101 0101 0101 0101 0101 0101 0101 0101 偶数位为 0 ,奇数位为 1 交替出现

0xaaaaaaaa: 1010 1010 1010 1010 1010 1010 1010 1010 偶数位为 1 ,奇数位为 0 交替出现

0x33333333: 0011 0011 0011 0011 0011 0011 0011 0011 0 和 1 每隔两位交替出现

0xcccccccc: 1100 1100 1100 1100 1100 1100 1100 1100 1 和 0 每隔两位交替出现

0x0f0f0f0f: 0000 1111 0000 1111 0000 1111 0000 1111 1 和 0 每隔四位交替出现

0xf0f0f0f0: 1111 0000 1111 0000 1111 0000 1111 0000 0 和 1 每隔四位交替出现

或 (|)

计算式 a | b , a、b 各位中有一个为 1 则为 1

非 (~)

将运算符后二进制数反转, 0 变 1 , 1 变 0

异或 (^)

计算式 a ^ b , a、b 对应位相同为 0 ,不同则为 1

根据性质可以得出: a^a=0a^0=a,且支持交换律

位移

a << 1 相当于 a * 2 (不超出数值类型范围的情况下)

a >> 1 相当于 a / 2

左移 (<<)

对于数值 3 ,它的二进制为 00011 ,第一位为符号位

下标符号位3210
位数00011

左移两位 3 << 2注意符号位不参与位移

下标符号位3210
位数00011

高位舍弃,低位补 0 ,结果得 12

下标符号位3210
位数01100

对于 -3

下标符号位3210
位数11101

计算机中的负数以补码的形式存储,正数的补码和原码一样,负数的补码由除符号位的原码(改数的绝对值)的反码加一得到

左移两位 -3 << 2

下标符号位3210
位数11101

高位舍弃,低位补 0 ,结果为 -12 (结果仍为补码)

下标符号位3210
位数10100

右移 (>>) 和无符号右移 (>>>)

右移在移动后高位补符号位,低位舍弃,因此在右移负数时,得到的结果差别很大

无符号右移则为移动后高位补 0 ,低位舍弃(此时符号位会参与位移