------- android培训、java培训、java学习型技术博客、期待与您交流! ----------
一、进制的产生概述:
我们的生活中,从小开始接触到的数学规则是满十进一,这就是进制的最常见制。在我们的世界里面,十进制是默认通用的,事实上其他进制在生活中我们也用不上。
在高速发展的现代社会,计算机浩浩荡荡地成为了人们生活中不可缺少的一部分,帮助人们解决通信,联络,互动等各方面的问题。随着使用的人越来越多,计算机的世界也就越来越人们所了解。
在计算机中,数据储存是通过硬盘操作的,使用电路的形式来代表数据,电路里面的表现形式只有两种,开或者关,用0或者1来表示,这也就是二进制的起源了。
简单说,在人类的世界里面,十进制是通用的,在计算机的世界里面,二进制是通用的。在人类世界与计算机世界进行交流的过程中,就需要使用到翻译,这个翻译就是进制的转换了。在说明进制转换原理之前,先再说说我们还见过的常见的其他进制。
八进制: 满8进位,用数字0~7表示,在java中,用0开头表示 比如数字10用八进制表示就是: 012;
十六进制:满16进位,用数字0~9以及字母A~F表示,用0x开头 ,比如数字18在十六进制终究是:0xF2;
三十二进制:理论上有,但是因为代表的值太大了,所以基本上没有使用的情况。
那么,除了十进制和二进制的使用之外,其他几个进制的使用价值在哪里呢?下面解析进制的原理:
在计算机里面,最小的储存单位是字节byte,一个byte代表八个进制为:0000-0000。
比如我们定义一个byte a = 6 时,6这个数字在计算机里面的表现形式为: 0000-00110(使用其他类型的数据,可以使用多个byte来定义);这样就会产生一个问题,当这个数字很大的时候,显示这个数字所表示出来的字符长度就会很长,不便于阅读,于是就出现了常见的八进制,取三个进制为来表示一个数字,例如:
20的二进制表现形式为,0001-0100,如果使用八进制进行表示:00-010-100 , 则八进制的表现形式为:017 ,则看起来数字会更加的符合人类的认识度。
同理,十六进制也一样,使用4个进制位来表示一位。
至于为什么八进制和十六进制会和十进制一起出现,我个人的理解是:十进制是人类的规则,但是不完全符合计算机,八进制和十六进制是基于二进制的基础上做优化,相比起来转化的效率会更高。
二、进制的装换:
进制的转换就跟原理一样,满几进位,其中大致的规则如下:
其他进制到十进制
- 其他进制包含二进制,八进制,十六进制
- 转换规则
- 先把数据的每一位上的系数乘以对应基数的次幂(低位从从零开始),然后相加即可
- 规则:除基取余,直到商为0,最后将余数反转
十进制--->二进制
对于整数部分,用被除数反复除以2,除第一次外,每次除以2均取前一次商的整数部分作被除数并依次记下每次的余数。另外,所得到的商的最后一位余数是所求二进制数的最高位。
对于小数部分,采用连续乘以基数2,并依次取出的整数部分,直至结果的小数部分为0为止。故该法称“乘基取整法”。
最常见的一个十进制,比如:6,如果将它转换成二进制数呢?
10进制数转换成二进制数,这是一个连续除以2的过程:
把要转换的数,除以2,得到商和余数,
将商继续除以2,直到商为0。最后将所有余数倒序排列,得到数就是转换结果。
听起来有些糊涂?结合例子来说明。比如要转换6为二进制数。
“把要转换的数,除以2,得到商和余数”。
那么,结合图片来看:
- 要转换的数是6, 6 ÷ 2,得到商是3,余数是0。
- “将商继续除以2,直到商为0……”现在商是3,还不是0,所以继续除以2。那就: 3 ÷ 2, 得到商是1,余数是1。
- “将商继续除以2,直到商为0……” 现在商是1,还不是0,所以继续除以2。那就: 1 ÷ 2, 得到商是0,余数是1
- “将商继续除以2,直到商为0……最后将所有余数倒序排列”好极!现在商已经是0。
- 我们三次计算依次得到余数分别是:0、1、1,将所有余数倒序排列,那就是:110了!
- 6转换成二进制,结果是110。
public class ToBinary
{
//实现传入一个整数,输出一个二进制的字符串
public static void main (String [] args )
{
System.out.println(toBinaryString (134));
}
public static String toBinaryString(int num)
{
//定义一个字符串缓冲区,储存运算结果
StringBuilder sb = new StringBuilder();
while(num!=0)
{
//当num不等于0是,对num进行除2取模,将结果插入到字符缓冲区的第一位(等于是倒序排位结果)
sb.insert(0,num%2);
num = num>>1;
}
return sb.toString() ;
}
}
运行的结果是:
十进制转换为二进制的步奏就是这样,同理,十进制转换为八进制和十六进制也是类似,下面代码实现了十进制转成其他进制的通用方法:
public class toBinary
{
static char [] ch = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
//实现传入一个整数,输出一个二进制的字符串
public static void main (String [] args )
{
System.out.println(toOtherString (222));
System.out.println(toOtherString (222,6));
System.out.println(toOtherString (222,8));
System.out.println(toOtherString (222,16));
}
public static String toOtherString(int num )
{
return toOtherString(num ,2);
}
public static String toOtherString(int num ,int regex)
{
//定义一个字符串缓冲区,储存运算结果
StringBuilder sb = new StringBuilder();
while(num!=0)
{
//当num不等于0是,对num进行除2取模,将结果插入到字符缓冲区的第一位(等于是倒序排位结果)
//从对应的ch数组中,取出每个数字进制对应的字符,存入字符串缓冲区
sb.insert(0,(char)ch[num%regex]);
num = num/regex;
}
return sb.toString() ;
}
}
运行结果是:
二进制转十进制:
二进制数第0位的权值是2的0次方,第1位的权值是2的1次方……
所以,设有一个二进制数:0110 0100,转换为10进制:
下面是竖式:
0110 0100 换算成十进制
第0位 0 * 20 = 0
第1位 0 * 21 = 0
第2位 1 * 22 = 4
第3位 0 * 23 = 0
第4位 0 * 24 = 0
第5位 1 * 25 = 32
第6位 1 * 26 = 64
第7位 0 * 27 = 0
公式:第N位2(N)
---------------------------
100
用横式计算为:
0 * 20 + 0 * 21 + 1 * 22 + 0 * 23 + 0 * 24 + 1 * 25 + 1* 26 + 0 * 27 = 100
同理的,八进制与十六进制的转换也一样,对应的位数乘以基数的对应位数的n次方,这样比较难理解,下面代码实现了将一个代表十六进制以下的数转换成10进制输出:
class ToShi
{
public static void main(String[] args)
{
//打印不同进制下同一字符串代表的十进制的值
System.out.println(toShi("11111",2));
System.out.println(toShi("11111",8));
System.out.println(toShi("11111",10));
System.out.println(toShi("11111",16));
System.out.println(toShi("A1F11",16));
System.out.println(toShi("A1G11",16));
}
//输入一个数字的字符串形式,并输入注明这个字符串是多少进制的,最后将该字符串代表的数转换为十进制整数返回
public static int toShi(String str,int regex)
{
//定义一个int类型的整数储存结果
int sum = 0 ;
for (int i = str.length()-1,j = 0;i>=0 ;i--,j++ )
{
char c = str.charAt(i);
//判断,如果字母是大于A小于F的,则算出该字母代表的数字的值,然后值乘以进制基数的n次方,n等于该字母在字符串中的倒位位置
if(c >= 'A'&&c <= 'F'&®ex==16)
{
int temp = (int)c -'A' +10;
sum = sum + (int)(temp*Math.pow(regex,j));
}else if (c >= '0'&&c <= '9')
{
int temp = (int)c -'0';
sum = sum + (int)(temp*Math.pow(regex,j));
}else{
throw new RuntimeException("数字不合法,请输入十六进制内的数字");
}
}
return sum;
}
}
运行结果是:
负数的转换
负数在进行转换的时候根据,两个个步骤即可:
- 获取负数的补码形式,补码就是取反加1;
- 按照整数的转换形式进行转换即可。
个人小结:进制转换是比较基础的东西,很多人初学者都会忽视掉,特别是在实际开发中,都是使用Integer的toXXXString来进行快速的转换,更加不需要掌握实际的转换原理。但是我还是那句话,应对面试也好,实操也好。作为一个合格的程序,首先需要的尽可能的知道程序实现的原理,这样在需要开发的时候才会更得心应手。作为初学者,我希望从一开始就能有这样的习惯。