首页 > 编程语言 > 详细

java 位操作

时间:2019-07-12 16:17:09      阅读:74      评论:0      收藏:0      [点我收藏+]

1、位操作运算符的种类:&(与)、|(或)、~(取反)、^(异或)、<<(左移)、>>(右移)、>>>(无符号右移)。

2、位运算符操作不会短路。

3、位运算符操作的是补码,所以~后正负号会发生变化。

4、位运算符只能用于整型。

其中移位运算符需要注意的地方:

三个移位运算符的相同点:当移位的位数超出数值的位数则会取模后再移位。

<<(左移):左移所操作数字的补码,二进制补码整体左移(包括符号位),溢出则舍弃,低位补0。这意味着正数在左移的过程中是可以变成负数的。以Java中int型作为测试,Java中int型为4个字节,所以移位的位数为0~31,用32作为测试。如下

public class Tests{
    public static void main(String[] args) {
        System.out.println(1<<32);  //结果为1
        System.out.println(8>>33);  //结果为4
        System.out.println(8>>>33);  //结果为4
System.out.println(1<<31);  //结果为-2147483648 } }

由运行结果运行结果可以看出,对32进行了模运算。

但是如果我们一次不进行过长的移位就不会进行模运算,做如下测试

public class Tests{
    public static void main(String[] args) {
        int x = 1<<31;
        int y = 1<<31;
        System.out.println(x);  //输出为-2147483648
        x = x<<31;
        System.out.println(x);  //输出为0
        y = y<<1;
        System.out.println(y);  //输出为0
    }
}

有上面的测试可以验证上述的点。左移操作是没有符号位一说的,直接对补码的整体进行操作。所以也就没有无符号左移<<<这样的运算符。

>>(右移或者说是 有符号右移):右移所操作数字的补码,二进制补码整体右移(包括符号位),舍弃右侧多出部分,高位补符号位。即相当于正数高位补0,负数高位补1。这样的操作对于负数来说,会让二进制数中的1的个数持续增多。但是得到的值是正确的。以整数-1来说。作如下测试。

public class Tests{
    public static void main(String[] args) {
        int x=-1;
        for(int i=0; i<10; i++){
            System.out.println(x>>1);  //输出永远是-1;
        }
    }
}

在这个测试中-1所对应的原码为 ,为方便查看简单到8位,-1的原码为1000 0001 补码为1111 1111 所以无论移动多少次,其结果永远是-1。进一步可以以-8作为一个测试。一下完整的32位的-8、-4、-2、-1的原码和补码

-8原码:1000 0000 0000 0000 0000 0000 0000 1000

-8补码:1111 1111 1111 1111 1111 1111 1111 1000

-4补码:1111 1111 1111 1111 1111 1111 1111 1100

-2补码:1111 1111 1111 1111 1111 1111 1111 1110

-1补码:1111 1111 1111 1111 1111 1111 1111 1111

由上述的内容我们可以看出,-8右移一位则除2,补码中的1会多一个。但结果正确。

>>>(无符号右移):右移做操作数字的补码,高位补0,低位超出则舍弃。由于高位补零,所以一个负数一旦移位则会变成正数。测试如下

public class Tests{
    public static void main(String[] args) {
        System.out.println(-1>>>1);  //结果为2147483647
    }
}

 一下为一些运用

统计十进制数对应的二进制中1的个数(统计的是补码)

public class Tests{
    public static void main(String[] args) {
        int sum = 0;
        int n = -8;
        do{
            sum += n&1;
        }while((n >>>= 1)!=0);
        System.out.println(sum);  //29  n取任何数
    }
}

还有一种

public class Tests{
    public static void main(String[] args) {
        int n = -8;
        int sum = 0;
        while(n != 0){
            sum++;
            n = n&(n-1);
        }
        System.out.println(sum);  //29  n取任何数
    }
}

下面这种方法对于正数很好理解,就是每次都取n-1的值,这样就会影响最低位的1及其更低位的值,影响的效果为取反,而高位不会影响。每次的循环都会利用&运算将低位的1去除。例如0111 1000,减一的值为0111 0111,&运算后为0111 0000。在负数的情况下,我们可以直接看补码的关系,1111 1000的补码为1000 1000,减一后(注意是负数加相反数)1111 1001的补码为1000 0111,直接看补码间的关系可以看出其实就是去掉符号位后,其余的值当作正数做减一运算与正数情况相同。

负数在变位补码时,只需要确定最低的一位1,比最低的1高的位依次求反(不包括最低位的1)。所以可以看作,在最低的一位1前的数会受影响。这里负数的减一即绝对值加1后,在变为补码,相当于从最低位就影响补码的值。这样可以认为,n(第一个1的高位取反)n-1(全部取反,相对于n)这样的&操作,会使n的最低位1及其更低位变成0。

异或交换元素值

public class Tests{
    public static void main(String[] args) {
        int a=2;
        int b=3;
        a = a^b;
        b = a^b;
        a = a^b;
        System.out.println(a+"   "+b);  //3  2
    }
}

快速幂

 

java 位操作

原文:https://www.cnblogs.com/ant-xu/p/11176170.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!