机器中的位运算

Scroll Down

首先需要了解一下在计算机中原码,补码,还有反码的知识。

原码表示法是机器数的一种简单的表示法。

其符号位用0表示正号,用:表示负号,数值一般用二进制形式表示。

机器数的反码可由原码得到。如果机器数是正数,则该机器数的反码与原码一样; 如果机器数是负数,则该机器数的反码是对它的原码(符号位除外)各位取反而得到的。

机器数的补码可由原码得到。如果机器数是正数,则该机器数的补码与原码一样;

如果机器数是负数,则该机器数的补码是对它的原码(除符号位外)各位取反,并在未位加1而得到的。

因为在电脑中存储数值都是用补码来进行存储的,所以对负数的计算首先要先算出它的补码值

下面对java的一些位运算符进行实例计算

首先是运算符分为 & | ~ ^ >> << >>> 意义分别为

  1. 位与'&'
  2. 位或'|'
  3. 位非'~'
  4. 位异或'^'
  5. 右移'>>'
  6. 左移'<<'
  7. 0填充的右移'>>>'

其中位与运算是二者为1时才为1,否则为0 位或运算为两者有一个为1时则为1,否则为0 位非运算,0转换成1,1转换成0,首先高位符号位从0转为1 异或运算为两者都相同时则为0,否则为1

int a=129;//10000001
int b=128;//10000000
System.out.println("位与运算"+(a&b));//位与运算时两者为1时才为1,否则为0 结果为 1000 0000=128
System.out.println("位或运算"+(a|b));//位或运算为两者有一个为1时则为1,否则为0,结果为 1000 0001=129
System.out.println("位非运算"+(~b));//位非运算,0转换成1,1转换成0,首先高位符号位从0转为1
//结果为1111 1111 1111 1111 1111 1111 1111 0111 1111 对这个数进行取反
//结果为1000 0000 0000 0000 0000 0000 0000 1000 0000
// 加1后结果 1000 0000 0000 0000 0000 0000 0000 1000 0001
//答案为-129
System.out.println("异或运算"+(a^b));//异或运算为两者都相同时则为0,否则为1 结果为 00000001=1

运行结果为:

位与运算=128 位或运算=129 位非运算=-129 异或运算=1


下面对符号左移,符号右移,无符号右移进行描述(java中没有无符号左移)

负数右移时左边补1,正数右移时左边补0,无符号右移时无论是正数还是负数均左边补0。

int c=128;//1000 0000
int d=4;
System.out.println("符号右移="+(c>>d));
//右移四位相当于除以2的4次方,相当于128/16=8,实际上为1000 0000
//               0000 0000 0000 0000 0000 0000 1000 0000
//右移四位结果为  0000 0000 0000 0000 0000 0000 0000 1000  结果为8
System.out.println("符号左移="+(c<<d));
//左移四位相当于乘上2的4次方,相当于128*16=2048
//              0000 0000 0000 0000 0000 0000 1000 0000
//左移四位结果为 0000 0000 0000 0000 0000 1000 0000 0000=2的11次方=2048
System.out.println("无符号右移="+(c>>>d));
//右移四位相当于除以2的4次方,相当于128/16=8,实际上为1000 0000
//               0000 0000 0000 0000 0000 0000 1000 0000
//右移四位结果为  0000 0000 0000 0000 0000 0000 0000 1000  结果为8

得到结果为

符号右移=8 符号左移=2048 无符号右移=8

下面对负数进行右移左移及无符号右移进行计算

int m=-128;
int n=4;
System.out.println("符号右移="+(m>>n));
// 1000 0000 0000 0000 0000 0000 1000 0000  -128的原码
// 1111 1111 1111 1111 1111 1111 0111 1111  -128的反码
// 1111 1111 1111 1111 1111 1111 1000 0000  -128的补码
// 1111 1111 1111 1111 1111 1111 1111 1000  负数右移时左边补1,正数右移时左边补0,这里重新取补码得到答案
// 1000 0000 0000 0000 0000 0000 0000 0111  取反得
// 1000 0000 0000 0000 0000 0000 0000 1000  取补得结果为-8
System.out.println("符号左移="+(m<<n));
// 1111 1111 1111 1111 1111 1111 1000 0000  -128的补码
// 1111 1111 1111 1111 1111 1000 0000 0000  左移时右边补0,符号位不变
// 1000 0000 0000 0000 0000 0111 1111 1111  取反时符号位不变
// 1000 0000 0000 0000 0000 1000 0000 0000  取补码为 -2048
System.out.println("无符号右移="+(m>>>n));
//无符号右移时左侧只补0
//1111 1111 1111 1111 1111 1111 1000 0000  -128的补码
//0000 1111 1111 1111 1111 1111 1111 1000  直接得出答案

符号右移=-8 符号左移=-2048 无符号右移=268435448

这里要重点重新强调一下,正数的 原码,反码和补码全部相同。


假如右移的是负数位的情况也有 在java中对int型的右移则是让这个负数位和0b11111进行位与运算,对long类型的则是和0b111111进行位与运算 这里参考于:Chapter 15. Expressions

If the promoted type of the left-hand operand is int, then only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.

If the promoted type of the left-hand operand is long, then only the six lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x3f (0b111111). The shift distance actually used is therefore always in the range 0 to 63, inclusive.


int k=2048;
int l=-30;
System.out.println(k>>l);

//位移负数位
//题目效果为 2048>>(-30&0b11111)
//-30的原码为1000 0000 0000 0000 0000 0000 0001 1110
//-30的反码为1111 1111 1111 1111 1111 1111 1110 0001
//-30的补码为1111 1111 1111 1111 1111 1111 1110 0010  
//           0000 0000 0000 0000 0000 0000 0001 1111  int型取后5位,long型后6位均为1
//           0000 0000 0000 0000 0000 0000 0000 0010  进行位与运算后得到结果为2
//上面相当于效果为2048 右移两位 得到答案为 512

最终结果得到为512