各进制学习
计算机使用的是二进制,那么什么是进制呢?
进制是我们规定的按照多少来选择进位,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