Programming04

题目大意

ALU.javaFPU.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&&quotient.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);
    }

}

其实测试样例挺弱的,很简单就过了。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容