原来位运算还可以这样牛逼!深入了解位运算

位运算的种类

在进行位运算的时候要把数据转换成二进制位,并且全部都是补码的形式。

前面文章讲过怎么将十进制二进制互转 https://mp.weixin.qq.com/s/o-ddNSI2GvFktbmtfZ5W7w

  • **按位与 & :**两个同为1的时候才为1,否则为0

    3 & 4 = ?

    首先将3转换成二进制数:11,补码形式:0b00000000000000000000000000000011(int占4个字节,一个字节=8位,共32位)

    再将4转换成二进制数:100,补码形式:0b00000000000000000000000000000100(共32位)

    那么 3&4 = 0b00000000000000000000000000000000 = 0

  • **按位或 | :**两个中只要有一个为1,结果就为1

    3 | 4 = ?

    首先将3转换成二进制数:11,补码形式:0b00000000000000000000000000000011(共32位)

    再将4转换成二进制数:100,补码形式:0b00000000000000000000000000000100(共32位)

    那么 3|4 = 0b00000000000000000000000000000111 = 7

  • **按位异或 ^:**两个不一样的时候才为1,一样则为0

    3 ^ 4 = ?

    首先将3转换成二进制数:11,补码形式:0b00000000000000000000000000000011(共32位)

    再将4转换成二进制数:100,补码形式:0b00000000000000000000000000000100(共32位)

    那么 3^4 = 0b00000000000000000000000000000111 = 7

  • **按位取反 ~ :**1变0,0变1

    ~3 = ?

    首先将3转换成二进制数:11,补码形式:0b00000000000000000000000000000011(共32位)

    取反后的结果:0b11111111111111111111111111111100(补码 负数)

    补码:原码取反+1

    通过补码求原码:补码 - 1 --> 取反(取反的过程中符号位不变,也就是b后面的一位)

    0b11111111111111111111111111111100减1 = 0b11111111111111111111111111111011

    0b11111111111111111111111111111011取反:0b10000000000000000000000000000100 = -4

  • **左移 << :**让操作数乘以2的n次幂 n就是移动的位数

    3 << 2 = ?

    3 << 2 = 3 ∗ 2 2 3*2^2 322 = 12

    那计算机底层是如何计算的呢?

    3的二进制位:00000000000000000000000000000011,左移两位: 00000000000000000000000000001100 = 12

  • **右移 >> :**让操作数除以2的n次幂 n就是移动的位数

    32 >> 2 = ?

    32 >> 2 = 32 / 2 2 32 / 2^2 32/22 = 8

    32的二进制位:00000000000000000000000000100000,右移两位:00000000000000000000000000001000 = 8(如果符号位是1,那么左边就用1补充,符号位是0就用0补充)

    -32 >> 2 = ?

    -32的二进制位:(位运算都是针对补码进行操作的

    ​ 原码:10000000000000000000000000100000

    ​ 反码:11111111111111111111111111011111

    ​ 补码:11111111111111111111111111100000(补码 = 反码 + 1)

    ​ -32向右移动2位:11111111111111111111111111111000 (补码)

    ​ 根据补码求原码:(反码 = 补码 - 1)

    ​ 11111111111111111111111111111000 - 1 = 11111111111111111111111111110111

    ​ 原码:11111111111111111111111111110111取反 = 10000000000000000000000000001000 = -8

  • **无符号右移 >>> :**让操作数除以2的n次幂 n就是移动的位数

    无符号右移与右移的区别:

    ​ 有符号右移:右边的末位被挤掉,左边用符号位的数字补充

    ​ 无符号右移:右边的末位被挤掉,左边用0补充

    -32 >> 2 = 8

    音频、视频…属于无符号数据。

应用

  • 按位与 & 的应用

    • 判断一个数是奇数还是偶数

      if(n & 1 == 1){
          // n 是个奇数。
      }
      

      1的二进制数是1,按位与的作用是两边都是1的时候才会返回1,假设n=6

      那么6的二进制表示为:0b00000000000000000000000000000110

      1的二进制表示为:0b00000000000000000000000000000001

      n & 1 = 0,所以n是偶数。

      也就是只判断n的最末一位,如果是1则是奇数,0是偶数。

  • 异或 ^ 的应用

    • 一个数据对相同的两个数据异或两次,其值不变。一般应用在加密上。

      a ^ b ^ b = a

      其中b可以用作秘钥,客户端对a进行异或操作后传给服务端,服务端把这个值再进行异或后得到原始值。

    • 实现两个值的交换

      int x = 10;
      int y = 20;
      
      x = x ^ y;
      y = x ^ y; // 变量替换 y = (x ^ y) ^ y (前面讲过一个数据对相同的两个数据异或两次值不变,那么y = x)
      x = x ^ y; // 变量替换 x = x ^ (x ^ y) 那么x = y
      

面试

  • int型变量在内存中是如何存储的?

    因为int占4个字节,每个字节占二进制的8位,一共对应二进制的32位,如十进制的数字7,对应二进制应该是:

    0b00000000000000000000000000000111(0b表示二进制数)

  • int的取值范围是如何确定的?

    如十进制的数字7,对应二进制应该是:0b00000000000000000000000000000111,最左边的第一位(b后面的第一位)表示符号位(0正数 1负数),从第二位开始直到最后一位表示数值位,所以int的取值为-2的31次幂 到 2的31次幂

  • 为什么int的取值范围不是-2的32次幂 到 2的32次幂?

    因为int的二进制位一共是32位,其中第一位表示符号位,其余的31位才表示数值位。

  • 如果0b00000000000000000000000000000111表示十进制的数字7,那0b10000000000000000000000000000111表示为十进制的数字-7吗?为什么?

    不是。计算机中存储有符号数的时候是按照补码的形式存进去的。

    0b10000000000000000000000000000111不是二进制的补码,而是二进制的源码。

    计算机中所有的有符号数据都是按照补码形式存储的。

    正数的原码、反码、补码都一样。

    负数的原码、反码、补码不一样。

  • 什么是原码、反码、补码?

    原码:符号位+数值位

    反码:除符号位不变,其他位(数值位)全部1变0,0变1

    补码:在反码的基础上加1

  • 7 和 -7 的原码、反码、补码分别怎么表示?

    • 7的原码、反码、补码

      原码:0b10000000000000000000000000000111

      反码:0b10000000000000000000000000000111

      补码:0b10000000000000000000000000000111

    • -7的原码、反码、补码

      原码: 0b10000000000000000000000000000111

      反码:0b11111111111111111111111111111000

      补码:0b11111111111111111111111111111001

  • 0b11111111111111111111111111111001的原码是什么?

    根据补码求原码:

    1. 根据补码减1得到反码
    2. 根据反码取反得到原码

    反码 = 补码0b11111111111111111111111111111001 - 1

    ​ = 0b11111111111111111111111111111000;

    原码 = 反码取反0b11111111111111111111111111111000

    ​ = 0b10000000000000000000000000000111;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YoungJ5788

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值