精华内容
下载资源
问答
  • JAVA 运算和实际应用 前言: ​ 作为一个有近8年 JAVA 开发经验的老程序员,再加上工作性质比较偏于项目管理,平时工作对于运算和二进制数的运算和应用比较少。偶尔看一些源码,对于出现的运算符总是一...

    JAVA 中的位运算和实际应用

    前言:

    ​ 作为一个有近8年 JAVA 开发经验的老程序员,再加上工作性质比较偏于项目管理,平时工作中对于位运算和二进制数的运算和应用比较少。偶尔看一些源码,对于出现的位运算符总是一脸懵逼,不得不再回炉重新温习一下,这篇文章记录一下自己的学习过程,加深印象。接下来就开始吧!

    1. 数学中的二进制

    ​ 先简单介绍下二进制,二进制是用0和1两个数码表示的数字,进位规则是“逢二进一”,借位规则是“借一当二”。程序员都知道,二进制在当代计算机中非常微小的开关,用*”开(true)“表示1,”关(false)“*表示0。二进制数据采用的位置计数法,其权位是以 2 为底的幂。

    1.1 二进制转十进制

    例1:二进制数 1101 与十进制转换:
    (1 x 2³) + (1 x 2²) + (0 x 2¹) + (1 x 2⁰) = 8 + 4 + 0 + 1 = 13
    例2:二进制数 111.01 与十进制转换:
    (1 x 2²) + (1 x 2¹) + (1 x 2⁰) + (0 x 2⁻¹) + (1 x 2⁻²) = 4 + 2 + 1 + 0 + 0.25 = 7.25

    浮点型的二进制数在Java中用的不多,后面就暂且不论

    1.2 十进制转二进制

    除以2取余,逆序排列 (除二取余法) 例:89 = 1011001

    十进制数/2 商(下次的被除数) 余数(二进制数)
    89 / 2 44 1
    44 / 2 22 0
    22 / 2 11 0
    11 / 2 5 1
    5 / 2 2 1
    2 / 2 1 0
    1 / 2 0 1

    以上表格中的余数倒过来,就是 89 对应的二进制数

    2. JAVA 中的二进制

    2.1 二进制转十进制

    ​ Java 中的二进制数是以 0b + 数字形式,b 大小写不限制,例如:0b101 表示二级制数 101,可以直接赋值到 十进制的 int 基本数据类型。常见表示方法有 int binary = 0b101;

    int binary = 0b101;
    System.out.println("0b101 = " + binary);
    //输出是:0b101 = 5 
    

    2.2 十进制转二进制

    ​ 通过 Integer 的整型包装类中的方法 toBinaryString 可以把十进制转换成二进制然后通过字符串输出。

    int i = 5;
    String binary = Integer.toBinaryString(i);
    System.out.println(i + " = " + binary);
    //输出是:5 = 101
    

    3. 位运算符

    ​ 位运算符用来对二进制位进行操作,Java 中提供了如下表所示的位运算符:位运算符中,除 ~ 以外,其余均为二元运算符。

    运算符 描述
    & 与,两个二进制数如果相对应位都是1,则结果为1,否则为0
    | 或,两个二进制数如果相对应位都是0,则结果为0,否则为1。
    ^ 异或,如果相对应位值相同,则结果为0,否则为1
    ~ 非(取反),按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 一元运算符
    >> 按位左移,左操作数按位左移右操作数指定的位数。
    >> 按位右移,左操作数按位右移右操作数指定的位数。
    >>> 无符号按位右移,左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。

    ​ 在计算机中位运算符比数学中常规的加减乘除效率高很多,对于一些追求效率的数据结构或者算法来说,掌握位运算符的用法会让程序员在开发过程中如虎添翼,但是目前来看用的真的不是很多,可能和可读性不高有关吧。总之希望读者看了这篇文章后能对位运算符能有所了解,更能实际运用到自己的项目或者工作中去。

    ​ Java 中位运算符只能针对整型,除long型外,其他类型会自动转成int型,转换之后再进行位运算。首先复习一下Java中基本数据类型,也叫 Java 的内置数据类型如下表:

    数据类型 大小 最小 最大
    boolean
    byte 8-bit - 128 + 127
    char 16-bit \u0000 \u65535
    short 16-bit -215 + 216 - 1
    int 32-bit -231 + 231 - 1
    long 64-bit -263 + 263 - 1
    float 32-bit IEEE 754 IEEE 754
    double 64-bit IEEE 754 IEEE 754

    ​ 以上基本数据类型除了boolean外对应二进制的位数在Java中可以通过他们的包装类型获取 如下:

    // byte
    System.out.println("基本类型:byte 二进制位数:" + Byte.SIZE);
    System.out.println("包装类:java.lang.Byte");
    System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE);
    System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE);
    System.out.println();
    
    // short
    System.out.println("基本类型:short 二进制位数:" + Short.SIZE);
    System.out.println("包装类:java.lang.Short");
    System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE);
    System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE);
    System.out.println();
    
    // int
    System.out.println("基本类型:int 二进制位数:" + Integer.SIZE);
    System.out.println("包装类:java.lang.Integer");
    System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE);
    System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE);
    System.out.println();
    
    // long
    System.out.println("基本类型:long 二进制位数:" + Long.SIZE);
    System.out.println("包装类:java.lang.Long");
    System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE);
    System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE);
    System.out.println();
    
    // float
    System.out.println("基本类型:float 二进制位数:" + Float.SIZE);
    System.out.println("包装类:java.lang.Float");
    System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE);
    System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE);
    System.out.println();
    
    // double
    System.out.println("基本类型:double 二进制位数:" + Double.SIZE);
    System.out.println("包装类:java.lang.Double");
    System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE);
    System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE);
    System.out.println();
    
    // char
    System.out.println("基本类型:char 二进制位数:" + Character.SIZE);
    System.out.println("包装类:java.lang.Character");
    // 以数值形式而不是字符形式将Character.MIN_VALUE输出到控制台
    System.out.println("最小值:Character.MIN_VALUE="
            + (int) Character.MIN_VALUE);
    // 以数值形式而不是字符形式将Character.MAX_VALUE输出到控制台
    System.out.println("最大值:Character.MAX_VALUE="
            + (int) Character.MAX_VALUE);
    
    //控制台输出如下
    基本类型:byte 二进制位数:8
    包装类:java.lang.Byte
    最小值:Byte.MIN_VALUE=-128
    最大值:Byte.MAX_VALUE=127
    
    基本类型:short 二进制位数:16
    包装类:java.lang.Short
    最小值:Short.MIN_VALUE=-32768
    最大值:Short.MAX_VALUE=32767
    
    基本类型:int 二进制位数:32
    包装类:java.lang.Integer
    最小值:Integer.MIN_VALUE=-2147483648
    最大值:Integer.MAX_VALUE=2147483647
    
    基本类型:long 二进制位数:64
    包装类:java.lang.Long
    最小值:Long.MIN_VALUE=-9223372036854775808
    最大值:Long.MAX_VALUE=9223372036854775807
    
    基本类型:float 二进制位数:32
    包装类:java.lang.Float
    最小值:Float.MIN_VALUE=1.4E-45
    最大值:Float.MAX_VALUE=3.4028235E38
    
    基本类型:double 二进制位数:64
    包装类:java.lang.Double
    最小值:Double.MIN_VALUE=4.9E-324
    最大值:Double.MAX_VALUE=1.7976931348623157E308
    
    基本类型:char 二进制位数:16
    包装类:java.lang.Character
    最小值:Character.MIN_VALUE=0
    最大值:Character.MAX_VALUE=65535
    

    ​ Float和Double的最小值和最大值都是以科学记数法的形式输出的,结尾的"E+数字"表示E之前的数字要乘以10的多少次方。比如3.14E3就是3.14 × 103 =3140,3.14E-3 就是 3.14 x 10-3 =0.00314。实际上,JAVA中还存在另外一种基本类型 void,它也有对应的包装类 java.lang.Void,不过我们无法直接对它们进行操作。

    ​ 以下我们主要讲intlong类型的位运算,位运算通过对二进制位的操作来快速达到运算目的(因为计算机底层的存储就是按照二进制结构的)比如 int 型的变量占用了32-bit,在计算机中占用 4-byte,每个byte为8字节前面我们说到了 89 = 1011001 可以用以下方式表示

    ​ Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节型(byte)等类型。位运算符作用在所有的位上,并按位运算。假设a = 60,b = 13; 我们来看看各种位运算之后的运算结果。

    3.1 & 与运算

    &(与),两个二进制数如果相对应位都是1,则结果为1,否则为0。例如:60 & 13 = 12 60 的二进制数是 111100,13的二进制数是 1101 以32位bit位计算,剩余位数补0,对于每个位上的操作,进行And比较,如果都是1则结果的相应位也是1,否则是0。 图示如下:

    Java代码:

    int a = 60;
    int b = 13;
    System.out.println(Integer.toBinaryString(a));
    System.out.println(Integer.toBinaryString(b));
    System.out.println("60 & 13 = " + (a & b));
    
    //控制台输出如下:
    111100
    1101
    二进制 60 & 13 = 1100
    十进制 60 & 13 = 12
    

    实际应用:判断奇偶数

    判断奇偶数:假如存在 a & 1 结果为 0 ,a 就是偶数。a & 1结果为 1 ,a 就是奇数。
    我们知道,二进制数有 逢二进一 的规则,那么凡是偶数,第一位必然是 0 ,奇数第一位必然是 1。通过例子我们也知道 & 运算是两个二进制数的运算,相应位都是1则结果的相应位也是1,对于1来说,第一位是1,其它位都是0。那么任何二进制奇数 & 1,只有第一位满足都是1,所以第一位是1,其它位都是0。如果该二进制数为偶数,如果该二进制数是偶数,则第一位是0,所以 & 1 后,所有位都为 0,我们看下下图就一目了然:

    Java 代码:

    int a = 60;
    int b = 13;
    System.out.println(" 60 & 1 = " + (a & 1));
    System.out.println(" 13 & 1 = " + (b & 1));
    //输出如下:
    60 & 1 = 0   //偶数
    13 & 1 = 1   //奇数
    

    3.2 | 或运算

    |(或),两个二进制数如果相对应位都是0,则结果为0,否则为1。其实很好理解,或运算正好对与运算,和我们的逻辑运算符 && 和 || 非常像,我们想象 1 = true,0 = false 。 对于与运算符,需要都为true则true,对于或运算符,只要1个为true则true。图示如下:

    Java代码:

    int a = 60;
    int b = 13;
    System.out.println(Integer.toBinaryString(a));
    System.out.println(Integer.toBinaryString(b));
    System.out.println("二进制 60 | 13 = " + Integer.toBinaryString(a | b));
    System.out.println("十进制 60 | 13 = " + (a | b));
    
    //输出
    111100
    1101
    二进制 60 | 13 = 111101
    十进制 60 | 13 = 61
    

    3.3 ^ 异或运算符

    ^(异或),如果相对应位值相同,则结果为0,否则为1。这次和前面不同了,相当于逻辑运算符中的 == 和 != 区别是异或运算 == 的话是false ,!= 的话是true,继续撕图:

    Java 代码

    int a = 60;
    int b = 13;
    System.out.println(Integer.toBinaryString(a));
    System.out.println(Integer.toBinaryString(b));
    System.out.println("二进制 60 ^ 13 = " + Integer.toBinaryString(a ^ b));
    System.out.println("十进制 60 ^ 13 = " + (a ^ b));
    
    //输出:
    111100
    1101
    二进制 60 ^ 13 = 110001
    十进制 60 ^ 13 = 49
    

    实际应用:Swap 两数互换

    异或运算符用于 Swap 互换不需要第三个temp变量,我们可以把异或想象成减法取绝对值, 在二进制中,由于逢二进一,所以有1 - 1 = 0, 1 - 0 = 1, 0 - 0 = 0这样的特性,所以这三个等式中,任意两个数相减的绝对值都等于第三个数,用这种特性,就能进行Swap的两数互换。

    java 代码:

    int a = 60;
    int b = 13;
    
    System.out.println("a = " + Integer.toBinaryString(a));
    System.out.println("b = " + Integer.toBinaryString(b));
    
    System.out.println("a ^= b = " + Integer.toBinaryString(a ^ b));
    a ^= b;
    System.out.println("b ^= a = " + Integer.toBinaryString(b ^ a));
    b ^= a;
    System.out.println("a ^= b = " + Integer.toBinaryString(a ^ b));
    a ^= b;
    
    System.out.println("a = " + a);
    System.out.println("b = " + b);
    //输出
    a = 111100
    b = 1101
    a ^= b = 110001
    b ^= a = 111100
    a ^= b = 1101
    a = 13
    b = 60
    

    3.4 ~ 非(取反)运算

    ~(非),按位取反运算符翻转操作数的每一位,即0变成1,1变成0。所有的位运算符中,只有 ~ 运算符是一元运算符。如果我们把 1 看做 true 0 看做 false,取反操作就等于是每一位进行 !操作,!0 或者 !1,看下图。

    Java代码:

    int a = 60;
    int b = 13;
    
    System.out.println("二进制 a = " + Integer.toBinaryString(a));
    System.out.println("二进制 ~60 = " + Integer.toBinaryString(~a));
    System.out.println("十进制 ~60 = " + (~a));
    
    System.out.println("二进制 b = " + Integer.toBinaryString(b));
    System.out.println("二进制 ~13 = " + Integer.toBinaryString(~b));
    System.out.println("十进制 ~13 = " + (~b));
    
    //输出
    二进制 a = 111100
    二进制 ~60 = 11111111111111111111111111000011
    十进制 ~60 = -61
    二进制 b = 1101
    二进制 ~13 = 11111111111111111111111111110010
    十进制 ~13 = -14
    

    实际应用:取相反数

    首先先看下实际的二进制 int 型整数的 32-bit 存储图,图中最高位为0表示正数 ,1表示负数。int 型二进制最大正整数为 2147483647 ,最小负整数为 -2147483648,最小数恰恰是最大数的二进制数 +1。而且他们正好是互相按位反数,有~ 2147483647 = -2147483648。 直接上图

    avatar

    通过上图我们发现,对于int 型来说 最大正整数的取反正好是最小负整数,同时最小负整数的递增数的取反操作正好对应了最大正整数的递减数。所以得出取相反数的二进制位运算为 (~x + 1)

    Java 代码

    int a = 60;
    int b = 13;
    
    System.out.println("十进制 a = " + a);
    System.out.println("二进制 a = " + Integer.toBinaryString(a));
    System.out.println("二进制 ~a + 1 = " + Integer.toBinaryString((~a + 1)));
    System.out.println("十进制 ~a + 1 = " + (~a + 1));
    
    
    System.out.println("十进制 b = " + b);
    System.out.println("二进制 b = " + Integer.toBinaryString(b));
    System.out.println("二进制 ~b + 1 = " + Integer.toBinaryString((~b + 1)));
    System.out.println("十进制 ~b = 1 = " + (~b + 1));
    
    //输出如下:
    十进制 a = 60
    二进制 a = 111100
    二进制 ~a + 1 = 11111111111111111111111111000100
    十进制 ~a + 1 = -60
    十进制 b = 13
    二进制 b = 1101
    二进制 ~b + 1 = 11111111111111111111111111110011
    十进制 ~b = 1 = -13
    

    3.5 >> 按位左移

    按位左移,左操作数按位左移右操作数指定的位数。 写作 a << n ,使 a 的二进制数整体向左移动 n 位,并在低位补0。这个操作等同于 a x (2n) ,看图说话:

    Java 代码:

    int a = 60;
    int b = 13;
    
    System.out.println("十进制 a = " + a);
    System.out.println("二进制 a = " + Integer.toBinaryString(a));
    System.out.println("二进制 a << 2 = " + Integer.toBinaryString((a << 2)));
    System.out.println("十进制 a << 2 = " + (a << 2));
    
    
    System.out.println("十进制 b = " + b);
    System.out.println("二进制 b = " + Integer.toBinaryString(b));
    System.out.println("二进制 b << 2 = " + Integer.toBinaryString((b << 2)));
    System.out.println("十进制 b << 2 = " + (b << 2));
    
    //输出如下:
    十进制 a = 60
    二进制 a = 111100
    二进制 a << 2 = 11110000
    十进制 a << 2 = 240
    十进制 b = 13
    二进制 b = 1101
    二进制 b << 2 = 110100
    十进制 b << 2 = 52
    

    3.6 >> 按位右移

    按位右移,左操作数按位右移右操作数指定的位数。写作 a >> n ,使 a 的二进制数整体向右移动 n 位。这个操作等同于 a / (2n) , 如图:

    Java 代码

    int a = 60;
    int b = 13;
    
    System.out.println("十进制 a = " + a);
    System.out.println("二进制 a = " + Integer.toBinaryString(a));
    System.out.println("二进制 a >> 2 = " + Integer.toBinaryString((a >> 2)));
    System.out.println("十进制 a >> 2 = " + (a >> 2));
    
    
    System.out.println("十进制 b = " + b);
    System.out.println("二进制 b = " + Integer.toBinaryString(b));
    System.out.println("二进制 b >> 2 = " + Integer.toBinaryString((b >> 2)));
    System.out.println("十进制 b >> 2 = " + (b >> 2));
    
    //输出如下:
    十进制 a = 60
    二进制 a = 111100
    二进制 a >> 2 = 1111
    十进制 a >> 2 = 15
    十进制 b = 13
    二进制 b = 1101
    二进制 b >> 2 = 11
    十进制 b >> 2 = 3
    

    3.7 >>> 无符号按位右移

    按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。使 a 的二进制数整体向右移动 n 位,并在高位补0。这个操作等同于 a / (2n),他和 >> 区别在于高位补0,所以也叫无符号右移。如下图:

    Java 代码:

    int a = 60;
    int b = 13;
    
    System.out.println("十进制 a = " + a);
    System.out.println("二进制 a = " + Integer.toBinaryString(a));
    System.out.println("二进制 a >>> 2 = " + Integer.toBinaryString((a >>> 2)));
    System.out.println("十进制 a >>> 2 = " + (a >>> 2));
    
    
    System.out.println("十进制 b = " + b);
    System.out.println("二进制 b = " + Integer.toBinaryString(b));
    System.out.println("二进制 b >>> 2 = " + Integer.toBinaryString((b >>> 2)));
    System.out.println("十进制 b >>> 2 = " + (b >>> 2));
    
    //输出如下:
    十进制 a = 60
    二进制 a = 111100
    二进制 a >>> 2 = 1111
    十进制 a >>> 2 = 15
    十进制 b = 13
    二进制 b = 1101
    二进制 b >>> 2 = 11
    十进制 b >>> 2 = 3
    

    4. 常用的使用场景及效率对比

    前面介绍了3种最常用的使用场景,这里再介绍几种用法和它们的效率对比

    • 奇数偶数判断 a & 1 = 1 (奇数) a & 1 = 0 (偶数) 位运算效率低
    int a = 100;
    boolean temp;
    long start,end;
    start = System.currentTimeMillis();
    for(long i =0;i<100000000L;i++){
        temp = (a & 1) == 1;
        temp = (a & 1) == 0;
    }
    end = System.currentTimeMillis();
    System.out.println("位运算 :"+(end-start));
    start = System.currentTimeMillis();
    for(long i =0;i<100000000L;i++){
        temp = a % 1 == 1;
        temp = a % 1 == 0;
    }
    end = System.currentTimeMillis();
    System.out.println("模运算 :"+(end-start));
    //输出
    位运算 :38
    模运算 :33
    
    • Swap 不用临时变量两数互换 a ^= b; b ^= a; a ^= b; 位运算效率低
    int a = 100,b = 200,temp;
    long start,end;
    start = System.currentTimeMillis();
    for(long i =0;i<100000000L;i++){
        a = a^b;
        b = b^a;
        a = a^b;
    }
    end = System.currentTimeMillis();
    System.out.println("位运算 :"+(end-start));
    start = System.currentTimeMillis();
    for(long i =0;i<100000000L;i++){
        temp = a;
        a = b;
        b =temp;
    }
    end = System.currentTimeMillis();
    System.out.println("临时变量 :"+(end-start));
    //输出
    位运算 :99
    临时变量 :54
    
    • 取反 (~a + 1) 两者效率接近
    int a = 100;
    int temp;
    long start, end;
    start = System.currentTimeMillis();
    for (long i = 0; i < 1000000000L; i++) {
        temp = ~a + 1;
    }
    end = System.currentTimeMillis();
    System.out.println("位运算 :" + (end - start));
    start = System.currentTimeMillis();
    for (long i = 0; i < 1000000000L; i++) {
        temp = -a;
    }
    end = System.currentTimeMillis();
    System.out.println("直接取反 :" + (end - start));
    //输出
    位运算 :325
    直接取反 :331
    
    • 取绝对值 (a^(a>>31))-(a>>31) 两者效率接近
    int a = 100;
    int temp;
    long start, end;
    start = System.currentTimeMillis();
    for (long i = 0; i < 1000000000L; i++) {
        temp =  (a^(a>>31))-(a>>31) ;
    }
    end = System.currentTimeMillis();
    System.out.println("位运算 :" + (end - start));
    start = System.currentTimeMillis();
    for (long i = 0; i < 1000000000L; i++) {
        temp = Math.abs(a);
    }
    end = System.currentTimeMillis();
    System.out.println("Math函数 :" + (end - start));
    //输出
    位运算 :350
    Math函数 :331
    

    后面我们就不做代码示例了,各位有兴趣可以自己尝试下。

    • 整数的平均值 (x&y)+((x^y)>>1; 这样不会导致INT_MAXVALUE 溢出 两者效率接近
    • 快速乘法 a * (2^n) 等价于 a << n 位运算略快
    • 快速除法 a / (2^n) 等价于 a >> n 位运算略快

    总结:

    经过大量实验,在 Java 中其实位运算主要还是用在对位操作有要求的场景,在大多数情况下,位和数学运算的效率差不多。所以不需要为了装B而用位运算,这样会导致效率没怎么提升,代码阅读性还降低了。在HashMap源码中对Size扩容有这样一段代码,意思大概是每次扩容到距离 cap 最近的下一个 2n 的值。这段效率是普通数学运算的4倍左右。有兴趣的朋友可以试试!

    //HashMap源码,扩容方法
    static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }
    

    二进制
    位运算
    关于Java中位运算符的理解
    java基本数据类型
    路过图床

    展开全文
  • 公司项目领导要求数据库一个字段用int类型二进制表示多种状态 每个下标对应不同状态,1表示正常0表示不正常 如7二进制是111,则表示三个状态都正常6二进制110表示第一个不正常,第二第三个都正常. 要查询第...

    公司项目中领导要求数据库的一个字段用int类型的二进制表示多种状态
    每个下标对应不同的状态,1表示正常0表示不正常
    如7的二进制是111,则表示三个状态都正常6的二进制110表示第一个不正常,第二第三个都正常.
    要查询第二个状态是正常的,直接sql也能查出.
    如要查出第3位是正常所有记录

    select * from tableName where (column >> (3-1)) & 1 = 1;
    

    这个样表示的好处就是便于以后扩展,以后的状态有增减不用修改数据库.

    package com.base;
    
    /**
     * @Authro: QYF
     * @Time:2021/2/26 21:38
     */
    public class BinaryDemo {
        public static void main(String[] args) {
            //整数
            int num = 18;
            //转成二进制
            String binary = Integer.toString(num, 2);
            //从低位算,获取第几位是否为1
            int index = 2;
            boolean flag = getStatusType(num, index);
            System.out.println(num + "的二进制为:" + binary + ",二进制第:" + index + "位为:" + (flag ? 1 : 0));
    
            //状态
            int status = 0;
            int result = updateStatusType(num, index, status);
            System.out.println(num + "的二进制为:" + binary + ",把第" + index + "位改成" + status);
            System.out.println(result + "的二进制为:" + Integer.toString(result, 2));
        }
    
        /**
         * 判断第几位是否为1
         * <p>
         * 如18的二进制为10010,要获取第3位,则右移(3-1)位得100,第2位变成第1位,这样就可以和&1,最低位为1返回1,为0则返回0
         *
         * @param num   整数
         * @param index 低位起第几位下标
         * @return
         */
        private static boolean getStatusType(int num, int index) {
            return (num >> (index - 1) & 1) == 1;
        }
    
        /**
         * @param num    整数
         * @param index  低位起第几位下标
         * @param status 要修改的状态
         * @return
         */
        private static int updateStatusType(int num, int index, int status) {
            if (status != 0 && status != 1) {
                throw new IllegalArgumentException();
            }
            if (status == 1) {
                //1向左移(index-1) 和10010 或
                return (1 << (index - 1)) | num;
            } else {
                //先判断原来是不是0,原来是0则直接返回
                if (!getStatusType(num,index)){
                    return num;
                }
                //10010 - 1向左移(index-1)
                return num - (1 << (index - 1));
            }
    
        }
    
    }
    

    输出结果:

    18的二进制为:10010,二进制第:2位为:1
    18的二进制为:10010,把第2位改成0
    16的二进制为:10000
    
    展开全文
  •  Linux中的文件管理子系统权限管理,想必大家都知道:rwx分别代表read(可读),write(可写), execute(可执行,如果是可执行程序话),其中rxw可以按照数字表示:  r ------------- 4  w------------- ...

    前言:

      Linux中的文件管理子系统的权限管理,想必大家都知道:rwx分别代表read(可读),write(可写), execute(可执行,如果是可执行程序的话),其中rxw可以按照数字表示:

      r  -------------  4

      w -------------  2

      x  -------------  1
      如果有可读,可写,可执行权限,则用7表示...
      

      在最近的项目中,就遇到了这样的问题:我们做是IOT的硬件报警设备,现在一共有7种报警类型,每种设备报警的可能有:1种,多种或者0种,后台返回一个10进制数字来表示这种可能,前端需要根据后台返回的数字判断包含的报警。

      其实这个就跟linux文件权限一样,后台用bit位来存储设备报警结果,一共有7种报警类型,8个bit位就够了,每一个bit位对应一种报警类型,如果包含某种报警,对应的位置为1,反之置为0,然后后台将bit转位10进制的数字传给前端。其实表示这7种报警类型常规的做法是:后台为这报警类型alarm字典,将这7种报警类型存入alarm字典中,每一种报警类型是否包含的话用true和false处理,返回给前端的话如下:

      

    {
      alarm1: true,
      alarm2: false,
      alarm3: true,
      alarm4: false,
      alarm5: true,
      alarm6: false,
      alarm7: true,
    }

      从结果中,前端可以判定设备产生了4中报警:alarm1,alarm3,alarm5,alarm7。。。

      回到我现在的问题中去,前端需要将后台返回的10进制数字转为2进制数字(8个bit位),然后去判断1的位置,如果某一位的值为1,则包含对应的报警. 

      方法一:非CS专业出身笨办法

    let type = alarm.toString(2).padStart(8, '0').split('').reverse()
    const arr = [] // 用来存储包含的报警类型
    for (var i = 0; i < type.length; i++) {
        if (type[b] === '1') {
          switch (i) {
            case 0:
              alarm.push[i]
              break
            case 1:
              alarm.push[i]
              break
            case 2:
              alarm.push[i]
              break
            case 3:
              alarm.push[i]
              break
            case 4:
              alarm.push[i]
              break
            case 5:
              alarm.push[i]
              break
        
            default:
              break
          }
        }
    }
    console.log(arr.toString()) // 打印出所有的报警类型

     

      方法二:利用位操作判断(对于js按位操作不熟悉的同学,请自行补充相关知识)

      

    const arr = [] // 用来存储包含的报警类型
    for (let i = 0; i < 7; i++) {
        if (alarm >> i & 1) {
            arr.push(i)
        }
    }
    console.log(arr.toString()) // 打印出所有的报警类型

       按照这个实现,虽然看着舒服,但是简洁加执行效率高,还是很帅的。

      最后来说下,我google的实现结果,感觉更好理解:

    // 预先定义不同报警类型
    const alarm1 = 1;      // 0000 0001
    const alarm2 = 1 << 1; // 0000 0010
    const alarm3 = 1 << 2; // 0000 0100
    const alarm4 = 1 << 3; // 0000 1000
    const alarm5 = 1 << 4; // 0001 0000
    const alarm6 = 1 << 5; // 0010 0000
    const alarm7 = 1 << 6; // 0100 0000
    
    
    const arr = [] // 用来存储包含的报警类型
    const alarm = 7; // 后台返回的10进制数字
    
    // 是否包含alarm1
    if (alarm & alarm1) {}
    
    // 是否包含alarm1和alarm2中的任意一个
    if (alarm & (alarm1 | alarm2)) {}
    
    // 是否只包含alarm1和alarm2
    if (alarm === (alarm1 | alarm2)) {}
    
    // 是否同时包含alarm1和alarm2
    if (alarm === (alarm | (alarm1 | alarm2)) ) {}

     

    参考资料:

    https://codeburst.io/using-javascript-bitwise-operators-in-real-life-f551a731ff5

    转载于:https://www.cnblogs.com/hanshuai/p/10725402.html

    展开全文
  • 平均数、中位数、众数都是度量一组数据集中趋势统计量。所谓集中趋势是指一组数据向某一中心值靠拢倾向,测度集中趋势就是寻找数据一般水平代表值或中心值。而这三个特征数又各有特点,能够从不同角度提供...
    平均数、中位数、众数都是度量一组数据集中趋势的统计量。所谓集中趋势是指一组数据向某一中心值靠拢的倾向,测度集中趋势就是寻找数据一般水平的代表值或中心值。而这三个特征数又各有特点,能够从不同的角度提供信息。
    平均数
    特点:计算用到所有的数据,它能够充分利用数据提供的信息,它具有优 的数学性质,因此在实际应用中较为广泛。但它受极端值的影响较大。
    应用场合:没有极端值的情况下数据集中趋势的刻画。
    如:
    小明五次测试的成绩好下,87、88、89、93、94你认为小明这五次测试成绩怎样?
    分析:
    中位数
    特点:中位数是一组数据中间位置的代表值。计算简单,不受极端值的影响,但不能充分利用每个数据所提供的信息。
    应用场合:有极端值,且无某数据重复出现多次的情况下集中趋势的刻画。
    如:
    某公司员工月工资如下:
    员工 经理 副经理 员工a 员工b 员工c 员工d 员工e 员工f 杂工
    月工资/元 6000 4000 1700 1300 1200 1100 1100 1100 500
    这个公司员工的月工资有一般水平是多少?
    分析:这组数据的平均数是2000,而高于这一水平的只有2人,不具有代表性。其中位数是1200,处于其相当水平的有5人,占大多数。较好的反映了一般水平。
    众数
    特点:众数是一组数据中出现次数最多的数据。不受极端值的影响,当一组数据中苛些数据多次重复出现时,众数往往是人们最关心的一个量。但它不能象平均数那样充分利用数据提供信息。
    应用场合:有极端值,有某些数据多次重复出现时。
    如:
    一家鞋店在一段时间内销售了某种女鞋30双,各种尺码鞋的销量如下:
    尺码/厘米 22 22.5 23 23.5 24 24.5 25
    销售量/双 1 1 2 5 15 5 1
    你能为这家鞋店提供进货建议吗?

    分析:由于进货最关心的是哪种尺码的鞋最多,而这里很明显24码的要占相当大的量15双。较好的得到所需信息。


    转载:http://www.jxteacher.com/jxpxslzxhr/column7644/4ea14916-e613-4826-bcd4-861ef995798e.html

    展开全文
  • 已知n,检测其第K(右起)是否为1,可以用以下表达式: n & (1 << k - 1) 结果为0,说明第K为0;结果不为0,说明第K为1。 比如我要检测965二进制第3是否为1 public static void main(String[] ...
  • 已知n,检测其第K(右起)是否为1,可以用以下表达式: n & (1 << k - 1) 结果为0,说明第K为0;结果不为0,说明第K为1。 比如我要检测965二进制第3是否为1 public static void main(String[] ...
  • 在项目,有时候我们需要将数字转换成特定格式便于操作和使用。最常用就是在操作价格数字时候,需要将数字转换成小数点后保留两小数,比如讲3.4转换成3.40 我们可以用DecimalFormat,它是NumberFormat一...
  • 一. 操作基础,用一张表描述... 操作趣味应用,列举了操作在高低位交换、二进制逆序、二进制1个数以及缺失数字这4种趣味应用。 希望读者能认真学习和亲自上机输入代码进行实验,相信通过本文及适...
  • 对于未分组数据,可使用ExcelMEDIAN函数求解中位数。 对于分组数据,分为: 1. 组离散数据的中位数: 首先要构造累积频率分布表,然后通过累积频率分布表确定数据的中...看似非常简单的中位数计算,在使用了实际
  • 内容导入: 大家好,这里是每天分析一点点。本期给大家介绍是数据分析基础系列,主要给大家介绍是四分位数原理与应用,四分位数计算...多应用于统计学中的箱线图绘制。它是一组数据排序后处于25%和75%位置上
  • 下面是我在这次项目学习到,我眼中的位运算的应用!主要是实现 通知3个操作: 1. 置顶 2. 设为首页 3. 同时为 “置顶”+ “设为首页” 效果如图: 我们要想简便进行运算,我们可以直接进行如下枚举...
  • 两个数字交换位置,不借助临时变量 //: A UIKit based Playground ...给定一个无符号整数Uint变量 ,求其二进制表示 1个数,要求算法执行效率尽可能高 code 解题思路 与1与法 //: A UIKit based Playg..
  • 操作趣味应用,列举了操作在高低位交换、二进制逆序、二进制1个数以及缺失数字这4种趣味应用。 希望读者能认真学习和亲自上机输入代码进行实验,相信通过本文及适当练习可以使你对位操作有更加深入...
  • ASCII码表的实际应用之“随机生成六验证码”案例 需求: 随机生成一个6位数的验证码,验证码可以有大写字母,小写字母,至少有一个数字; 分析: 随机生成6位数的验证码,必须会使用Random; 而Random只能生成数字,思考...
  • 如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。根据题目的意思,就是对数据流中的数据进行排序然后得到其中位数。要解决的关键问题是如何在读入数据的时候就对数据进行排序。...
  • 结合学习成绩与收入案例分析,内容深入浅出,案例贴合实际,文章内容适合数据分析小白。下期给大家介绍集中趋势的应用。欢迎大家关注。概念介绍:四分位数是指在统计学把所有数值由小到大排列并分成四等份,...
  • 如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。思路:根据题目的意思,就是对数据流中的数据进行排序然后得到其中位数。要解决的关键问题是如何在读入数据的时候就对数据进行...
  • 带权中位数

    2012-11-06 18:37:12
    带权中位数算法及应用   信息学奥赛中有这样一类题:给出若干个排列在一条直线上点,每个点有一个权值,比如说货物量或者人数等,然后让我们找出使所有点货物或人集合到一个点总代价值最小得位置。这类问题...
  • 本文描述了两种时下 方法来改善实际ADC应用中的量化噪声性能:过采样和高频抖动。 为理解量化噪声缩减法,首先让我们回顾一下,一个理想NADC信号与量化噪声比为(单位dB) SNRQ=6.02N+4.77+20log10(LF)...
  • 1. Lambda 函数Lambda 函数是一种比较小匿名函数——匿名是指它实际上没有函数名。Python 函数通常使用 def a_function_name() 样式来定义,但对于 lambda 函数,我们根本没为它命名。这是因为 lambda 函数功能...
  • 【资料】带权中位数

    2019-09-30 23:06:18
    带权中位数算法及应用 信息学奥赛中有这样一类题:给出若干个排列在一条直线上点,每个点有一个权值,比如说货物量或者人数等,然后让我们找出使所有点货物或人集合到一个点总代价值最小得位置。这类问题...
  • 结合学习成绩与收入案例分析,内容深入浅出,案例贴合实际,文章内容适合数据分析小白。下期给大家介绍集中趋势的应用。欢迎大家关注。概念介绍:四分位数是指在统计学把所有数值由小到大排列并分成四等份,...
  • 今天咱们分享有余数的除法知识和在生活中的实际应用,先通过一个图例来说明什么是余数?一、有余数除法的意义: 在平均分时,会出现两种情况:一种是刚好分完,另一种是剩余。当平均分一些物品有剩余且不够再分的...
  • 运算的应用

    2020-09-18 17:00:00
    n计算,若n为正数,则实际移动位数为n%32,若n为负数,则实际移动位数为(32+n%32),右移,同理。 判断一个n奇偶性  n&1 == 1? “奇数” : “偶数” int类型1前31都是0,最低为1,当一个...
  • 大部分刚刚进入到游戏行业里程序员,你问他什么叫运算,他都懂,但实际中往往却不记得去使用它。任何一个整数都可以用二进度方式来表示,不同类型整数它位数长度也不一样,INT8或者char是由8个2进度...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,812
精华内容 724
关键字:

中位数的实际应用