进制与位运算(Java学习)

各进制学习

计算机使用的是二进制,那么什么是进制呢?
进制是我们规定的按照多少来选择进位,X进制就逢X进一。

各进制信息:

进制类型 前缀 举例
二进制: 0b /0B 0b1001
八进制: 0 01001
十进制: 没有前缀默认为10进制 1001
十六进制: 0x (X为A(10)-F(15),满16进1,以0X或0x开头表示,不分大小写) 0x1001

进制间相互转换

1.十进制转其他的x进制就是 除x取余,余数反转 。
2.其他进制转换十进制就是:各位拆开计算结果后合并
3.其他进制间相互转换就是前两种方法合起来使用,以十进制为桥梁。

protected static void base_study1(){
        String num1 = "0b10";
        int num2 = 011;
        int num3 = 0x11;
        int num4 = 11;
//        Java提供了十进制转其他进制的方法,Integer包装类提供以下的方法
        System.out.println("十进制11对应的二进制为:"+Integer.toBinaryString(num4));  //1011
        System.out.println("十进制11对应的八进制为:"+Integer.toOctalString(num4));   //13
        System.out.println(num4);  //11
        System.out.println("十进制11对应的十六进制为:"+Integer.toHexString(num4));    //b
    }

原码,反码,补码

对于有符号的而言:
1.二进制的最高位(最左边)是符号位:0表示正数,1表示负数;
2.正数的原码、反码、补码都一样(三码合一);
3.负数的反码=它的原码符号位不变,其他位数取反;
4.在计算机运算的时候,都是以补码的方式来运算的;
5.0的反码,补码都是0;
6.java中的数都是有符号的;
7.负数的补码=它的反码+1,负数的反码 = 负数的补码 - 1。
8.如果我们要看运算结果,要看它的原码。

位运算符

Java 定义的位运算是直接对整数类型的位进行操作,这些整数类型包括 long,int,short,char 和 byte。按每个二进制位进行计算,其操作数和运算结果都是整型值。Java 语言中的位运算符分为位逻辑运算符和位移运算符两类,下面详细介绍每类包含的运算符。
java中有七个位运算符(&、|、^、~、>>、<<、>>>),分别是按位与&,按位或|,按位异或,按位异或,按位取反,算数右移,算数左移,逻辑右移,
运算规则:
1)按位与&:两位全为1,结果为1,否则为0;

protected static void base_study2(){
        int num1 = 1;
        int num2 = 2;
        System.out.println("1的二进制数:"+Integer.toBinaryString(num1));//0000 0001
        System.out.println("2的二进制数:"+Integer.toBinaryString(num2));//0000 0010
        System.out.println("----------------------------------------");
//        按位与
        System.out.println(1 & 2);                                     //0000 0000
        \System.out.println("1 & 2 的结果二进制:"+Integer.toBinaryString((1 & 2)));//0
    }

(2)按位或|:两位有一个为1,结果为1,否则为0;

System.out.println("----------------------------------------");
System.out.println("1的二进制数:"+Integer.toBinaryString(num1));           //0000 0000 0000 0000 0000 0000 0000 0001
System.out.println("2的二进制数:"+Integer.toBinaryString(num2));           //0000 0000 0000 0000 0000 0000 0000 0010
//        按位或                                                                  //0000 0000 0000 0000 0000 0000 0000 00(0|1=1)(1|0=1)
System.out.println(1 |2 );                                               //3
System.out.println("1 | 2 的结果二进制:"+Integer.toBinaryString((1 | 2))); //0000 0000 0000 0000 0000 0000 0000 0011

(3)按位异或^:两位一个为0,一个为1,结果为1,否则为0;

System.out.println("----------------------------------------");
System.out.println("1的二进制数:"+Integer.toBinaryString(num1));           //0000 0000 0000 0000 0000 0000 0000 0001
System.out.println("2的二进制数:"+Integer.toBinaryString(num2));           //0000 0000 0000 0000 0000 0000 0000 0010
//        按位异或                                                         //0000 0000 0000 0000 0000 0000 0000 00(0 ^ 1=1)(1^0=1)
System.out.println(1 ^2 );                                                //3
System.out.println("1 ^2的结果二进制:"+Integer.toBinaryString((1 ^2)));     //0000 0000 0000 0000 0000 0000 0000 0011

(4)按位非~:0 ->1 , 1->0

System.out.println("----------------------------------------");
System.out.println("2的二进制数:"+Integer.toBinaryString(num2));           //0000 0000 0000 0000 0000 0000 0000 0010
//        按位非                                                           //(~0=1)111 1111 1111 1111 1111 1111 1111 1101
System.out.println(~2 );                                                 //-3
System.out.println("~ 2 的结果二进制:"+Integer.toBinaryString((~2)));      //1111 1111 1111 1111 1111 1111 1111 1101

(5)算数右移>>:低位溢出,符号位不变,并用符号位补溢出的

System.out.println("----------------------------------------");
System.out.println("5的二进制数:"+Integer.toBinaryString(5));           //0000 0000 0000 0000 0000 0000 0000 0101
//        右位移运算符                                                   //0000 0000 0000 0000 0000 0000 0000 0001 -(01)
System.out.println(5 >>2 );                                              //1
System.out.println("5 >>2的结果二进制:"+Integer.toBinaryString((5 >>2)));  //0000 0000 0000 0000 0000 0000 0000 0001

(6)算数左移<<:符号位不变,低位补0;

System.out.println("----------------------------------------");
System.out.println("5的二进制数:"+Integer.toBinaryString(5));           //0000 0000 0000 0000 0000 0000 0000 0101
//        左位移运算符                                                   //0000 0000 0000 0000 0000 0000 0001 0100 +(00)
System.out.println(5 <<2 );                                              //20
System.out.println("5<<2的结果二进制:"+Integer.toBinaryString((5<<2)));    //0000 0000 0000 0000 0000 0000 0001 0100

(7)逻辑右移>>>: 低位溢出,高位补0;

System.out.println("----------------------------------------");
System.out.println("5的二进制数:"+Integer.toBinaryString(5));           //0000 0000 0000 0000 0000 0000 0000 0101
//        无符号右位移运算符                                              //0000 0000 0000 0000 0000 0000 0000 0001 -(01)
System.out.println(5 >>>2 );                                             //1
System.out.println("5>>>2的结果二进制:"+Integer.toBinaryString((5>>>2)));  //0000 0000 0000 0000 0000 0000 0000 0001

(8)无>>>运算符。

System.out.println("----------------------------------------");
System.out.println("5的二进制数:"+Integer.toBinaryString(5));           //0000 0000 0000 0000 0000 0000 0000 0101
//        无符号右位移运算符                                              //0000 0000 0000 0000 0000 0000 0000 0001 -(01)
System.out.println(5 >>>2 );                                             //1
System.out.println("5>>>2的结果二进制:"+Integer.toBinaryString((5>>>2)));  //0000 0000 0000 0000 0000 0000 0000 0001

System.out.println("----------------------------------------");
System.out.println("-5的二进制数:"+Integer.toBinaryString(-5));         //1111 1111 1111 1111 1111 1111 1111 1011
//        无符号右位移运算符                                              // 0001 1111 1111 1111 1111 1111 1111 1110 -(11)
System.out.println(-5 >>>2 );                                            //1073741822
System.out.println("-5>>>2的结果二进制:"+Integer.toBinaryString((-5>>>2)));// 0011 1111 1111 1111 1111 1111 1111 1110

(9) 公式:m*2^n = m << n
法则一:任何数左移(右移)32的倍数位等于该数本身。
法则二:在位移运算m<<n的计算中,若n为正数,则实际移动的位数为n%32,若n为负数,则实际移动的位数 为 (32+n%32),右移,同理。左移是乘以2的幂,对应着右移则是除以2的幂。

(10)快速判断一个数n的奇偶性
原理:偶数的最后一位肯定是0,1的最后一位是1,那么就用其他数来和1进行位与的运算,1的其他31位都是0,不可能和其他数实现位与得1,所以就看最后两者的结果是不是1就可以判断奇数还是偶数了。

        int num1 =1;
        int num2 =2;
        System.out.println((num1 & 1)==1 ? "奇数" : "偶数");//偶数
        System.out.println((num2 & 1)==1 ? "奇数" : "偶数");//奇数

`
(11)不用临时变量交换两个数(相同的两个数无法交换)
连续三次使用异或,并没有临时变量就完成了两个数字交换

        int a = 1;
        int b = 2;
        System.out.println("a:" +a +",b:" +  b); //1;2
        a = a ^ b;
        b = b ^ a;  //b = b ^ (a ^ b) => b=a
        a = a ^ b;  //a = (a ^ b)^[b ^ (a ^b)] => a=b
        System.out.println("a:" +a +",b:" +  b); //2;1
` ` `

(12)取绝对值
原理: |a| = (a^(a>>31))-(a>>31)

        int sum3=-1;
        System.out.println((sum3^(sum3>>31))-(sum3>>31));

位运算的其他妙用

四、有趣的位运算符操作
1.利用或操作 | 和空格将英文字符转换为小写

('a' | ' ') = 'a'
('A' | ' ') = 'a'

2.利用与操作 & 和下划线将英文字符转换为大写

```java
('b' & '_') = 'B'
('B' & '_') = 'B'

3.利用异或操作 ^ 和空格进行英文字符大小写互换

('d' ^ ' ') = 'D'
('D' ^ ' ') = 'd'

以上操作能够产生奇特效果的原因在于 ASCII 编码。字符其实就是数字,恰巧这些字符对应的数字通过位运算就能得到正确的结果,有兴趣的读者可以查 ASCII 码表自己算算,本文就不展开讲了。

4.判断两个数是否异号

int x = -1, y = 2;
bool f = ((x ^ y) < 0); // true
int x = 3, y = 2;
bool f = ((x ^ y) < 0); // false

这个技巧还是很实用的,利用的是补码编码的符号位。如果不用位运算来判断是否异号,需要使用 if else 分支,还挺麻烦的。读者可能想利用乘积或者商来判断两个数是否异号,但是这种处理方式可能造成溢出,从而出现错误。

5.不用临时变量交换两个数

int a = 1, b = 2;
a ^= b;
b ^= a;
a ^= b;
// 现在 a = 2, b = 1

6.加一

int n = 1;
n = -~n;

7.减一

int n = 2;
n = ~-n;

参考文献

参考文章1:http://c.biancheng.net/view/784.html
参考文献2:https://blog.csdn.net/qq_42265220/article/details/118386893

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值