题目大意
在
ALU.java
与FPU.java
中完成除法部分
补码除法
不覆盖reminder的算法,根据PPT上给出的步骤算就好了:
Extend the dividend by adding n bits sign in the front, and store it in the remainder and quotient registers
If dividend has the same sign with divisor, do subtraction; otherwise, do addition
- If the remainder has same sign with divisor, Qn=1; otherwise, Qn= 0
If the remainder has the same sign with divisor , Ri+1=2Ri-Y; otherwise, Ri+1=2Ri+Y
- If the new remainder has the same sign to divisor, set quotient to 1; otherwise, set quotient to 0
Repeat the above step
Left shift quotient, if quotient is negative (the dividend has the different sign with divisor), quotient adds 1
The remainder has the different sign with dividend
- Remainder adds divisor if the dividend has the same sign with divisor, and subtracts divisor otherwise
但是要注意一下这个算法实际上是会留下一个余数的并且这个余数可能会等于除数,所以要进行判断一下,把商加上1或-1(由被除数的符号决定)。
代码如下:
public class ALU {
// 模拟寄存器中的进位标志位
private String CF = "0";
// 模拟寄存器中的溢出标志位
private String OF = "0";
private StringBuilder ans=new StringBuilder();
public static String getComplement(String tar) {
tar = tar.replace("0", "2").replace("1", "0").replace("2", "1");
char[] status = tar.toCharArray();
for (int i = tar.length() - 1, jud = 1; i >= 0; i--) {
status[i] = (char) ((jud ^ (tar.charAt(i) - '0')) + '0');
jud = ((tar.charAt(i) - '0') & jud);
}
return Arrays.toString(status).replaceAll("[\\[\\]\\s,]", "");
}
String add(String src, String dest) {
ans=new StringBuilder();
int c=0,s=0;
for(int i=dest.length()-1;i>=0;i--){
int x=src.charAt(i)-'0',y=dest.charAt(i)-'0';
s=x^y^c;
c=(x&c)|(y&c)|(x&y);
ans.append(s);
}
return ans.reverse().toString();
}
String shift(String src){
return src.substring(1)+"0";
} //特殊的位移一位方法
/**
* 返回两个二进制整数的除法结果 operand1 ÷ operand2
* @param operand1 32-bits
* @param operand2 32-bits
* @return 65-bits overflow + quotient + remainder
*/
String div(String operand1, String operand2) {
if(Pattern.matches("0{32}",operand2)){
if(!Pattern.matches("0{32}",operand1))
throw new ArithmeticException();
else return BinaryIntegers.NaN;
}else if(Pattern.matches("0{32}",operand1)) {
return "0"+BinaryIntegers.ZERO+BinaryIntegers.ZERO;
}
char flag1=operand1.charAt(0);
char flag2=operand2.charAt(0);
String divisor=operand2+"000000000000000000000000000000000"; //divisor=高32位+低32位0+商末尾补充位0
String rev=getComplement(operand2)+"000000000000000000000000000000000";// -divisor=高32位补码+低32位0+商末尾补充位0
String ans=(operand1.charAt(0)=='1'?"11111111111111111111111111111111":"00000000000000000000000000000000")+
operand1+"0"; //高32位符号位+低32位被除数+补充位0
if(flag1==flag2)
ans=add(ans,rev);
else ans=add(ans,divisor);
if(ans.charAt(0)==flag2) {
ans=ans.substring(0,ans.length()-1)+"1";
}
for(int i=0;i<32;i++){
if(ans.charAt(0)==flag2) {
ans=shift(ans);
ans=add(ans,rev);
}else{
ans=shift(ans);
ans=add(ans,divisor);
}
if(ans.charAt(0)==flag2)
ans=ans.substring(0,ans.length()-1)+"1";
}
String quotient=ans.substring(32,65);
String reminder=ans.substring(0,32);
quotient = shift(quotient).substring(0,32);
if(quotient.charAt(0)=='1')
quotient = add(quotient, "00000000000000000000000000000001");
if(reminder.charAt(0)!=flag1) {
if (flag1 == flag2)
reminder = add(reminder, operand2);
else
reminder=add(reminder,getComplement(operand2));
}
if(reminder.equals(getComplement(operand2))){
reminder="00000000000000000000000000000000";
quotient=add(quotient,getComplement("00000000000000000000000000000001"));
}else if(reminder.equals(operand2)) {
reminder="00000000000000000000000000000000";
quotient=add(quotient, "00000000000000000000000000000001");
}
return (flag2!='0'&&flag1==flag2&"ient.charAt(0)==flag1?"1":"0")+quotient+reminder;
}
}
Float除法
暂时不考虑0.significant形式的小数,处理方法类似于乘法,处理指数+截取小数除法的前23位。
要稍微注意一下,这里的除法相当于把小数部分统一成了1.xxxxx/1.xxxxx,那么答案要么是0余若干数,要么是1余若干数,因此我们把返回的商的末位,补到扩充significant时加上的0的个数对应的位数之后。
00001[补充了4个0]+significant+0000[保护位],那么最后截取的应该是:
(quotient.charAt(end-1)+reminder[4...]).substring(indexOf('1')+1,indexOf('1')+24)
如果indexOf('1')不为0,还需要加到ex上。
代码如下:
public class FPU {
/**
* compute the float mul of a / b
*/
String div(String a, String b) {
char flag=a.charAt(0)==b.charAt(0)?'0':'1';
if(Pattern.matches("[01]0{31}",b))
if(Pattern.matches("[01]0{31}",a)) return IEEE754Float.NaN;
else throw new ArithmeticException();
if(Pattern.matches("1{8}0{23}",a.substring(1,a.length()))||Pattern.matches("[01]0{31}",a))
return flag+a.substring(1,a.length());
ALU alu=new ALU();
String ex=alu.add(a.substring(1,9),alu.add(ALU.getComplement(b.substring(1,9)),"01111111"));
String sig=alu.div("00001"+a.substring(9,32)+"0000","00001"+b.substring(9,32)+"0000");
sig=sig.charAt(32)+sig.substring(38);
for(int i=0;i<sig.indexOf('1');i++)
ex=alu.add(ex,"11111111");
return flag+ex+sig.substring(sig.indexOf('1')+1,sig.indexOf('1')+24);
}
}
其实测试样例挺弱的,很简单就过了。