进制转换与位运算

进制转换与位运算

  • 进制转换
    • 数学进制转换
    • Java进制转换
  • 按位运算
  • 位运算应用

进制转换

  • 二进制数:由前缀0b开头,前缀可省略。只有0和1组成
  • 十进制数:由1-9开头,0-9组成
  • 八进制数:由前缀0以及后续的0-7的数字来表示
  • 十六进制数:由前缀0x,后面跟随0-9或大/小写的a-f来表示(a-f依次表示10-15)

数学进制转换

十进制 => 二进制

十进制数除2取余法,即十进制数除2,余数为权位上的数,得到的商值继续除2,依此步骤继续向下运算直到商为0为止。

十进制 160 80 40 20 10 5 2 1 0
除2取余 0 0 0 0 0 1 0 1 0

倒序后:

  • 十进制160 的二进制:10100000
  • 十进制80   的二进制:1010000
  • 十进制40   的二进制:101000

二进制 => 十进制

把二进制数按权展开、相加即得十进制数。

二进制 1 0 1 0 0 0 0 0
按权展开 1 × \times × 27 0 × \times × 26 1 × \times × 25 0 × \times × 24 0 × \times × 23 0 × \times × 22 0 × \times × 21 0 × \times × 20
计算 128 0 32 0 0 0 0 0

相加后:

  • 二进制10100000 的十进制 :128 + 32 = 160
  • 二进制    100000 的十进制:32

二进制 => 八进制

从右向左,每3位二进制数按权展开相加得到1位八进制数

二进制 1 0 1 0 0 0 0 0
按权展开 1 × 27 0 × 26 1 × 25 0 × 24 0 × 23 0 × 22 0 × 21 0 × 20
计算 2 4 0

相加后:

  • 二进制10100000 的八进制:240
  • 二进制    100000 的八进制:40

八进制 => 二进制

八进制是取三合一,八进制数通过除2取余法,得到二进制数,对每个八进制为3个二进制,不足时在最左边补零。

八进制 2 4 0
除2 2 1 0 4 2 1 0 0 0
取余(二进制) 0 1 0 0 0 1 0 0 0
倒序 010 100 000

转换后:

  • 八进制240 的 二进制:010100000
  • 八进制   40 的二进制:100000

二进制 => 十六进制

与二进制转八进制方法近似,十六进制是取四合一。(注意事项,4位二进制转成十六进制是从右到左开始转换,不足时补0)

二进制 1 0 1 0 0 0 0 0
按权展开 1 × 27 0 × 26 1 × 25 0 × 24 0 × 23 0 × 22 0 × 21 0 × 20
计算 a(10) 0

转换后:

  • 二进制10100000 的十六进制:0xa0
  • 二进制1010         的十六进制:0xa

十六进制 => 二进制

十六进制数通过除2取余法,得到二进制数,对每个十六进制为4个二进制,不足时在最左边补零。

十六进制 a(10) 0
除2 10 5 2 1 0 0 0 0
取余 0 1 0 1 0 0 0 0
倒序 1010 0000

转换后:

  • 十六进制0xa0的二进制:10100000
  • 十六进制0xa  的二进制:1010
【原码、补码、反码】
正数:正数的原码即为其反码,正数的原码即为其补码
  •     十进制:160 --> 二进制:1010 0000
  • 原码:0 0 0 0   0 0 0 0   0 0 0 0   0 0 0 0   0 0 0 0   0 0 0 0   1 0 1 0   0 0 0 0
  • 反码:0 0 0 0   0 0 0 0   0 0 0 0   0 0 0 0   0 0 0 0   0 0 0 0   1 0 1 0   0 0 0 0
  • 补码:0 0 0 0   0 0 0 0   0 0 0 0   0 0 0 0   0 0 0 0   0 0 0 0   1 0 1 0   0 0 0 0
负数:将原码除符号位以外的位数取反得到反码,补码=反码+1
  •     十进制:-160
  • 原码:1 0 0 0   0 0 0 0   0 0 0 0   0 0 0 0   0 0 0 0   0 0 0 0   1 0 1 0   0 0 0 0
  • 反码:1 1 1 1   1 1 1 1   1 1 1 1   1 1 1 1   1 1 1 1   1 1 1 1   0 1 0 1   1 1 1 1
  • 补码:1 1 1 1   1 1 1 1   1 1 1 1   1 1 1 1   1 1 1 1   1 1 1 1   0 1 1 0   0 0 0 0

Java进制转换

System.out.println("---------------------------------");
System.out.println("十进制转二进制:" + Integer.toBinaryString(160));
System.out.println("十进制转八进制:" + Integer.toOctalString(160));
System.out.println("十进制转十六进制:" + Integer.toHexString(160));
System.out.println("十进制转三进制:" + Integer.toString(160,3));
System.out.println("---------------------------------");
System.out.println("二进制转十进制:" + Integer.parseInt("10100000", 2));
System.out.println("八进制转十进制:" + Integer.parseInt("240", 8));
System.out.println("十六进制转十进制:" + Integer.parseInt("a0", 16));
System.out.println("三进制转十进制:" + Integer.parseInt("12221", 3));
System.out.println("---------------------------------");
System.out.println("二进制 0b10100000 的十进制:" + 0b10100000);
System.out.println("八进制 0024 的十进制:" + 0240);
System.out.println("十六进制 0xa0 的十进制:" + 0xa0);
System.out.println("---------------------------------");
  • 数字的二进制表示形式称为“有效的二进制补码”
  • java中 Integer.toBinaryString(i) 是转换为二进制补码

按位运算

与(&)

  • 如果两个输入位都是1,则按位与,生成一个输出位1;否则生成一个输出位0
1 & 1 = 1 1 & 0 = 0 0 & 0 = 0

或(|)

  • 如果两个输入位里只要有一个是1,则按位或,生成一个输出位1;只有在两个输出位都是0的情况下,才会生成一个输出位0。
1 | 1 = 1 1 | 0 = 1 0 | 0 = 0

异或(^)

  • 如果输入位的某一个是1,但不全都是1,那么按位异或,生成一个输出位1。
1 ^ 1 = 0 1 ^ 0 = 1 0 ^ 0 = 0
i ^ 1 == i + 1 ( i 为偶数) i ^ -1 == - ( i + 1 ) i ^ 0 = i

非(~)

  • 按位非,取反操作符,一元操作符,只对一个操作数进行操作,生成与输入位相反的值
1 0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 1
~1 1 1 1 1  1 1 1 1  1 1 1 1  1 1 1 1  1 1 1 1  1 1 1 1  1 1 1 1  1 1 1 0
-5 1 1 1 1  1 1 1 1  1 1 1 1  1 1 1 1  1 1 1 1  1 1 1 1  1 1 1 1  1 0 1 1
~-5 0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 0  0 1 0 0

a % 2 == a & 1 ;   ~x + 1 可得相反数

左移(<<)

  • 左移 位操作符 能够按照操作符右侧指定的位数 将操作符左边的操作数 向左 移动
  • 规则:溢出的舍弃,空位的补0
  • 注意:移位时,需要使用补码进行计算
    进制转换与位运算_第1张图片
    进制转换与位运算_第2张图片
  • 计算负数时,先算出补码进行计算,计算完成后,使用补码-1进行逆运算获得反码,最后计算出原码

右移(>>)

  • 右移 位操作符 能够按照操作符右侧指定的位数 将操作符左边的操作数 向右 移动
  • 规则:溢出的舍弃,空位正数用0填补,负数用1填补
  • 注意:移位时,需要使用补码进行计算
    进制转换与位运算_第3张图片
    进制转换与位运算_第4张图片
  • 计算负数时,先算出补码进行计算,计算完成后,使用补码-1进行逆运算获得反码,最后计算出原码

无符号右移(>>>)

  • 无符号右移:正数与右移规则一样,负数的无符号右移,就是相应的补码移位所得,在高位补0即可
    进制转换与位运算_第5张图片
  • 对于负数,无符号右移后,不取原码,因此 -10>>>2的结果为111111111111111111111111111101

快捷计算方式:
   对于 i << n,计算方式是 i * (2n)
   对于 i >> n,计算方式是 i / (2n)

位运算应用

1. 判断奇偶性

奇数都不是2的整数倍,转换成二进制后最低位必然为1,偶数则相反。

boolean isOddNumber(int n){
     
    return (n & 1) == 1;
}

2. 判断一个正整数是否是2的整数次幂

常见的2的整数次幂的数:2、4、8、16,转化成二进制依次为:10、100、1000、10000。除了首位是1,其他全是0。
规律:这些数减去1后等于他们依次按位取反的结果,比如8-1=7,7的二进制是111,8的二进制1000按位取反后也是111。8 & 7= 0。可总结为 ( n & (n-1))==0

boolean isPowOfTwo(int n){
     
    return (n & (n-1)) == 0;
}

3. 求绝对值

任何正数右移31后只剩符号位0,最终结果为0,任何负数右移31后也只剩符号位1,溢出的31位截断,空出的31位补符号位1,最终结果为-1.右移31操作可以取得任何整数的符号位。
a>>31取得a的符号,若a为正数,a>>31等于0,a ^ 0=a,不变;若a为负数,a>>31等于-1 ,a ^ -1每一位取反

int getAbs(int a){
     
	return  (a^(a>>31))-(a>>31);
}

4. 求平均值

对于两个整数x,y,假设用 (x+y)/2 求平均值。会产生溢出。由于 x+y 可能会大于INT_MAX,可是它们的平均值是肯定不会溢出的。

int getAverage(int x, int y){
         
    return (x&y)+((x^y)>>1); 
} 

5. 求二进制中1的个数

一个int型的十进制正整数,计算出该int型数据在内存中存储时1的个数。

int getCount(int num){
     
	int count = 0;
    while(num != 0) {
     
        count++;
        num = num & (num -1);
    }
    return count;
}

你可能感兴趣的:(Java基础,java)