拓展延伸: 實現一個百億級別的計算器

編程題目:

拓展延伸:實現一個百億級別的計算器。

示例代碼:

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;
        
    }
	
}

結果顯示:

在這裏插入圖片描述

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