进制转换在平时的算法练习题或者项目中都会遇到,下面我们来看一下使用java如何进行进制互相转换。
在java函数中,Integer类中已经有相应函数可以进行十进制 与 二进制,八进制和十六进制的转换。
十进制转换其他进制
//十进制转成二进制
Integer.toBinaryString(int i)
//十进制转成八进制
Integer.toOctalString(int i)
//十进制转成十六进制:
Integer.toHexString(int i)
其他进制转换十进制
//二进制转十进制
Integer.valueOf("10111",2).toString()
//八进制转成十进制
Integer.valueOf("188",8).toString()
//十六进制转成十进制
Integer.valueOf("ABC",16).toString()
使用java提供的函数进行进制转换只能进行二进制,八进制,十进制和十六进制间的转换,这可能还不能满足我们的需求,那么如何实现任意进制的转换呢。
可以使用离散数学的模运算来进行进制的转换。具体的计算过程这里就不赘述了,下面是相应代码。
十进制到任意进制的转换:
public static String Dec2Any(int n,int k){
Stack s = new Stack();
String result = "";
int i = 0;
while(n != 0){
s.push(n % k);
n = n / k;
i ++;
}
while(i > 0){
result = result + s.pop();
i--;
}
return result;
}
上面的代码需要注意一个问题,就是把十进制的数转为超过十进制的数字时,需要用相应的多进制表示符号替换。
也可以直接进行运算来获取任意进制到十进制数的转换,代码如下
public static int Any2Dec(String num,int k){
int f=1;
int result = 0;
for (int i=num.length()-1;i>=0;i--)
{
if (num.charAt(i)=='A'||num.charAt(i)=='B'||num.charAt(i)=='C'||num.charAt(i)=='D'||num.charAt(i)=='E'||num.charAt(i)=='F')
{
result = result + f * (num.charAt(i)-'A'+10);
}
else
{
result = result + f * (num.charAt(i)-'0');
}
f = f * k;
}
return result;
}
以前进行进制转换,我也只会想到使用模运算,但是后来通过查看java的Integer中进制转换的源码,发现java内部是使用位运算进行进制转换的。
我们首先看十进制到其他进制的转换,相应函数的源码如下
public static String toBinaryString(int i) {
return toUnsignedString(i, 1);
}
public static String toOctalString(int i) {
return toUnsignedString(i, 3);
}
public static String toHexString(int i) {
return toUnsignedString(i, 4);
}
我们可以看到,内部是通过调用了toUnsignedString(int i)这个函数来实现进制转换的。
final static char[] digits = {
'0' , '1' , '2' , '3' , '4' , '5' ,
'6' , '7' , '8' , '9' , 'a' , 'b' ,
'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
'o' , 'p' , 'q' , 'r' , 's' , 't' ,
'u' , 'v' , 'w' , 'x' , 'y' , 'z'
};
private static String toUnsignedString(int i, int shift) {
char[] buf = new char[32];
int charPos = 32;
int radix = 1 << shift;
int mask = radix - 1;
do {
buf[--charPos] = digits[i & mask];
i >>>= shift;
} while (i != 0);
return new String(buf, charPos, (32 - charPos));
}
因为我对位运算不是很熟悉,因此看起来还是挺有难度的,这里对函数进行一个解析,以十进制转为十六进制toUnsignedString(i, 4)为例。
int radix = 1 << shift这一行,把1左移4位,得到radix为16
int mask = radix - 1得到mask为15,其二进制形式为00001111
buf[--charPos] = digits[i & mask]中,i & mask的目的就是取i的最后4位,然后在digits表单中取到相应的十六进制字符。
i >>>= shift,这一行,抛弃刚处理过的最后4位,往右再推4位,然后进入循环,直到i为0;
所有的十六进制的字符都放在了buf里面,然后组合成一个字符串,返回。
我们可以通过改写这个函数,把十进制的数转换为任意2次方进制的数。
把其他进制转换为十进制时,内部是调用了Integer的parseInt(String s, int radix)方法。代码如下:
public static int parseInt(String s, int radix)
throws NumberFormatException
{
/*
* WARNING: This method may be invoked early during VM initialization
* before IntegerCache is initialized. Care must be taken to not use
* the valueOf method.
*/
if (s == null) {
throw new NumberFormatException("null");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
int multmin;
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}
核心代码是下面这部分
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
通过学习Inreger进制转换方法的实现过程,读者可以自己对其进行改造从而实现自己需要完成的功能。毕竟使用位运算进行进制转换的效率会高一些。