Java的相关文章已经有很多了,很多前辈也分享了很多很多编程经验与技巧。本文是我在学习Java过程中有感而发,代码实现计组的定点整数加减法的过程,希望对读者有帮助。
本课题要求编写一个程序:
① 输入:两个长整数
② 输出:两个数的和、差
③ 使用Java,计算过程要模拟手算64位定点整数加减法的过程,且使用字符数组储存二进制机器数。
技术要点
真值转换为64位补码
要得到补码,首先要能将真值的十进制转换为64位原码,从而得到64位反码,最后得到64位补码。
因此包含以下功能模块:
- 十进制转二进制:使用除2取余法即可。
result[i] = num % 2 == 0 ? '0' : '1';
num /= 2;
- 二进制补全为64位原码:符号位根据正负填充1、0,空位用0填充。
- 64位原码各位取反得到64位反码:用一个循环以及逻辑非。
result[i] = result[i] == '1' ? '0' : '1';
- 64位反码末位加1得到64位补码:开发一个全加器用于末位加1。
temp = FullAdder.getS(result[i], '0', c);
c = FullAdder.getC(result[i], '0', c);
result[i] = temp;
二进制机器码转十六进制
64位的二进制机器数可以说是相当的冗长,不便于开发者进行调试,因此需要开发一个方法将二进制机器码以16进制形式输出在终端上。
按照人工手算二进制转十六进制的方法,每四位划分一组,每组分别计算出一个十六进制数字,并进行字符串累加即可。
final static char[] hexCharacters = "0123456789ABCDEF".toCharArray();
private static String BtoH(char[] chars) {
String result = "0x";
for (int i = 0; i <= 15; i++) {
int tag = 0;
for (int j = 0; j <= 3; j++) {
tag += chars[4 * i + j] == '1' ? Math.pow(2, 3 - j) : 0;
}
result += hexCharacters[tag];
}
return result;
}
一位全加器的实现
在计算机组成原理中,我们学习了一位全加器74LS181的功能与逻辑表达式:
S
i
=
A
i
⊕
B
i
⊕
C
i
C
i
+
1
=
A
i
B
i
+
(
A
i
+
B
i
)
C
i
S_i=A_i\oplus B_i \oplus C_i \\C_{i+1}=A_iB_i+(A_i+B_i)C_i
Si=Ai⊕Bi⊕CiCi+1=AiBi+(Ai+Bi)Ci
因此要得到
S
i
、
C
i
+
1
S_i、C_{i+1}
Si、Ci+1,只需要分别按照两个逻辑表达式分别写两个方法即可。
S i S_i Si:
return x=='1'^y=='1'^c=='1'?'1':'0';
C i + 1 C_{i+1} Ci+1:
return (x=='1'&&y=='1')||((x=='1'||y=='1')&&c=='1')?'1':'0';
模四补码加法
模四补码加法的双符号位使得溢出判断变得简单。
计算完成后,如果双符号位分别为
11或00:未溢出
10:下溢出
01:上溢出
由于使用了大小为64的字符数组,因此要实现双符号位,只需要额外再声明一个syn变量作为最高位符号位即可。判断溢出的时候,只需要将syn与字符数组的最高位进行比较、判断。
char syn = FullAdder.getS(xChar[0], yChar[0], c);
//00或11
if (result[0] == syn) {
System.out.println("结果未溢出\n");
}
//10
else if (syn == '1')
System.out.println("结果下溢出\n");
//01
else
System.out.println("结果上溢出\n");
64位补码转换为十进制真值
补码加法得到的结果为一个补码,要将补码先转换为原码,再将原码转换为真值。
补码转原码,已经实现了,只需要套用原码转补码的方法就可以,一个字都不用改。
原码转真值,只需要按位乘以权重,再进行累加即可。
num += result[i] == '1' ? Math.pow(2, 63 - i) : 0;
代码实现
一位全加器的实现
FullAdder.java
public class FullAdder {
public static char getS(char x,char y,char c){
return x=='1'^y=='1'^c=='1'?'1':'0';
}//得到Si
public static char getS(char x,char y){
return getS(x,y,'0');
}
public static char getC(char x,char y,char c){
return (x=='1'&&y=='1')||((x=='1'||y=='1')&&c=='1')?'1':'0';
}//得到进位位Ci
public static char getC(char x,char y){
return getC(x,y,'0');
}
}
转换、计算功能的实现
public class BinaryComputing {
final static char[] hexCharacters = "0123456789ABCDEF".toCharArray();
//二进制转十六进制
private static String BtoH(char[] chars) {
String result = "0x";
for (int i = 0; i <= 15; i++) {
int tag = 0;
for (int j = 0; j <= 3; j++) {
tag += chars[4 * i + j] == '1' ? Math.pow(2, 3 - j) : 0;
}
result += hexCharacters[tag];
}
return result;
}
//输入十进制真值得到原码的二进制形式
private static char[] getTrueFormBinary(long num) {
char[] result = new char[64];
//符号位
result[0] = num >= 0 ? '0' : '1';
if (num < 0) num = -num;
//除2取余
for (int i = 63; i > 0; i--) {
result[i] = num % 2 == 0 ? '0' : '1';
num /= 2;
}
return result;
}
//输入十进制真值得到补码的二进制形式
private static char[] getCompletionFormBinary(long num) {
char[] result = getTrueFormBinary(num);
return getCompletionFormBinary(result);
}
//输入十进制真值得到补码的二进制形式
private static char[] getCompletionFormBinary(char[] result) {
//原码为正数时,无需操作
if (result[0] == '0') return result;
//按位取反得到反码
for (int i = 1; i < 64; i++) {
result[i] = result[i] == '1' ? '0' : '1';
}
//使用一位全加器进行末位加1操作
char c = '1', temp;
for (int i = 63; i > 0; i--) {
temp = FullAdder.getS(result[i], '0', c);
c = FullAdder.getC(result[i], '0', c);
result[i] = temp;
if (c == '0') break;
}
return result;
}
//输入二进制原码得到十进制真值
public static long trueFormToNum(char[] result) {
long num = 0;
for (int i = 1; i < 64; i++) {
num += result[i] == '1' ? Math.pow(2, 63 - i) : 0;
}
return result[0] == '0' ? num : -num;
}
//输入二进制补码得到十进制真值
public static long completionFormToNum(char[] result) {
result = getCompletionFormBinary(result);
return trueFormToNum(result);
}
//输入十进制真值得到十六进制原码
public static String getTrueFormHex(long num) {
return BtoH(getTrueFormBinary(num));
}
//输入十进制真值得到十六进制补码
public static String getCompletionFormHex(long num) {
return BtoH(getCompletionFormBinary(num));
}
//加法器
public static long adder(long x, long y) {
char[] xChar = getCompletionFormBinary(x), yChar = getCompletionFormBinary(y);
char[] result = new char[64];
System.out.println("转换得到x补码为" + BtoH(xChar) + "\n");
System.out.println("转换得到y补码为" + BtoH(yChar) + "\n");
char c = '0';
for (int i = 63; i >= 0; i--) {
//利用一位全加器进行串行加法计算
result[i] = FullAdder.getS(xChar[i], yChar[i], c);
c = FullAdder.getC(xChar[i], yChar[i], c);
}
//声明syn变量作为拓展符号位
char syn = FullAdder.getS(xChar[0], yChar[0], c);
//判断溢出情况
if (result[0] == syn) {
System.out.println("结果未溢出\n");
}
else if (syn == '1')
System.out.println("结果下溢出\n");
else
System.out.println("结果上溢出\n");
System.out.println("结果的补码(16进制)为:" + BtoH(result) + "\n");
//补码转真值
return completionFormToNum(result);
}
//减法器:x-y=x+(-y)
public static long subtractor(long x,long y){
return adder(x,-y);
}
}
测试样例
Test1.java
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String scIn;
long a, b;
System.out.println("请输入x、y:\n");
a = sc.nextLong();
b = sc.nextLong();
System.out.println("\nx+y:\n");
System.out.println("结果为"+BinaryComputing.adder(a, b)+"\n");
System.out.println("\nx-y:\n");
System.out.println("结果为"+BinaryComputing.subtractor(a, b)+"\n");
}
}
输入
-23 59
输出
请输入x、y:
-23 59
x+y:
转换得到x补码为0xFFFFFFFFFFFFFFE9
转换得到y补码为0x000000000000003B
结果未溢出
结果的补码(16进制)为:0x0000000000000024
结果为36
x-y:
转换得到x补码为0xFFFFFFFFFFFFFFE9
转换得到y补码为0xFFFFFFFFFFFFFFC5
结果未溢出
结果的补码(16进制)为:0xFFFFFFFFFFFFFFAE
结果为-82
希望对读者有所帮助