在计算机中,目前常用的进制有如下几种:二进制、八进制、十进制、十六进制
本篇研究十进制与其他进制(其他进制一般情况下都是在指二进制、八进制、十六进制)的转换,其中重点讲解"十进制与二进制之间如何互换"。其他的进制和十进制互转"原理同"二进制和十进制互转",就不展开了
注:只是简单记怎么转换,更底层的原理后续再说
1、二进制基础要点
二进制(binary)、八进制(octal)、十进制(decimal)、十六进制(hex)
1.1、当前使用的数字是十进制形式的,对于二进制、八进制、十六进制的数字,编写是这样的
二进制
数字0加大小写都可以的字母B/b,表示二进制。如二进制下的12写作0b12,转为十进制是4
八进制
数字零跟数字表示八进制下的数字,如010表示八进制的10,转为十进制是8
十进制正常写
十六进制
数字零和字母x/X再跟数字表示十六进制下的数字,如ox10,转为十进制是16
(注意十六进制满16位进1,0到9、A到F(字母也可以是小写的))
1.2、原码、反码、补码
正数的原码、反码、补码是一致的。负数的原码转为反码是"符号位不变,其余位取反",负数的反码转为补码则是"末尾位+1",所以原反补的概念只对负数有实际意义
1.3、计算机永远存储的都是二进制的补码形式且你十进制转为二进制是转为了二进制的补码形式
计算机中,最高位表示符号位,0表示正数、1表示负数
2、十进制与二进制互转
2.1、十进制转为二进制
两种方法:第一种方法叫除进制数取余数,逆序输出法;第二种方法叫凑数法(方法一二仅仅是我个人的叫法;别处管第一种叫"辗转法")
2.1.1、方法一
十进制转二进制,所以进制数是2,所以是除2取余数,再逆序输出。具体是十进制的数除以你所要转换的进制数,把每次除得的余数记在旁边,所得的商数继续除以进制数,直到商为0时止,再将余数和最后的1按照从下向上倒序写
100转换为二进制
100/2=50....(余数为0)
50/2=25.....(余数为0)
25/2=12.....(余数为1)
12/2=6......(余数为0)
6/2=3.......(余数为0)
3/2=1.......(余数为1)
1/2=0.......(余数为1)
所以十进制的100用二进制表示就是0110 0100
(注:为了方便查看,一般都是用一个字节表示)
十进制转其他进制同理
//100转换成八进制形式
100/8=12...(余数为4)
12/8=1.....(余数为4)
1/8=0......(余数为1)
得出144,此即为十进制100在八进制下的表示形式
//再看一个,144转为8进制
144/8=18..0
18/8=2..2
2/8=0..2
所以是220
//再看100转换为十六进制
100/16=6....(余数为4)
6/16=0......(余数为6)
所以以十六进制表示的100为64
2.1.2、方法二
凑数就是知道二进制每一位的值多大
同样1字节演示
0 0 0 0 0 0 0 0
2^7=128 2^6=64 2^5=32 2^4=16 2^3=8 2^2=4 2^1=2 2^0=1
简记
0 0 0 0 0 0 0 0
128 64 32 16 8 4 2 1
所以二进制数0110 0001转为十进制就是
64+32+1=97
//十进制的302转为二进制是?
上面可见最高位的值是128,往前一位的值是256、再往前一位是512
302拆出最大值是256
256 128 64 32 16 8 4 2 1
1 1 1 1 1
302=256+32+8+4+2
得到十进制的302在二进制下表示是1 0010 1110,完整是0000 0001 0010 1110
//再看十进制150,其二进制表示是
0 0 0 0 0 0 0 0
128 64 32 16 8 4 2 1
1 0 0 1 0 1 1 0
128 64 32 16 8 4 2 1
128+16+4+2=150
所以二进制就是0000 0000 1001 0110
2.2、十进制的负数、小数怎么转为二进制
2.2.1、负数的二进制
去掉负号按照正数求出二进制表示,再加上负号(最高位是符号位,加上负号即符号位改为1),得到了负数的原码。负数的反码则是符号位不变,其他位取反。负数的补码则负数的反码+1
举例,-24和-68,求出其二进制表示
-24
先去掉负号,求24的原码,是0001 1000
再加上负号得出-24的原码,是1001 1000
再求-24的反码,是1110 0111
再求-24的补码,是1110 1000
-24 24的原码是0001 1000
-24的原码是1001 1000
-24的反码是1110 0111
-24的补码是1110 1000
//再算-68
-68 68的原码,0100 0100
-68的原码,1100 0100
-68的反码,1011 1011
-68的补码,1011 1100
2.2.2、小数转二进制
十进制数12.02,怎么转为二进制呢?
整数部分前面学过,小数部分同样管自己求。意思是有小数的数,整数部分按正数转二进制的方法去算二进制表示,小数部分按小数转二进制的方法去算二进制表示,不是一起转换为二进制的
下面介绍小数怎么转二进制表示
整数部分是除进制数取余数逆序输出法,而小数部分是乘进制数取商法
小数部分乘以 2,记录结果的整数部分,摘取结果的小数进入下一次*2,直到出现结果的小数为 0 时停止。最后将每次得到的整数部分按照先后顺序正序排列,就能得到对应的二进制表示了
如十进制的0.25
0.25 *2=0.5 取0
0.5 *2=1.0 取1。可见小数部分是0了,所以停止-2
所以十进制的0.25转为二进制是0.01
用凑数法也行
8 4 2 1 0.5 0.25
所以0.25就是
0000.01
2.3、二进制转十进制
前面"十进制转二进制是转的补码形式",注意二进制转十进制要求二进制是原码形式
以前面的十进制150转二进制为例
150转二进制得到1001 0110
int类型的150,其二进制完整表示是
0000 0000 0000 0000 0000 0000 1001 0110
再强转为byte类型所以砍去三字节,剩下1001 0110
符号位是1所以是负数,底层存储的都是补码形式
所以
1001 0110 补码形式;转反码
1001 0101 反码形式;再转原码
1110 1010 原码形式;这下可以转十进制了
-(64+32+8+2)=-106
再看
byte bt=(byte)300;
System.out.println(bt); 44
同理
先写出300的二进制: 省略23个0,再跟1 0010 1100
由于300超出byte范围,所以强转后只剩下一个字节变为0010 1100
再正数原反补一致所以直接转十进制,得到结果是44
下面看第二种转换方法,仅了解
把二进制从最高位(最左边的“1”)开始,先按照从上到下的顺序写出来。先从第1位开始计算0*2,如果每一位上对应的余数是1,在乘以”2“之后还要再加”1“,否则就加0。接着用上一次计算得到的结果乘以2,后面再加1或者是0,以此类推。用1 0010 1110进行演示
100101110
1…………0✖️2+1=1…………余数为1
0…………1✖️2+0=2………… 余数为0
0 …………2✖️2+0=4 ………… 余数为0
1 …………4✖️2+1=9……………… 余数为1
0…………9✖️2+0=18 ……………… 余数为0
1 …………18✖️2+1=37 …………余数为1
1…………… 37✖️2+1=75…………余数为1
1………………75✖️2+1=151………… 余数为1
0………………151✖️2+0=302 ………… 余0
通过这样的计算就可以得到最终的十进制数302
3、代码层面进行进制转换
3.1、十进制转为其他进制
Integer类,里面提供了三个方法
Integer.toBinaryString(int i) 十进制数转换成无符号的二进制数
Integer.toOctalString(int i) 十进制数转换成无符号的八进制数
Integer.toHexString(int i) 十进制数转换成无符号的十六进制数
实测
public static void test1(){
int num = 200;
System.out.println(num + " 转二进制是:" + Integer.toBinaryString(num));
System.out.println(num + " 转八进制是:" + Integer.toOctalString(num));
System.out.println(num + " 转十六进制是:" + Integer.toHexString(num));
}
200 转二进制是:11001000
200 转八进制是:310
200 转十六进制是:c8
注:这里也是讨论的无符号的转换。如果是带符号的,转换规则跟这个完全不一样,需要另行讨论
->可见限制还挺大的,只能是正数是int类型的才能有这么代码转换
3.2、其他进制转为二进制
//二进制转为十进制的方法
public static Integer binaryToDecimal(String binary){
Integer result=0;
char[] binarys=new StringBuffer(binary).reverse().toString().toCharArray();
for(int index=0;index<binary.length();index++){
result=result+Integer.valueOf(binarys[index]+"")*pow(2,index);
}
return result;
}
//计算幂次方的方法
public static Integer pow(int num1,int num2){
Integer result=1;
for (int index=0;index<num2;index++){
result*=num1;
}
return result;
}
//八进制转十进制
public static Integer octalToDecimal(String octal){
Integer result=0;
char[] octals=new StringBuffer(octal).reverse().toString().toCharArray();
for (int index=0;index<octal.length();index++){
result=result+Integer.valueOf(octals[index]+"")*pow(8,index);
}
return result;
}
//十六进制转为十进制
public static Integer hexToDecimal(String hex){
Integer result=0;
char[] hexs=new StringBuffer(hex).reverse().toString().toCharArray();
for (int index=0;index<hex.length();index++){
if ("A".equalsIgnoreCase(hexs[index]+"")){
result=result+10*pow(16,index);
}else if ("B".equalsIgnoreCase(hexs[index]+"")){
result=result+11*pow(16,index);
}else if ("C".equalsIgnoreCase(hexs[index]+"")){
result=result+12*pow(16,index);
}else if ("D".equalsIgnoreCase(hexs[index]+"")){
result=result+13*pow(16,index);
}else if ("E".equalsIgnoreCase(hexs[index]+"")){
result=result+14*pow(16,index);
}else if ("F".equalsIgnoreCase(hexs[index]+"")){
result=result+15*pow(16,index);
}else {
result=result+Integer.valueOf(hexs[index]+"")*pow(16,index);
}
}
return result;
}
3.3、拓展
实际上Integer还提供了更多进制转十进制、十进制转更多进制的方法
//十进制 -> N 进制
Integer.toString(int num, int N)
第一个参数是要转换的数字,第二个参数是要转换成为的进制
即,第一个参数接收传参,第二个参数表示要转换为哪个进制:二进制传2、八进制传8...
当数字为十进制的时候认为是 int (或者long,BigInteger…)是个数字类型
当数字为其他进制的时候则被认为 是String 类型->啥意思
//十进制转为二、八、十六进制
String tb2 = Integer.toString(9, 2); // 10进制转2进制
String to2 = Integer.toString(10, 8); // 10进制转8进制
String th2 = Integer.toString(1194684, 16);// 10进制转16进制
//再看转为三进制
System.out.println(num + " 转三进制是:" + Integer.toString(num, 3));
200 转三进制是:21102
//N进制->十进制
相反,如果我们要将一个 N 进制的字符串 str 转换为十进制数,那么可以使用以下方法
Integer.parseInt(String str, int N)
第一个参数是要转换的字符串,第二个参数是字符串所属于的进制
不写表示进制的参数,则默认是十进制
(因为我们要转换为int,默认就是十进制了->不对吧,怎么就默认十进制了,不是字符串所属的进制吗)
int b = Integer.parseInt("1001", 2); // 2进制转10进制
int o = Integer.parseInt("12", 8); // 8进制转10进制
int h = Integer.parseInt("123ABC", 16); // 16进制转10进制
int t = Integer.parseInt("21102", 3);
String str = "21104";
int N = 5;
System.out.println(str + " 转十进制是:" + Integer.parseInt(str, N));
"21104" 转十进制是:1404
还有Integer.valueOf(String,int)
Integer b2 = Integer.valueOf("1001", 2); // 2进制转10进制
Integer o2 = Integer.valueOf("12", 8); // 8进制转10进制
Integer h2 = Integer.valueOf("123ABC", 16); // 16进制转10进制
Integer t2 = Integer.valueOf("21102", 3);