JavaScript 使用 32 位按位运算数
JavaScript 将数字存储为 64 位浮点数,但所有按位运算都以 32 位二进制数执行。
在执行位运算之前,JavaScript 将数字转换为 32 位有符号整数。
执行按位操作后,结果将转换回 64 位 JavaScript 数。
一句话总结:第一位符号位,1为负,0为正;后面跟31位的1或0。
1. 按位与&
同位比较,全部是1则为1,否则为0
- 举例:6 & 3
首先,我们知道位运算符都是按 32位 二进制进行计算,所以我们先将这两个数转成二进制
6 => 0000 0000 0000 0000 0000 0000 0000 0110
3 => 0000 0000 0000 0000 0000 0000 0000 0011
然后按照&的规则,同位比较得到
0000 0000 0000 0000 0000 0000 0000 0010 => 2
所以 6 & 3 = 2
2. 按位或|
同位比较,有一个是1则为1,否则为0
- 举例:6 | 3
6 => 0000 0000 0000 0000 0000 0000 0000 0110
3 => 0000 0000 0000 0000 0000 0000 0000 0011
按照|的规则,同位比较得到
0000 0000 0000 0000 0000 0000 0000 0111 => 7
所以 6 | 3 = 7
3. 按位异或^
同位比较,有且只有一个是1则为1,否则为0
- 举例:6 ^ 3
6 => 0000 0000 0000 0000 0000 0000 0000 0110
3 => 0000 0000 0000 0000 0000 0000 0000 0011
按照^的规则,同位比较得到
0000 0000 0000 0000 0000 0000 0000 0101 => 5
所以 6 ^ 3 = 5
4. 取反~
反转所有位,也就是1变为0,0变为1,包括符号位
- 举例:
6 6 => 0000 0000 0000 0000 0000 0000 0000 0110的规则,取反得到
按照
1111 1111 1111 1111 1111 1111 1111 1001
这里我们看到第一个符号位变为了1,说明结果是一个负数,那么这里还需要说明的是,负数在32位二进制中是按照补码的形式存在的: 负数是正数的二进制补码加 1
所以这里需要反向操作,先减去个1,再进行翻转得到
1000 0000 0000 0000 0000 0000 0000 0111 => -7
所以 ~6 = -7
负数的理解:例如7的二进制为0000 0000 0000 0000 0000 0000 0000 0111,那么-7就应该是7的补码加上1,最终得到1111 1111 1111 1111 1111 1111 1111 1001
5. 左位移<<
向左侧平移,右侧补0,超出的部分截取掉
- 举例:6 << 3
6 => 0000 0000 0000 0000 0000 0000 0000 0110
向左侧平移3位,右侧补0,左侧溢出的部分截取掉,得到
0 0000 0000 0000 0000 0000 0000 0110 000 => 48
说明:对于二进制的计算,0 0000 0000 0000 0000 0000 0000 0110 000 => 2的5次方 + 2的4次方
Math.pow(2, 5) + Math.pow(2, 4)
=32+16=48
5. 有符号右位移>>
向右侧平移,左侧补最左侧的拷贝(也就是符号不变),超出的部分截取掉
- 举例:6 >> 2
6 => 0000 0000 0000 0000 0000 0000 0000 0110
00 0000 0000 0000 0000 0000 0000 0000 01 => 1 - 举例:-6 >> 2
-6 => 1111 1111 1111 1111 1111 1111 1111 1010
11 1111 1111 1111 1111 1111 1111 1111 10 => -2
6. 无符号右位移>>>
向右侧平移,左侧补0,超出的部分截取掉
- 举例:6 >>> 2
6 => 0000 0000 0000 0000 0000 0000 0000 0110
00 0000 0000 0000 0000 0000 0000 0000 01 => 1 - 举例:-6 >>> 2
-6 => 1111 1111 1111 1111 1111 1111 1111 1010
00 1111 1111 1111 1111 1111 1111 1111 10 => 1073741822(Math.pow(2, 30) -Math.pow(2, 1)
)
应用
//1. 取整
//需要注意的是数字要在[-Math.pow(2, 31), Math.pow(2, 31) - 1]之间
console.log(~~11.23) //11
//2. 计算x二进制中1的个数
// Brian Kernighan 算法:x &= (x - 1) 将最后一个1变为0
const countOnes = (x) => {
let ones = 0;
while (x > 0) {
x &= (x - 1);
ones++;
}
return ones;
}
// 6 => 0000 0000 0000 0000 0000 0000 0000 0110
countOnes(6) //2
//3. 替换二进制中的某一位为1
// 6 => 0000 0000 0000 0000 0000 0000 0000 0110
// => 0000 0000 0000 0000 0000 0000 0001 0110 => 22
console.log(6 | (1 << 4)) //22
//4. 判断乘除运算的符号
(a > 0) ^ (b > 0)
刚开始学习二进制的位运算,哪里说的不对希望大佬们指正,还有其他的应用也希望大家不吝赐教,感谢!!