最近在看Java jdk的源码,源码里会用到许多二进制的运算,因此会使用到十进制转二进制的工具。心血来潮想自己实现一个简单的转换工具,心动不如行动,let'go !
温馨提示:文中的代码实现并未考虑性能以及内存消耗,仅跟着思路随手写下,并伴有少许拼音变量名。
正的十进制转二进制比较简单,首先理清楚手算十进制时的过程(原谅我是个灵魂画手):
从这个计算过程得出:输入的正数除以2,依次记录余数,最终把余数按照倒序(从下往上)拼接在一起即得到结果,5(十进制)=101(二进制)。代码实现:
import java.util.Stack;
public class CalService {
private Stack stack = new Stack();
/**
* 十进制转二进制
*
* @param tenNum 十进制数
* @return 转换的二进制结果
*/
public String ten2Two(Integer tenNum) {
StringBuilder sb = new StringBuilder();
cal(tenNum);
//输出栈的所有内容得到结果
while (!stack.empty()) {
sb.append(stack.pop().toString());
}
}
private void cal(Integer tenNum) {
//除2取商
Integer quotient = tenNum / 2;
//除2取余,把余数放入栈中
stack.push(tenNum % 2);
//如果余数大于1继续计算,否则计算结束
if (quotient > 1) {
//递归计算
cal(quotient);
} else {
stack.push(quotient);
return;
}
}
}
PS:由于最后需要把余数按照倒序进行拼接,即先入后出,第一个想到的就是使用栈来存放。
负的十进制转二进制会相对复杂一些,概括起来就是其原码的补码。以 -5 来举例:
第一步:计算该负数绝对值的二进制,也就是其正数的原码:
5的原码 101
第二步:int值最多为32位,最高位用于表示正负,正为0,负为1。因此把101的最高位置1,其余位补0,得到负数的原码:
-5的原码 10000000 00000000 00000000 00000101
第三步:计算负数原码的反码。正数的反码与原码相同,负数的反码为原码除符号位(最高位的1)外,其余取反:
-5的反码 11111111 11111111 11111111 11111010
第四步:计算负数原码的补码。正数的补码与原码相同,负数的补码为反码加1(这也是为什么我们要先算其反码)。
-5的补码 11111111 11111111 11111111 11111011
最终得到-5(十进制)=11111111 11111111 11111111 11111011(二进制)。
上述过程中,蓝色内容就是需要实现的代码逻辑,代码如下:
import java.util.Stack;
/**
* 十进制转二进制,正、负数均可
*/
public class CalService {
private Stack stack = new Stack();
/**
* 十进制转二进制
*
* @param tenNum 十进制数
* @return 转换的二进制结果
*/
public String ten2Two(Integer tenNum) {
StringBuilder sb = new StringBuilder();
//正数转二进制
if (tenNum > 0) {
cal(tenNum);
while (!stack.empty()) {
sb.append(stack.pop().toString());
}
return sb.toString();
} else {//负数转二进制
//计算该负数绝对值的二进制
tenNum = -tenNum;
cal(tenNum);
//判断需要补0的个数
int buZeroCount = 31 - stack.size();
//最高位置1,其余位补0,得到负数的原码
StringBuilder newSb = new StringBuilder();
newSb.append("1");
//int最多32位,空的位置补0,加上最高位为1表示负数,补满32位
for (int i = 0; i < buZeroCount; i++) {
newSb.append("0");
}
while (!stack.empty()) {
newSb.append(stack.pop().toString());
}
//计算反码,原码除符号位(最高位的1)外,其余取反
String[] bits = newSb.toString().split("");
for (int i = 1; i < 32; i++) {
String bit = bits[i];
if (bit.equals("0")) bits[i] = "1";
else bits[i] = "0";
}
//反码加1
for (int i = 31; i > 0; i--) {
String bit = bits[i];
if (bit.equals("0")) {
bits[i] = "1";
break;
} else {
bits[i] = "0";
}
}
StringBuilder resultSb = new StringBuilder();
//输出结果
for (int i = 0; i < 32; i++) {
resultSb.append(bits[i]);
}
return resultSb.toString();
}
}
private void cal(Integer tenNum) {
Integer quotient = tenNum / 2;
stack.push(tenNum % 2);
if (quotient > 1) {
cal(quotient);
} else {
stack.push(quotient);
return;
}
}
}
为了方便测试,再写一个main方法作为入口:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class main {
public static void main(String[] arg) throws IOException {
System.out.print("请输入要转换为二进制的十进制数:");
CalService calService = new CalService();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = br.readLine()) != null) {
System.out.println(calService.ten2Two(Integer.valueOf(line)));
System.out.print("请输入要转换为二进制的十进制数:");
}
}
}
输出: