拓展延伸: 实现一个百亿级别的计算器

编程题目:

拓展延伸:实现一个百亿级别的计算器。

示例代码:

package program.calculation.exercise70;

/**
 * 拓展延伸:实现一个百亿级别的计算器。
 */

public class MyBigCalculator {
	public static void main(String[] args) {
		
		String str1 = "123789965783241232323512323676678";  
        String str2 = "23245235435436807768829454365465889"; 
		//String str1 = "0000000000000100000000000000000000000000000000000002";  
        //String str2 = "000000000000050000000000000000000000000000000000000"; 
		//String str1 = "2433456789";  
        //String str2 = "4345678";  
		
		System.out.println("两数之和:"+add(str1, str2));
        System.out.println("两数之差:"+subtract(str1, str2));
        System.out.println("两数之积:"+multiply(str1, str2));
        System.out.println("两数之商:"+divide(str1, str2));
        System.out.println("两数之余:"+remainder(str1, str2));
		
	}
	
	//相加
	private static String add(String str1,String str2){
		
        StringBuffer res = new StringBuffer(); //和(summary)
        
        //根据数字字符串的正负号,决定调用不同的方法
        if(str1.contains("-") && str2.contains("-")){
        	str1 = str1.replace("-", "");
        	str2 = str2.replace("-", "");
            return "-"+add(str1, str2);
        }else if((!str1.contains("-") && str2.contains("-"))){
            return subtract(str1,str2.replace("-", ""));
        }else if((str1.contains("-") && !str2.contains("-"))){
            return subtract(str2,str1.replace("-", ""));
        }
        
        //去除数字字符串前面的0,但注意应先去除正负号
        String s1 = str1.replaceAll("^0*", "");
    	String s2 = str2.replaceAll("^0*", "");
    	
    	//如果两数均为0,则和为0,注意:此时0已被去除,为空白字符串
    	if("".equals(s1) && "".equals(s2)){
    		return "0";
    	}
    	
        //将两个数字的位数设为相同,不同的前面补0
        int len = Math.abs(s1.length()-s2.length());//返回两数相减的绝对值
        if(s1.length() > s2.length()){
            s2 = makeSameFigure(s2,len);
        }else{
            s1 = makeSameFigure(s1,len);
        }
        
        //两数的对应位数依次相加,大于9需要向前进位
        int n = 0; //需要进位的个数
        for(int i=s1.length()-1;i>=0;i--){
        	//通过对应位数的数字字符的ASCII码相减获取数字
            int temp = (s1.charAt(i)-'0')+(s2.charAt(i)-'0')+n;//如果需要进位,则加上进位的个数
            if(i == 0){ //所有位数数字相加结束
            	//temp%10:本位数字,temp/10:进位数字,如果为0,则不进位
                res.append(temp%10).append(temp/10==0?"":temp/10);//注意:此处从前往后添加,输出时倒序输出
            }else{
                res.append(temp%10); //将本位数字添加进结果中
                n = temp/10; //记录进位的个数
            }    
        }
        //去除首位数字0,并将StringBuffer类型的res转换为String类型,注意:输出需要倒序
        return kickFirstZero(String.valueOf(res.reverse()));
        
    }
    
	//相减
    private static String subtract(String str1,String str2){
    	
        boolean flag = false;//判断被减数与减数的大小,false:被减数大于减数
        StringBuffer res = new StringBuffer(); //差(difference)
        
        //根据数字字符串的正负号,决定调用不同的方法
        if(str1.contains("-") && str2.contains("-")){
            return subtract(str2.replace("-", ""),str1.replace("-", ""));
        }else if((!str1.contains("-") && str2.contains("-"))){
            return add(str1,str2.replace("-", ""));
        }else if((str1.contains("-") && !str2.contains("-"))){
            return "-"+add(str2,str1.replace("-", ""));
        }
        
        //去除数字字符串前面的0,但注意应先去除正负号
        String s1 = str1.replaceAll("^0*", "");
    	String s2 = str2.replaceAll("^0*", "");
    	
    	//如果两数相等,差为0,包括两数均为0的情况(其实此时为空白字符串,0已经被去除)
        if(s1.equals(s2)){
    		return "0";
    	}
        
        //如果被减数小于减数,则交换,同时将flag置为true
        if(!isBigger(s1,s2)){
            flag = true;
            String temp = s1;
            s1 = s2;
            s2 = temp;
        }
        
        //将两个数字的位数设为相同,不同的前面补0
        s2 = makeSameFigure( s2,s1.length()-s2.length());
        
        //两数的对应位数依次相减,不够减需要向前借位
        int n = 0; //需要借位的个数
        for(int i=s1.length()-1;i>=0;i--){
        	//通过对应位数的数字字符的ASCII码相减获取数字
        	int temp = (s1.charAt(i)-'0')-(s2.charAt(i)-'0')-n;//再减去借位的个数
        	if(i == 0){ //所有位数数字相减结束
        		//如果最后位数数字为0,则转换为空白字符串
        		res.append(temp==0?"":temp);//注意:此处是从后往前添加的,输出需要倒序
        	}else{
        		//如果位数数字大于等于0,则添加进结果,如果小于0,则需要借位+10,再相减
        		res.append(temp>=0?temp:temp+10); 
        		n = temp>=0?0:1; //记录借位的个数
        	}
            
        }
        //去除首位数字0,并将StringBuffer类型的res转换为String类型,注意:输出需要倒序
        String s = kickFirstZero(String.valueOf(res.reverse()));
        //如果flag=true,说明被减数小于减数,结果应加上负号-,
        return flag?"-"+s:s;
        
    }
    
    //相乘
    private static String multiply(String str1,String str2){
    	
    	String res = ""; //积(product)
    	
    	//判断积(product)的正负号
    	int p = 0; //若p为偶数,积为正数,若p为奇数,积为负数
        if(str1.contains("-")){
            str1 = str1.replace("-", "");
            p++;
        }
        if(str2.contains("-")){
            str2 = str2.replace("-", "");
            p++;
        }
    	
        //去除数字字符串前面的0,但注意应先去除正负号
    	String s1 = str1.replaceAll("^0*", "");
    	String s2 = str2.replaceAll("^0*", "");
    	
    	//如果两数有一个为0,则结果为0,注意:0已经被去除,此处为空白字符串
    	if("".equals(s1) || "".equals(s2)){
    		return "0";
    	}
    	
    	//根据乘法的运算规则:被乘数分别乘以乘数的位数数字,然后再相加
        for(int i=s2.length()-1;i>=0;i--){ //乘数的位数
        	//被乘数乘以乘数的位数数字n,其实也就是本身自加n次
            for(int j=0;j<s2.charAt(i)-'0';j++){ //通过ASCII码相减获取位数数字
                res = add(res,s1); //结果相加
            }
            s1 += "0"; //被乘数每乘以完乘数一个位数数字后,应进位,扩大10倍,字符串直接加0即可
        }
        
        //如果负号为奇数个,即c==1,则结果应为负数,加上"-"
        return p==1?"-"+res:res;
        
    } 
    
    //相除
    private static String divide(String str1,String str2){
    	
    	String res = ""; //商(quotient)
    	
        //判断商的正负号
    	int q = 0; //若q为偶数,商为正数,若q为奇数,商为负数
        if(str1.contains("-")){
            str1 = str1.replace("-", "");
            q++;
        }
        if(str2.contains("-")){
            str2 = str2.replace("-", "");
            q++;
        }
        
        //去除数字字符串前面的0,但注意应先去除正负号
    	String s1 = str1.replaceAll("^0*", "");
    	String s2 = str2.replaceAll("^0*", "");
    	
        //如果除数为0,表达式错误,注意:0已经被去除,此处为空白字符串
        if("".equals(s2)){
            return "ERROR";
        }
        
        //如果被除数绝对值小于除数绝对值,则商为0,或者被除数为0,注意:0已被去除,此处为空白字符串
        if(!isBigger(s1,s2) || "0".equals(s1)){
            return "0";
        }
        
        //如果被除数绝对值等于除数绝对值,则商绝对值为1
        if(s1.equals(s2)){
        	res = "1"; //此处赋值给res,因为要添加正负号
        }else{ //主要处理被除数大于除数的情况
        	//如果被除数的首位数字大于等于除数首位数字,则给被除数补一个零
        	//此种情况如果不给被除数补一个零,则商会少最后一位数
        	//原因:运行下面代码将位数置为相等后,此种情况下,其实被除数相当于少了一位数
            if(s1.charAt(0) >= s2.charAt(0)){
            	s1 += "0";
            }
            //主要处理被除数位数大于除数位数的情况
            for (int n=s1.length()-s2.length();n>0;n--) { //n是s1与s2的位数差
            	
                //除数补零操作,使除数的位数与被除数的位数相等
                while(s1.length() > s2.length()){
                    s2 += "0";
                }
                //如果补零后被除数小于除数,则给被除数补一个零,否则进行下一步运算
                if (!isBigger(s1, s2)) {
                    s1 += "0";
                }
                //循环找出 除数*i(i数0~9之间的数)的结果不大于被除数的最大i值,找到的i即为商的位数值
                for (int i=9;i>=0;i--) { //注意此处应倒序,因为循环找到不大于被除数的最大i值
                    String temp = multiply(s2, String.valueOf(i));
                    if (isBigger(s1, temp)) { //s1大于temp说明此时找到的i即为商的位数值
                        s1 = subtract(s1, temp); //本次循环后的余数,作为下一次循环的被除数
                        res += i; //将i添加到结果上
                        break; //结束本次循环,开始执行下次循环
                    }
                }	
            }    
        }
        //如果负号为奇数个,即c==1,则结果应为负数,加上"-"
        return q==1?"-"+res:res;
    	
    }
    
    //取余
    private static String remainder(String str1,String str2){
    	
        //第一种方式:取余运算:被除数-(商*除数)=余数,该方法比较取巧
        /*String quotient = divide(str1, str2); //获取两数之商
        String product = multiply(quotient, str2); //获取商和除数之积
        String difference = subtract(str1, product); //获取余数
        return difference;*/
        
        //第二种方式:等同于除法,只不过进行了余数判断以及记录除数补0的次数
        String res = ""; //商(quotient)
        String rem = ""; //余数(remainder)
    	
        //判断商(quotient)和余数(remainder)的正负号
    	int q = 0; //若q为偶数,商为正数,若q为奇数,商为负数
    	int r = 0; //若r为偶数,余数为正数,若r为奇数,余数为负数,根据被除数的正负号判断
        if(str1.contains("-")){
            str1 = str1.replace("-", "");
            q++;
            r++;
        }
        if(str2.contains("-")){
            str2 = str2.replace("-", "");
            q++;
        }
        
        //去除数字字符串前面的0,但注意应先去除正负号
    	String s1 = str1.replaceAll("^0*", "");
    	String s2 = str2.replaceAll("^0*", "");
    	
        //如果除数为0,表达式错误,注意:0已经被去除,此处为空白字符串
        if("".equals(s2)){
            return "ERROR";
        }
        
        //如果被除数绝对值小于除数绝对值,则余数为被除数本身
        if(!isBigger(s1,s2)){
            rem = s1; //此处赋值给rem,因为要添加正负号
        }
        
        //记录除数在下面代码中补0的次数
        int count = 0; //除数每补一次0,就会导致余数结尾多一个0
        //如果被除数绝对值等于除数绝对值,则余数为0,或者被除数为0,注意:0已被去除,此处为空白字符串
        if(s1.equals(s2) || "".equals(s1)){
        	return "0";
        }else{ //主要处理被除数大于除数的情况
        	//如果被除数的首位数字大于等于除数首位数字,则给被除数补一个零
        	//此种情况如果不给被除数补一个零,则商会少最后一位数
        	//原因:运行下面代码将位数置为相等后,此种情况下,其实被除数相当于少了一位数
            if(s1.charAt(0) >= s2.charAt(0)){
            	s1 += "0";
            }
            //主要处理被除数位数大于除数位数的情况
            for (int n=s1.length()-s2.length();n>0;n--) { //n是s1与s2的位数差
            	
                //除数补零操作,使除数的位数与被除数的位数相等
                while(s1.length() > s2.length()){
                    s2 += "0";
                    count++; //除数每补一次0,count就加1
                }
                //如果补零后被除数小于除数,则给被除数补一个零,否则进行下一步运算
                if (!isBigger(s1, s2)) {
                    s1 += "0";
                }
                //循环找出 除数*i(i数0~9之间的数)的结果不大于被除数的最大i值,找到的i即为商的位数值
                for (int i=9;i>=0;i--) { //注意此处应倒序,因为循环找到不大于被除数的最大i值
                    String temp = multiply(s2, String.valueOf(i));
                    if (isBigger(s1, temp)) { //s1大于temp说明此时找到的i即为商的位数值
                        s1 = subtract(s1, temp); //本次循环后的余数,作为下一次循环的被除数
                        res += i; //将i添加到结果上
                        break; //结束本次循环,开始执行下次循环
                    }
                }	
            }    
        }
        
        //如果负号为奇数个,即q==1,则结果应为负数,加上"-"
        res = q==1?"-"+res:res; //商
        if("0".equals(s1)){ //如果s1为0,则不再去除多出的0
        	rem = s1;
        }else{
        	rem = s1.substring(0,s1.length()-count);//去除余数后面多出的0
        }
        //如果被除数为负数,即r==1,则结果应为负数,加上"-",注意:如果余数为0,就不需要再加上负号"-"
        return rem=="0"?rem:r==1?"-"+rem:rem;
        
    }
    
    //判断大小
    private static boolean isBigger(String str1,String str2){
        
    	//去除数字字符串前面的正负号和0,但注意应先去除正负号
    	String s1 = str1.replace("-", "").replaceAll("^0*", "");
    	String s2 = str2.replace("-", "").replaceAll("^0*", "");
    	
        if(s1.length() > s2.length()){
            return true;
        }else if(s1.length() < s2.length()){
            return false;
        }else if(s1.length() == s2.length()){
            for(int i=0;i<s1.length();i++){
                if(s1.charAt(i) < s2.charAt(i)){
                    return false;
                }else if(s1.charAt(i) > s2.charAt(i)){
                    return true;
                }
            }
        }
        return true;
        
    }
    
    //将两个数字位数设为相等
    private static String makeSameFigure(String s,int len){
    	
        StringBuffer sb = new StringBuffer();
        for(int i=0;i<len;i++){
            sb.append("0");
        }
        s = String.valueOf(sb.append(s));
        return s; 
        
    }
    
    //去除首位数字0
    private static String kickFirstZero(String s){
    	
        while(s.length() > 1){
            if('0' == s.charAt(0)){
            	//substring(0,index)表示获取下标为0-index(不包括)的元素
                s = s.substring(1); //注意:substring(index)表示去除下标为index的元素
            }else{
                break;
            }
        }
        return s;
        
    }
	
}

结果显示:

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章