BruceOuyang / issuelist

用于记录日常碰到的各种问题和经验总结 (请看Issues)
4 stars 2 forks source link

位运算基础示例 - java #114

Open BruceOuyang opened 2 years ago

BruceOuyang commented 2 years ago

零、基本数据类型

基本类型 字节数 位数 最大值 最小值
byte 1byte 8bit 2^7 - 1 -2^7
short 2byte 16bit 2^15 - 1 -2^15
int 4byte 32bit 2^31 - 1 -2^31
long 8byte 64bit 2^63 - 1 -2^63
float 4byte 32bit 3.4028235E38 1.4E - 45
double 8byte 64bit 1.7976931348623157E308 4.9E - 324
char 2byte 16bit 2^16 - 1 0

对于所有的位运算,操作的都是二进制的数据,如果数据为其他进制,会先转换为二进制再做计算 一个整型数据占 4 字节,每个字节占 8 位,等于一个整型数据占 32 位 低精度的 byte / short 不适合做位运算,会有溢出,一般位运算基础类型为 int / long

一、位逻辑运算

与运算,对应位都为 1,结果为 1,否则为 0 相当于一般逻辑运算符 and ,把 1 视为 true, 把 0 视为 false

12 & 8 = 8

      0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式
 &    0000 0000 0000 0000 0000 0000 0000 1000      -> 十进制 8 的二进制形式
———————————————————————————————————————————————
      0000 0000 0000 0000 0000 0000 0000 1000

或运算,对应位含有 1,结果为 1,否则为 0 相当于一般逻辑运算符 or ,把 1 视为 true, 把 0 视为 false

12 | 8 = 12

      0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式
 |    0000 0000 0000 0000 0000 0000 0000 1000      -> 十进制 8 的二进制形式
———————————————————————————————————————————————
      0000 0000 0000 0000 0000 0000 0000 1100

取反运算,对应位为 1,结果为 0,否则为 1 相当于一般逻辑运算符 ! ,把 1 视为 true, 把 0 视为 false

~12 = -13

 ~    0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式
———————————————————————————————————————————————
      1111 1111 1111 1111 1111 1111 1111 0011

异或运算,对应位值相同,结果为 0,否则为 1 相当于一般逻辑运算符 equals ,把 1 视为 true, 把 0 视为 false

12 ^ 8 = 4

      0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式
 ^    0000 0000 0000 0000 0000 0000 0000 1000      -> 十进制 8 的二进制形式
———————————————————————————————————————————————
      0000 0000 0000 0000 0000 0000 0000 0100

二、位移运算

左移运算,对应位整体向左移动 n 位,低位补 0, 高位溢出的舍去 相当于乘以 2 的 n 次方

12 << 2 = 48

 << 2     0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式
———————————————————————————————————————————————————————
          0000 0000 0000 0000 0000 0000 0011 0000

正数右移运算,对应位整体向右移动 n 位,高位补 0, 低位溢出的舍去 相当于除以 2 的 n 次方

12 >> 2 = 3

 >> 2     0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式
———————————————————————————————————————————————————————
          0000 0000 0000 0000 0000 0000 0000 0011

负数右移运算,对应位整体向右移动 n 位,高位补 1, 低位溢出的舍去

-12 >> 2 = -3

 >> 2     1111 1111 1111 1111 1111 1111 1111 0011      -> 十进制 -12 的二进制形式
———————————————————————————————————————————————————————
          1111 1111 1111 1111 1111 1111 1111 1100

无符号右移运算,对应位整体向右移动 n 位,高位补 0, 低位溢出的舍去 相当于除以 2 的 n 次方

12 >>> 2 = 3

 >>> 2    0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式
———————————————————————————————————————————————————————
          0000 0000 0000 0000 0000 0000 0000 0011

-12 >>> 2 = 1073741821

 >>> 2    1111 1111 1111 1111 1111 1111 1111 0011      -> 十进制 -12 的二进制形式
———————————————————————————————————————————————————————
          0011 1111 1111 1111 1111 1111 1111 1100

三、极端位移测试

左移运算,对应位整体向左移动 n 位,低位补 0, 高位溢出的舍去 若 n > 32, 相当于乘以 2 的 n % 32 次方

12 << 27 = 1610612736
12 << 30 = 0
12 << 32 = 12
12 << 33 = 24
12 << 64 = 12
12 << 96 = 12
          0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式

四、低精度整型位移运算

byte -32 >>> 1 = -16
short -128 >>> 1 = -64

低精度整形是不适合做位移操作的,会有溢出,因此,低精度的数据类型不适合用于位运算

扫码_搜索联合传播样式-标准色版

BruceOuyang commented 2 years ago

示例代码

/**
 * @ClassName: BitOperationTest
 *
 * @Description: 位运算测试
 *
 * @Author: bruce.ouyang
 * @Date: 2022/5/3 上午10:57
 * @Version: v1.0
 */
public class BitOperationTest {

    public static void main(String[] args) {

        System.out.println("对于所有的位运算,操作的都是二进制的数据,如果数据为其他进制,会先转换为二进制再做计算");
        System.out.println("一个整型数据占 4 字节,每个字节占 8 位,等于一个整型数据占 32 位");
        System.out.println("低精度的 byte / short 不适合做位运算,会有溢出,一般位运算基础类型为 int / long");
        System.out.println("");

        bitLogicOpTest();
        bitMoveOpTest();
        limitMoveBitTest();
        basicTypeBitTest();

//        checkMoveBitTest();
    }

    /**
     * 位逻辑运算
     * & 与       a & b
     * | 或       a | b
     * ~ 取反     ~a
     * ^ 异或     a ^ b
     */
    public static void bitLogicOpTest() {

        System.out.println("=========================================================");
        System.out.println("= 位逻辑运算");
        System.out.println("=========================================================");

        System.out.println("");
        System.out.println("- 与运算: a & b");
        System.out.println("");
        System.out.println("与运算,对应位都为 1,结果为 1,否则为 0");
        System.out.println("相当于一般逻辑运算符 and ,把 1 视为 true, 把 0 视为 false");
        System.out.println("");
        System.out.println("12 & 8 = " + (12 & 8));
        System.out.println("");
        System.out.println("      0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式");
        System.out.println(" &    0000 0000 0000 0000 0000 0000 0000 1000      -> 十进制 8 的二进制形式");
        System.out.println("———————————————————————————————————————————————");
        System.out.println("      0000 0000 0000 0000 0000 0000 0000 1000");
        System.out.println("");

        System.out.println("- 或运算: a | b");
        System.out.println("");
        System.out.println("或运算,对应位含有 1,结果为 1,否则为 0");
        System.out.println("相当于一般逻辑运算符 or ,把 1 视为 true, 把 0 视为 false");
        System.out.println("");
        System.out.println("12 | 8 = " + (12 | 8));
        System.out.println("");
        System.out.println("      0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式");
        System.out.println(" |    0000 0000 0000 0000 0000 0000 0000 1000      -> 十进制 8 的二进制形式");
        System.out.println("———————————————————————————————————————————————");
        System.out.println("      0000 0000 0000 0000 0000 0000 0000 1100");
        System.out.println("");

        System.out.println("- 取反运算: ~a");
        System.out.println("");
        System.out.println("取反运算,对应位为 1,结果为 0,否则为 1");
        System.out.println("相当于一般逻辑运算符 ! ,把 1 视为 true, 把 0 视为 false");
        System.out.println("");
        System.out.println("~12 = " + (~12));
        System.out.println("");
        System.out.println(" ~    0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式");
        System.out.println("———————————————————————————————————————————————");
        System.out.println("      1111 1111 1111 1111 1111 1111 1111 0011");
        System.out.println("");

        System.out.println("- 异或运算: a ^ b");
        System.out.println("");
        System.out.println("异或运算,对应位值相同,结果为 0,否则为 1");
        System.out.println("相当于一般逻辑运算符 equals ,把 1 视为 true, 把 0 视为 false");
        System.out.println("");
        System.out.println("12 ^ 8 = " + (12 ^ 8));
        System.out.println("");
        System.out.println("      0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式");
        System.out.println(" ^    0000 0000 0000 0000 0000 0000 0000 1000      -> 十进制 8 的二进制形式");
        System.out.println("———————————————————————————————————————————————");
        System.out.println("      0000 0000 0000 0000 0000 0000 0000 0100");
        System.out.println("");

    }

    /**
     * 位移运算
     * << 左移            a << 2
     * >> 右移            a >> 4
     * >>> 无符号右移      a >>> 2
     */
    public static void bitMoveOpTest() {

        System.out.println("=========================================================");
        System.out.println("= 位移运算");
        System.out.println("=========================================================");

        System.out.println("");
        System.out.println("- 左移运算: a << n");
        System.out.println("");
        System.out.println("左移运算,对应位整体向左移动 n 位,低位补 0, 高位溢出的舍去");
        System.out.println("相当于乘以 2 的 n 次方");
        System.out.println("");
        System.out.println("12 << 2 = " + (12 << 2));
        System.out.println("");
        System.out.println(" << 2     0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式");
        System.out.println("———————————————————————————————————————————————————————");
        System.out.println("          0000 0000 0000 0000 0000 0000 0011 0000");
        System.out.println("");

        System.out.println("");
        System.out.println("- 右移运算: a >> n");
        System.out.println("");
        System.out.println("正数右移运算,对应位整体向右移动 n 位,高位补 0, 低位溢出的舍去");
        System.out.println("相当于除以 2 的 n 次方");
        System.out.println("");
        System.out.println("12 >> 2 = " + (12 >> 2));
        System.out.println("");
        System.out.println(" >> 2     0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式");
        System.out.println("———————————————————————————————————————————————————————");
        System.out.println("          0000 0000 0000 0000 0000 0000 0000 0011");
        System.out.println("");
        System.out.println("负数右移运算,对应位整体向右移动 n 位,高位补 1, 低位溢出的舍去");
        System.out.println("");
        System.out.println("-12 >> 2 = " + (-12 >> 2));
        System.out.println("");
        System.out.println(" >> 2     1111 1111 1111 1111 1111 1111 1111 0011      -> 十进制 -12 的二进制形式");
        System.out.println("———————————————————————————————————————————————————————");
        System.out.println("          1111 1111 1111 1111 1111 1111 1111 1100");
        System.out.println("");

        System.out.println("");
        System.out.println("- 无符号右移运算: a >>> n");
        System.out.println("");
        System.out.println("无符号右移运算,对应位整体向右移动 n 位,高位补 0, 低位溢出的舍去");
        System.out.println("相当于除以 2 的 n 次方");
        System.out.println("");
        System.out.println("12 >>> 2 = " + (12 >>> 2));
        System.out.println("");
        System.out.println(" >>> 2    0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式");
        System.out.println("———————————————————————————————————————————————————————");
        System.out.println("          0000 0000 0000 0000 0000 0000 0000 0011");
        System.out.println("");
        System.out.println("");
        System.out.println("-12 >>> 2 = " + (-12 >>> 2));
        System.out.println("");
        System.out.println(" >>> 2    1111 1111 1111 1111 1111 1111 1111 0011      -> 十进制 -12 的二进制形式");
        System.out.println("———————————————————————————————————————————————————————");
        System.out.println("          0011 1111 1111 1111 1111 1111 1111 1100");
        System.out.println("");

    }

    public static void limitMoveBitTest() {

        System.out.println("=========================================================");
        System.out.println("= 极端位移测试");
        System.out.println("=========================================================");

        System.out.println("");
        System.out.println("- 左移运算: a << n, n > 32");
        System.out.println("");
        System.out.println("左移运算,对应位整体向左移动 n 位,低位补 0, 高位溢出的舍去");
        System.out.println("若 n > 32, 相当于乘以 2 的 n % 32 次方");
        System.out.println("");
        System.out.println("12 << 27 = " + (12 << 27));
        System.out.println("12 << 30 = " + (12 << 30));
        System.out.println("12 << 32 = " + (12 << 32));
        System.out.println("12 << 33 = " + (12 << 33));
        System.out.println("12 << 64 = " + (12 << 64));
        System.out.println("12 << 96 = " + (12 << 96));
        System.out.println("          0000 0000 0000 0000 0000 0000 0000 1100      -> 十进制 12 的二进制形式");
        System.out.println("");

    }

    public static void basicTypeBitTest() {

        System.out.println("=========================================================");
        System.out.println("= 低精度整型位移运算");
        System.out.println("=========================================================");

        System.out.println("");
        byte a = (byte) (-32 >>> 1);
        System.out.println("byte -32 >>> 1 = " +  a);

        short b = (short) (-128 >>> 1);
        System.out.println("short -128 >>> 1 = " + b);
        System.out.println("");

        System.out.println("低精度整形是不适合做位移操作的,会有溢出");
    }

    private static void checkMoveBitTest() {

        int a = 12;
        int count = 10;

        int v = a << count;

        int v_dynamic = v;

        int calc_count = 0;
        while((v_dynamic = v_dynamic >> 1) > 0) {
            calc_count ++;
            if (v_dynamic == a) {
                break;
            }
        }

        System.out.println(calc_count == count);

    }

}