位运算符

336 阅读3分钟

位运算符

位运算符直接对二进制进行计算

复习:原码,反码,补码

原码:首位为符号位的二进制数,正数符号为0,负数符号为1

反码:(为了解决正负相加)正数的反码等于它的原码,负数的反码保留原符号位,其他位取反

补码:(为了解决反码+0与-0)正数的补码是其本身,负数的补码在反码基础上加1

计算机运算时,以补码进行运算

位与(&)

两个数的对应的二进制位都是1,则为1,否则为0

示例

let a = 5; //00000000 00000000 00000000 00000101
a = a & 4; //00000000 00000000 00000000 00000100
console.log(a); //00000000 00000000 00000000 00000100
//4

用途:可以用来判断奇偶性

//偶数的二进制最低位数不会为1而奇数为1
for(let i=0; i<4; i++) {
    if(i & 1) {
        console.log("奇数",i);
    }else {
        console.log("偶数",i);
    }
}

位或(|)

两个数对应的二进制位至少有一个1就为1,否则为0

let a = 5; //00000000 00000000 00000000 00000101
a = a | 4; //00000000 00000000 00000000 00000100
console.log(a); //00000000 00000000 00000000 00000101
//5

位异或(^)

两个数对应的二进制位相同则为0,反之则为1

let a = 5; //00000000 00000000 00000000 00000101
let b = a ^ 4; //00000000 00000000 00000000 00000100
console.log(b); //00000000 00000000 00000000 00000001
//1

用途:可以用来值的互相交换

let a = 5;
let b = 2;
a ^= b;
b ^= a;
a ^= b;
console.log(a, b); //2,5

位非(~)

操作当前二进制由1变0,由0变1

let a = 7; //00000000 00000000 00000000 00000111
console.log(~a);  //-8
//位非变化,正数直接被~变化
//11111111 11111111 11111111 11111000 原码
//10000000 00000000 00000000 00000111 反码 = 符号位不变,其余取反
//10000000 00000000 00000000 00001000 补码 = 反码 + 1 即为-8
let a = -7; //10000000 00000000 00000000 00000111
console.log(~a);  //6
//负数先算出它的补码在进行计算后,在进行~变化
//10000000 00000000 00000000 00000111 原码
//11111111 11111111 11111111 11111000 反码 = 符号位不变,其余取反
//11111111 11111111 11111111 11111001 补码 = 反码 + 1 即为-8
//位非变化
//00000000 00000000 00000000 00000110 即得出的结果为6

总结: ~a = - (a+1);

左移 <<

二进制所有位向左移动,高位丢弃,低位补0

let a = 7; //00000000 00000000 00000000 00000111
let b = a << 1; //二进制向左移,右边用0填上
console.log(b); //00000000 00000000 00000000 00001110 即14
//-------------------------负数左移
let a = -7; //10000000 00000000 00000000 00000111 原码
let b = a << 1; //二进制向左移,右边用0填上
console.log(b); //-14
//负数先转换成补码
//10000000 00000000 00000000 00000111 原码,a的原码
//11111111 11111111 11111111 11111000 反码
//11111111 11111111 11111111 11111001 补码,a的补码
//11111111 11111111 11111111 11110010 左移位,为b的原码
//10000000 00000000 00000000 00001101 反码
//10000000 00000000 00000000 00001110 补码,b的补码 即为-(8+4+2)=-14

总结:a<<n为a*2^n

有符号右移>>

二进制所有位向右移动,低位丢弃,高位补上的值始终为开始最左侧位数,即符号位始终不变

let a = 7; //00000000 00000000 00000000 00000111
let b = a >> 1; //00000000 00000000 00000000 00000011 弃掉低位,补上的值拷贝最左侧的数,补上去。
console.log(b); //3
//-------------------------负数左移
let a = -7; //10000000 00000000 00000000 00000111 原码
let b = a >> 1; //a的补码弃掉低位,补上的值拷贝最左侧的数,补上去,然后为b的原码
console.log(b); //-4
//先转换a的补码
//10000000 00000000 00000000 00000111 原码
//11111111 11111111 11111111 11111000 反码
//11111111 11111111 11111111 11111001 a的补码
//有符号右移
//11111111 11111111 11111111 11111100 b的原码
//10000000 00000000 00000000 00000011 反码
//10000000 00000000 00000000 00000100 补码

总结:a>>n得到为a/(2^n)结果取最小整数。

无符号右移>>>

二进制所有位向右移动,低位丢弃,高位补上0。即总为正数

let a = 7; //00000000 00000000 00000000 00000111
let b = a >>> 1; //00000000 00000000 00000000 00000011 弃掉低位,补上的值拷贝最左侧的数,补上去。
console.log(b); //3
//-------------------------负数左移
let a = -7; //10000000 00000000 00000000 00000111 原码
let b = a >>> 1; //a的补码弃掉低位,补上的值拷贝最左侧的数,补上去,然后为b的原码
console.log(b); //2147483644

结语

位运算符也许在平常自己写东西的时候很少用到,但是在算法,查看底层代码时会遇见位运算,学习记住还是很有必要性的。等哪天做到算法题判断奇偶性直接甩出&,嘿嘿嘿