Java 十进制和各进制之间相互转换
话不多说,先上代码
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
public class NumberBaseUtil {
public static void main(String[] args) {
NumberBaseUtil nb = new NumberBaseUtil();
long number = NumberBaseUtil.toDecimal("1110", 2);
System.out.println(number);
System.out.println(NumberBaseUtil.toOtherBase(15, 2));
}
// number字符数组
public static final char[] NUMBER = {'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'};
/**
* 输入任意进制转化为10进制
* @param value 数值
* @param numberBase 进制 2~36
* @return long
* @Author xiangyuan.liu
* @Title toDecimal
*/
public static long toDecimal(String value, int numberBase) {
// 将数值中开头的0去掉并全部转成大写
value = value.replaceAll("^(0+)", "").toUpperCase();
// 初始化map,将字符数组中的按索引存入map,字符相当于key, value相当于十进制的值
int LEN = NUMBER.length;
Map<Character, Integer> numberMap = new HashMap<>(LEN);
for (int i = 0; i < LEN; i++) {
numberMap.put(NUMBER[i], i);
}
// 数值转为字符数组
char[] sh = value.toCharArray();
int len = sh.length;
// 位数
int n = 0;
long sum = 0;
for (char item : sh) {
// 从后位往前加
// 根据公式 S = x ** y * z (x代表进制,y代表位数,z代表该位上的值)
sum += (numberMap.get(item)) * Math.pow(numberBase, len - (n++) - 1);
}
return sum;
}
/**
* 10进制转任意进制
* @param value 10进制数值
* @param base 目标进制
* @return java.lang.String
* @Author xiangyuan.liu
* @Title toOtherBase
*/
public static String toOtherBase(long value, int base) {
StringBuilder str = new StringBuilder();
Stack<Character> stack = new Stack<>();
while (value != 0) {
stack.push(NUMBER[(int) (value % base)]);
value /= base;
}
while (!stack.isEmpty()) {
str.append(stack.pop());
}
return str.toString();
}
}
测试执行结果,转换正确。
有些缺陷就是,不能超过long的范围长度而且不支持小数,改进方法就是用BigDecimal类代替long类型。
原理
各进制转10进制
根据公式S = x ** y * z
x代表进制,y代表位数(y从右边开始为0),z代表该位上的值,然后将各个位算出的S累加起来
例如8进制转10进制:
八进制 30102, 则x=8,y分别为0,2,4;z为3,1,2
转换为十进制为:
8 ** 0 * 2 + 8 ** 2 * 1 + 8 ** 4 * 3 = 12354
2 + 64 + 12,288 = 12354
sum += (numberMap.get(item)) * Math.pow(numberBase, len - (n++) - 1);
从map中取出的相当于10进制的值z, 然后从右边开始乘于进制的位数次方,累加起来就可以得到10进制的值。
public static long toDecimal(String value, int numberBase) {
// 将数值中开头的0去掉并全部转成大写
value = value.replaceAll("^(0+)", "").toUpperCase();
// 初始化map,将字符数组中的按索引存入map,字符相当于key, value相当于十进制的值
int LEN = NUMBER.length;
Map<Character, Integer> numberMap = new HashMap<>(LEN);
for (int i = 0; i < LEN; i++) {
numberMap.put(NUMBER[i], i);
}
// 数值转为字符数组
char[] sh = value.toCharArray();
int len = sh.length;
// 位数
int n = 0;
long sum = 0;
for (char item : sh) {
// 从后位往前加
// 根据公式 S = x ** y * z (x代表进制,y代表位数,z代表该位上的值)
sum += (numberMap.get(item)) * Math.pow(numberBase, len - (n++) - 1);
}
return sum;
}
10进制转各进制
将10进制转换成各进制就是一个连续除以各进制的过程
把要转换的数,除以各进制,得到商和余数 ,商取整数,然后将商继续除以各进制,直到商为0。最后将所有余数倒序排列,得到的数就是转换结果。
例如10进制转8进制:
十进制 20
第一轮:
余数 : 20 % 8 = 4 ---> 存入栈
商: 20 / 8 ≈ 2
第二轮:
余数 :2 % 8 = 2 ---> 存入栈
商: 2 / 8 ≈ 0
最后就可以得到 20 的 8 进制数 为 24
这里用了栈的先进后出的特性,最后再循环将栈顶弹出
public static String toOtherBase(long value, int base) { //base为目标进制
StringBuilder str = new StringBuilder(); // 进制大于十 会有字母,所以用字符串
Stack<Character> stack = new Stack<>();
while (value != 0) { // 一直除以目标进制,直到value为0
stack.push(NUMBER[(int) (value % base)]); // 求余数
value /= base; // 求商
}
while (!stack.isEmpty()) { // 弹出栈顶元素。
str.append(stack.pop());
}
return str.toString();
}