计算机中的位运算(以Java为例)

计算机中的位运算(以Java为例)


最近在学Java基础,遇到位运算,顺便写了篇文章,顺手发了出来,也让自己多了一分理解吧


一、前置知识

  1. 当我们谈论一个二进制数的时候,首先要明确它的位数,比如二进制:11111000,如果是一个16位数(或更大),则表示的十进制数是:248;如果是一个8位数,则表示的十进制数为-8
  2. 二进制的最高位是符号位:0表示正数,1表示负数
  3. 计算机运算的时候用的是补码,我们人看一个数的时候,原码是最方便我们理解的
  4. 正数的原码,反码,补码都一样(三码合一)
  5. 负数的反码=除符号位外,其它位取反
  6. 负数的补码=它的反码+1
  7. 0的反码、补码都是0

二、位运算符(以Java为例)

  1. &:按位与:相对应的位,两个都为1,结果为1,否则为0
  2. |:按位或:相对应的位,两个中有一个为1,结果为1,否则为0
  3. ^:按位异或:相对应的位,两个不一样,结果为1,否则为0
  4. ~:按位取反:相应位,0变1,1变0
  5. >>:算术右移:低位溢出,高位补符号位
  6. <<:算术左移:高位溢出,低位补0
  7. >>>:无符号右移:低位溢出,高位补0
    注意:Java中没有无符号左移

三、举例说明

以下都以32位数为例
如果运算结果首位为1,则为负数,需要转化成原码之后我们才能看出来
如果运算结果首位为0,则为正数,不需要转换

1.&:按位与

    @Test
    public void test01() {
        /*
        &规则:相对应的位,两个都为1则为1,否则为0
		3 & 5
        3    00000000000000000000000000000011
        5    00000000000000000000000000000101
        3 & 5 运算结果:
        三码合一
             00000000000000000000000000000001  => 1
         */
        System.out.println("3 & 5 = " + (3 & 5));
        /*
        3 & -5
         3    00000000000000000000000000000011
        -5    11111111111111111111111111111011
        3 & -5 运算结果:
        三码合一
              00000000000000000000000000000011  => 3
         */
        System.out.println("3 & -5 = " + (3 & -5));
        /*
        -3 & -5
        -3    11111111111111111111111111111101
        -5    11111111111111111111111111111011
        -3 & -5 运算结果:
        补码  11111111111111111111111111111001
        反码  11111111111111111111111111111000
        原码  10000000000000000000000000000111  => -7
         */
        System.out.println("-3 & -5 = " + (-3 & -5));
    }

输出结果:

3 & 5 = 1
3 & -5 = 3
-3 & -5 = -7

2. |:按位或

    @Test
    public void test02() {
        /*
        | 规则:相对应的位,两个有一个为1则为1,否则为0

        3 | 5
        3    00000000000000000000000000000011
        5    00000000000000000000000000000101
        3 | 5 运算结果:
        三码合一
             00000000000000000000000000000111  => 7
         */
        System.out.println("3 | 5 = " + (3 | 5));
        /*
        3 | -5
         3    00000000000000000000000000000011
        -5    11111111111111111111111111111011
        3 | -5 运算结果:
        补码  11111111111111111111111111111011
        反码  11111111111111111111111111111010
        原码  10000000000000000000000000000101  => -5
         */
        System.out.println("3 | -5 = " + (3 | -5));
        /*
        -3 | -5
        -3    11111111111111111111111111111101
        -5    11111111111111111111111111111011
        -3 | -5 运算结果:
        补码  11111111111111111111111111111111 (这里可以看出是-1)
        反码  11111111111111111111111111111110
        原码  10000000000000000000000000000001  => -1
         */
        System.out.println("-3 | -5 = " + (-3 | -5));
    }

输出结果:

3 | 5 = 7
3 | -5 = -5
-3 | -5 = -1


3.^:按位异或

    @Test
    public void test03() {
        /*
        ^ 规则:相对应的位,不同为1,相同为0

        3 ^ 5
        3    00000000000000000000000000000011
        5    00000000000000000000000000000101
        ^运算结果:
        三码合一
             00000000000000000000000000000110  => 6
         */
        System.out.println("3 ^ 5 = " + (3 ^ 5));
        /*
        3 ^ -5
         3    00000000000000000000000000000011
        -5    11111111111111111111111111111011
        ^运算结果:
        补码  11111111111111111111111111111000
        反码  11111111111111111111111111110111
        原码  10000000000000000000000000001000  => -8
         */
        System.out.println("3 ^ -5 = " + (3 ^ -5));
        /*
        -3 ^ -5
        -3    11111111111111111111111111111101
        -5    11111111111111111111111111111011
        ^运算结果:
        三码合一
              00000000000000000000000000000110  => 6
         */
        System.out.println("-3 ^ -5 = " + (-3 ^ -5));
    }

输出结果:

3 ^ 5 = 6
3 ^ -5 = -8
-3 ^ -5 = 6

4.~:按位取反

    @Test
    public void test04() {
        /*
        ~ 规则,相应的位,1变0,0变1

        ~3
        3    00000000000000000000000000000011
        ~运算结果:
        补码  11111111111111111111111111111100
        反码  11111111111111111111111111111011
        原码  10000000000000000000000000000100  => -4
         */
        System.out.println("~3 = " + (~3));
        /*
        ~-5
        -5    11111111111111111111111111111011
        ~运算结果:
        三码合一
              00000000000000000000000000000100  => 4
         */
        System.out.println("~-5 = " + (~-5));
        /*
        顺便提一下,这里有个规律:~3+1=-3,~-3+1=3
        但是此规则不适用于下边界
         */
        System.out.println("~3 + 1 = " + (~3 + 1));
        System.out.println("~-3 + 1 = " + (~-3 + 1));
    }

输出结果:

~3 = -4
~-5 = 4
~3 + 1 = -3
~-3 + 1 = 3

5.>>:算术右移

    @Test
    public void test05() {

        /*
        >> 规则:低位溢出,高位补符号位
        在一定范围内,相当于右移1位就除以2,如果是奇数,则相当于加1除以2
        如果超出这个范围,原数是正数,则最终得到的值是0;原数是负数,则最终得到的值是-1

        32    00000000000000000000000000100000
        32 >> 2 运算结果:
        三码合一
              00000000000000000000000000001000  => 8 相当于32除以(2^2)
        32 >> 6 运算结果:
        三码合一
              00000000000000000000000000000000  => 0 只要位数超过5,结果都为0
         */
        System.out.println("32 >> 2 = " + (32 >> 2));
        System.out.println("32 >> 5 = " + (32 >> 5));
        System.out.println("32 >> 6 = " + (32 >> 6));
         /*
        -32 >> 2
        -32    11111111111111111111111111100000
        -32 >> 2 运算结果:
        补码   11111111111111111111111111111000
        反码   11111111111111111111111111110111
        原码   10000000000000000000000000001000 => -8 相当于-32除以(2^2)
        -32 >> 5 运算结果:
        补码   11111111111111111111111111111111  只要位数大于等于5,结果都是这个,即-1
        反码   11111111111111111111111111111110
        原码   10000000000000000000000000000001 => -1
         */
        System.out.println("-32 >> 2 = " + (-32 >> 2));
        System.out.println("-32 >> 5 = " + (-32 >> 5));
        System.out.println("-32 >> 6 = " + (-32 >> 6));
    }

输出结果:

32 >> 2 = 8
32 >> 5 = 1
32 >> 6 = 0
-32 >> 2 = -8
-32 >> 5 = -1
-32 >> 6 = -1

6.<<:算术左移

    @Test
    public void test06() {
        /*
        << 规则:高位溢出,低位补0
        在一定范围内,相当于左移1位就乘以2
        如果超出这个范围,则最终得到的值会是0

        32    00000000000000000000000000100000
        32 << 2 运算结果:
        三码合一
              00000000000000000000000010000000  => 128 相当于32乘以(2^2)
        32 << 25 运算结果:
        三码合一
              01000000000000000000000000000000  => 1073741824 相当于32乘以(2^25)
        32 << 26 运算结果:
        补码: 10000000000000000000000000000000  => 刚好是int的最小范围 -2147483648
        32 << 27 运算结果:
              00000000000000000000000000000000  => 0
         */
        System.out.println("32 << 2 = " + (32 << 2));
        System.out.println("32 << 25 = " + (32 << 25));
        System.out.println("32 << 26 = " + (32 << 26));
        System.out.println("Integer.MIN_VALUE="+Integer.MIN_VALUE);
        System.out.println("32 << 27 = " + (32 << 27));
        System.out.println("32 << 28 = " + (32 << 28));
        /*
        -32    11111111111111111111111111100000
        -32 << 2 运算结果:
        补码:  11111111111111111111111110000000
        反码:  11111111111111111111111101111111
        原码:  10000000000000000000000010000000 => -128  相当于-32乘以(2^2)
        -32 << 26 运算结果:
        补码:  10000000000000000000000000000000 => 刚好是int的最小范围 -2147483648 相当于32乘以(2^25)
        -32 << 27 运算结果:
                00000000000000000000000000000000 => 0
         */
        System.out.println("-32 << 2 = " + (-32 << 2));
        System.out.println("-32 << 26 = " + (-32 << 26));
        System.out.println("-32 << 27 = " + (-32 << 27));
        System.out.println("-32 << 28 = " + (-32 << 28));
    }

输出结果:

32 << 2 = 128
32 << 25 = 1073741824
32 << 26 = -2147483648
Integer.MIN_VALUE=-2147483648
32 << 27 = 0
32 << 28 = 0
-32 << 2 = -128
-32 << 26 = -2147483648
-32 << 27 = 0
-32 << 28 = 0

7.>>>:无符号右移

    @Test
    @Test
    public void test07() {
        /*
        >>> 规则:低位溢出,高位补0,
        Java中的处理方式:对于int类型的数而言,是移动 %32 位,也就是说 >>>2于 >>>34是一样的

        32 >>> 2
        32    00000000000000000000000000100000
        32 >>> 2 运算结果:
        三码合一
              00000000000000000000000000001000  => 8 相当于32除以(2^2)
        32 >>> 6 运算结果:
        三码合一
              00000000000000000000000000000000  => 0 只要 %32之后,位数超过5,结果都为0
         */
        System.out.println("32 >>> 2 = " + (32 >>> 2));
        System.out.println("32 >>> 34 = " + (32 >>> 34));
        System.out.println("32 >>> 5 = " + (32 >>> 5));
        System.out.println("32 >>> 6 = " + (32 >>> 6));

         /*
        -32 >>> 2
        -32    11111111111111111111111111100000
        -32 >>> 2 运算结果:
        补码   00111111111111111111111111111000
        反码   00111111111111111111111111110111
        原码   01000000000000000000000000001000 => 1073741816
        -32 >>> 31 运算结果:
        三码合一
              00000000000000000000000000000001 => 1
        -32 >>> 32 (-32 >>> 0)运算结果:-32
        -32 >>> 34 (-32 >>> 2)
         */
        System.out.println("-32 >>> 2 = " + (-32 >>> 2));
        System.out.println("-32 >>> 31 = " + (-32 >>> 31));
        System.out.println("-32 >>> 32 = " + (-32 >>> 32));
        System.out.println("-32 >>> 34 = " + (-32 >>> 34));
    }

输出结果:

32 >>> 2 = 8
32 >>> 34 = 8
32 >>> 5 = 1
32 >>> 6 = 0
-32 >>> 2 = 1073741816
-32 >>> 31 = 1
-32 >>> 32 = -32
-32 >>> 34 = 1073741816


如有不妥之处,请不吝指出,万分感谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值