算法通关村——位运算的操作规则和常见技巧

数值在计算机中的表示

机器数 一个数在计算机中的二进制表示形式,叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号,正数为0,负数为1。比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。这里的 00000011 和 10000011 就是机器数。

真值 因为机器数第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131)。所以,为了好区别,将带符号位的机器数对应的真正数值称为机器数的真值。例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1。

而 原码, 反码,补码就是对机器数的进一步的细化

原码、反码和补码是计算机中用于表示有符号整数的三种常见方式。它们在数字的表示和运算中具有重要作用。

  1. 原码(Sign-Magnitude Representation):

    • 原码是最基本的有符号整数表示方法,其中最高位表示符号(0 表示正数,1 表示负数),其余位表示数字的绝对值。
    • 例如,用 8 位表示 +3 和 -3 的原码分别为:00000011(+3)和 10000011(-3)。
  2. 反码(One’s Complement Representation):

    • 反码是在原码的基础上,对负数的绝对值按位取反得到的。
    • 例如,-3 的反码为 11111100。
  3. 补码(Two’s Complement Representation):

    • 补码是在反码的基础上,再加 1 得到的。
    • 补码的优势是可以通过简单的加法来实现减法运算,且没有正零和负零的区别。
    • 例如,-3 的补码为 11111101。

综合举例说明这三种表示方式:
用 8 位表示整数,即一个字节的大小。

  • 原码:+3 表示为 00000011,-3 表示为 10000011。
  • 反码:+3 的反码为 00000011,-3 的反码为 11111100。
  • 补码:+3 的补码为 00000011,-3 的补码为 11111101。

需要注意的是,原码、反码和补码之间的转换是常用的操作,计算机在进行有符号整数的加减法等运算时会根据实际情况进行相应的转换和处理。补码表示方式在计算机中得到广泛应用,因为它能够更方便地进行运算,并且能够避免正负零的区别。

位运算规则

与、或、异或、取反

当我们使用二进制中的位运算操作(与、或、异或、取反),实际上是对二进制位逐位进行操作。

假设我们有两个二进制数:A = 1100(12)和 B = 1010(10)。

  1. 与运算(&):

    • A & B:1100 AND 1010 = 1000(8)
    • 对应的位逐位比较:1 & 1 = 1,1 & 0 = 0,0 & 1 = 0,0 & 0 = 0。
  2. 或运算(|):

    • A | B:1100 OR 1010 = 1110(14)
    • 对应的位逐位比较:1 | 1 = 1,1 | 0 = 1,0 | 1 = 1,0 | 0 = 0。
  3. 异或运算 ⊕(在代码中用∧ 表示异或):

    • A ⊕ B:1100 ⊕ 1010 = 0110(6)
    • 对应的位逐位比较:1 ⊕ 1 = 0,1 ⊕ 0 = 1,0 ⊕ 1 = 1,0 ⊕ 0 = 0。
  4. 取反运算(~):

    • ~ A:~ 1100 = 0011(3)
    • 对应的位逐位取反:1 变为 0,0 变为 1。

移位运算

>> 右移
在 Java 中右移有两种:算数右移、逻辑右移

  • 逻辑右移:高位补 0
  • 算数右移:高位补最高位

实例

int num = 12;  // 二进制表示为 0000 1100
int result = num >> 2;  // 右移2位
// 结果:0000 0011,十进制为 3
int num = -12;  // 二进制表示为 1111 0100
int result = num >> 2;  // 右移2位
// 结果:1111 1101,十进制为 -3

<< 左移

高位舍弃低位补 0

实例:

int num = 5;  // 二进制表示为 0000 0101
int result = num << 2;  // 左移2位
// 结果:0001 0100,十进制为 20

位运算常用技巧

获取、更新或者设置都有对应的固定的套路

获取

    /**
     * 获取对应方法
     * 如果是 1 返回 true
     * 如果是 0 返回 false
     *
     * @param num
     * @param i
     * @return
     */
    public boolean getBit(int num, int i) {
        return (num & (1 << i)) != 0;
    }

设置

设置方法,这将会将第 i 位置为 1

    /**
     * 设置数据,将第 i 位设置成 1 
     *
     * @param num
     * @param i
     * @return
     */
    public int setBit(int num, int i) {
        return num | (1 << i);
    }

清零方法,将第 i 位设置成 0

    /**
     * 清空数据,把第 i 位设置成 0 
     * 
     * @param num
     * @param i
     * @return
     */
    public int clearBit(int num, int i) {
        int mask = ~(1 << i);
        return num | mask;
    }

更新

这个是 setBit 和 clearBit 合二为一

这里是先把 num 的第 i 位置上的值变成 0 (不管之前是不是 0),让后再把 v 向做移动 i 位,和操作之后的 num 进行 | 操作进行跟新数据

    /**
     * 更新对应 i 位置的值变成 v
     *
     * @param num 对应的值
     * @param i   跟新帝第几位
     * @param v   要跟新的值
     * @return
     */
    public int updateBit(int num, int i, int v) {
        int mask = ~(1 << i);
        return (num & mask) | (v << i);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值