1. 程式人生 > >四則運算程序(java基於控制臺)

四則運算程序(java基於控制臺)

ans tail https 個數 題目 OS 但是 展示 mage

一、題目描述:
1. 使用 -n 參數控制生成題目的個數,例如
Myapp.exe -n 10 -o Exercise.txt
將生成10個題目。
2. 使用 -r 參數控制題目中數值(自然數、真分數和真分數分母)的範圍,例如
Myapp.exe -r 10
將生成10以內(不包括10)的四則運算題目。該參數可以設置為1或其他自然數。該參數必須給定,否則程序報錯並給出幫助信息。
3. 生成的題目中如果存在形如e1 ÷ e2的子表達式,那麽其結果應是真分數。
4. 每道題目中出現的運算符個數不超過3個。
5. 程序一次運行生成的題目不能重復,即任何兩道題目不能通過有限次交換+和×左右的算術表達式變換為同一道題目。例如,23 + 45 = 和45 + 23 = 是重復的題目,6 × 8 = 和8 × 6 = 也是重復的題目。3+(2+1)和1+2+3這兩個題目是重復的,由於
+是左結合的,1+2+3等價於(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重復的兩道題,因為1+2+3等價於(1+2)+3,而3+2+1等價於(3+2)+1,它們之間不能通過有限次交換變成同一個題目。
生成的題目存入執行程序的當前目錄下的Exercises.txt文件,格式如下:
1. 四則運算題目1
2. 四則運算題目2
……

        其中真分數在輸入輸出時采用如下格式,真分數五分之三表示為3/5,真分數二又八分之三表示為2’3/8。
    6. 在生成題目的同時,計算出所有題目的答案,並存入執行程序的當前目錄下的Answers.txt文件,格式如下:
            1. 答案1
            2. 答案2

        特別的,真分數的運算如下例所示:1/6 + 1/8 = 7/24。
    7. 程序應能支持一萬道題目的生成。
    8. 程序支持對給定的題目文件和答案文件,判定答案中的對錯並進行數量統計,並會輸出所有題目中重復的題目,輸入參數如下:
         Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt -o Grade.txt

        統計結果輸出到文件Grade.txt,格式如下:

        Correct: 5 (1, 3, 5, 7, 9)
        Wrong: 5 (2, 4, 6, 8, 10)
        Repeat:2
        RepeatDetail:
        (1)   2,45+32  Repeat 3,32+45                    
        (2)   5,3+(2+1)  Repeat 7,1+2+3

二、分析設計
1.生成隨機表達式
需要生成隨機數(整數,分數,帶分數)的函數,隨機運算符的函數,隨機添加括號函數,采用String拼接生成隨機表達式。
2.表達式處理計算
將中綴表達式轉換為後綴表達式,對後綴表達式進行分割處理,通過棧操作進行運算,由於存在分數和帶分數,需通過自定義四則運算法則進行計算,具體為同化成分數進行運算,完成後需約分。
3.表達式查重
先通過讀取答案文檔,掃描相同答案的表達式進行判斷,可提高效率,接著再將相同答案的中綴表達式轉換成後綴表達式,判斷所有元素是否相等。此方法效率較高,但存在局限性。由於本人並不是通過二叉樹處理表達式,再使用二叉樹顯得 很繁瑣,且效率不高。
4.輸出至文檔
需要輸出的文檔有表達式Exercises.txt,答案Answers.txt,成績及查重結果Grade.txt。

三、功能實現

    1.主程序Main.java
        主要代碼:       
    System.out.println("---------------四則運算程序---------------");
    System.out.println("-n:生成題目個數");
    System.out.println("-r:參數數值範圍");
    System.out.println("-g:查看測試結果");
    System.out.println("Do:執行程序");
    System.out.println("請輸入指令:");
    Scanner in =new Scanner(System.in);
    while(in.hasNext()){
        switch(in.next()){
            case "-n" :
                System.out.println("請輸入要生成的題目個數:");
                n=in.nextInt();
                break;
            case "-r":
                System.out.println("請輸入運算數的數值範圍:");
                m=in.nextInt();
                break;
            case "-g":
                fo.FileC(file2, file3, file4);        //答案和做題文檔對比,結果寫入Grade文檔
                break;
            case "Do":
                for(int i=0;i<n;i++){
                    String s=ex.CreatExp(n,m),fstr;   //生成隨機表達式並求解
                    String rus=its.suffixToArithmetic(its.infixToSuffix(s));

                    fstr=i+1+":"+s+"\r\n";            
                    fo.FileW(file1, fstr);            //表達式寫入文檔
                    
                    fstr=i+1+":"+rus+"\r\n";
                    fo.FileW(file2, fstr);            //答案寫入文檔  
                }
                break;
            default:
                System.out.println("無效指令!");
                break;
        }
        System.out.println("請輸入指令:");   


    2.隨機表達式生成
        主要代碼:
        /*隨機生成表達式*/
    public String CreatExp(int n ,int m){
        String exp=CreatNum(m);                          //隨機操作數
        Random rd=new Random();
        int t=rd.nextInt(2);
        boolean flag=false;                              //是否生成括號
        if(t>0)
            flag=Creatkh();
        for(int i=0;i<=t;i++){                           //生成String類型中綴表達式
            if(flag==true){
                if(i==0){
                    exp=exp+CreatChar()+"("+CreatNum(m);
                }else
                {
                    exp=exp+CreatChar()+CreatNum(m)+")";
                }
                    }else{
                exp=exp+CreatChar()+CreatNum(m);
            }
        }
        return exp;
    }

    /*隨機生成操作數*/
    public String CreatNum(int m){
        String s="";
        Random rd=new Random();
        switch(rd.nextInt(2)){                            //隨機類型:整數,分數
            case 0:
                s=Integer.toString(rd.nextInt(m-1)+1);    //整數
                break;
            case 1:                                       //分數
                int a,b;
                a=rd.nextInt(m-1)+1;
                b=rd.nextInt(m-2)+2;
                s=Dating(a,b);                            //分數約分處理
                break;
        }
        return s;
    }

    /*隨機生成運算符*/
    public String CreatChar(){
        String s="";
        Random rd=new Random();
        switch(rd.nextInt(4)){
            case 0:s="+";break;
            case 1:s="-";break;
            case 2:s="*";break;
            case 3:s="÷";break;
        }
        return s;
    }

    /*分數進行約分*/
    public String Dating(int a,int b){
        String s="";
        int gongyinshu=1,c;
        c=a/b;
        a=a%b;
        if(c<0){                                   //若帶分數已為負數,這分數不用帶負號
            a=a*-1;
        }
        for (int i = 1; i <= a; i++) {             //求最小公約數
            if (a % i == 0 && b % i == 0) {  
                gongyinshu = i;  
            }  
        }
        a=a/gongyinshu;                            //生成最簡分數
        b=b/gongyinshu;
        if(a==0){
            s=Integer.toString(c);
        }else if(c==0){
            s=Integer.toString(a)+"/"+Integer.toString(b);
        }else{
            s=Integer.toString(c)+"‘"+Integer.toString(a)+"/"+Integer.toString(b);
        }
        return s;
    }

    /*隨機是否生成括號*/
    public boolean Creatkh(){
        boolean flag=false;
        Random rd=new Random();
        if(rd.nextInt(3)<1)                        //生成擴號的概率為1/3
            flag=true;
        return flag;
    }


    3.表達式處理
        主要代碼:
        /*中綴表達式轉後綴表達式*/
        public String infixToSuffix(String exp) {
            Stack<Character> s = new Stack<Character>();                // 創建操作符堆棧
            String suffix = "";                                         // 要輸出的後綴表達式字符串
            int length = exp.length();                                  // 輸入的中綴表達式的長度
            for (int i = 0; i < length; i++) {
                 char temp;
                 char ch = exp.charAt(i);                               // 獲取該中綴表達式的每一個字符並進行判斷
                 switch (ch) {
                    case ‘(‘:
                        s.push(ch);
                        break;
                    case ‘+‘:                              // 碰到‘+‘ ‘-‘,將棧中的所有運算符全部彈出去,直至碰到左括號為止,輸出到隊列中去
                    case ‘-‘:
                        suffix += " ";
                        while (s.size() != 0) {
                            temp = s.pop();
                            if (temp == ‘(‘) {
                                s.push(‘(‘);
                                break;
                            }
                            suffix += temp;
                            suffix += " ";
                        }
                        s.push(ch);
                        break;
                    case ‘*‘:                               // 如果是乘號或者除號,則彈出所有序列,直到碰到加好、減號、左括號為止,最後將該操作符壓入堆棧
                    case ‘÷‘:
                        suffix += " ";
                        while (s.size() != 0) {
                            temp = s.pop();
                            if (temp == ‘+‘ || temp == ‘-‘ || temp == ‘(‘) {
                                 s.push(temp);
                                 break;
                            } else {
                                 suffix += temp;
                                 suffix += " ";
                           }
                        }
                        s.push(ch);
                        break;
                    case ‘)‘:
                         while (!s.isEmpty()) {
                            temp = s.pop();
                            if (temp == ‘(‘) {
                                     break;
                            } else {
                                    suffix += " ";
                                    suffix += temp;
                            }
                         }
                         break;
                    default:
                         suffix += ch;
                         break;
                 }
            }
            while (s.size() != 0) {                            // 如果堆棧不為空,則把剩余運算符一次彈出,送至輸出序列
                    suffix += " ";
                        suffix += s.pop();
             }
            return suffix;
         }

         /*計算後綴表達式*/
         public String suffixToArithmetic(String exp) {  
             String[] strings = exp.split(" ");                  //按空格分解字符串
             Stack<String> stack = new Stack<String>();          //操作數棧
             for (int i = 0; i < strings.length; i++) {
                 if(strings[i].equals("+")||strings[i].equals("-")||strings[i].equals("*")||strings[i].equals("÷")){
                     String y=stack.pop();                        //讀取到運算符,提取棧頂的兩個操作數,先出的操作數為運算符後的數
                     String x=stack.pop();
                     String rus=calculate(x, y, strings[i]);      //調用自定義的四則運算法則
                     stack.push(rus);                             
                     if(rus.equals("無解"))                       //除數為0返回無解 
                     return rus; 
                     }else{
                         stack.push(strings[i]);
                 }   
             }
             return stack.pop();
         }

        /*自定義四則運算法則*/
         public String calculate(String x, String y, String ch) {
         }
         註:四則運算過程代碼較多,不展示。


    4.文件操作及表達式查重代碼不展示

四、結果展示
命令選擇:
技術分享圖片
表達式文檔:
技術分享圖片
答案文檔:
技術分享圖片
答題文檔:
技術分享圖片
成績文檔:
技術分享圖片
一萬道題測試:
技術分享圖片
技術分享圖片

五、實驗小結
此次編程要點在於表達式的處理,重點是對分數,帶分數的處理,具體解決方法是將其每個部分的整數提取出來,存於幾個參數中,通過參數間的轉化運算達到分數的計算,從而實現表達式的計算。過程中遇到挺多小問題,例如除數為0,6÷(3-3) ,解決方法為計算除法時,進行判斷,如果除數為0直接返回結果“無解”。

六 、PSP表

    PSP2.1  Personal Software Process Stages  Time Senior Student  Time  
    Planning       計劃                           2                   2    
    Estimate    估計這個任務需要多少時間             48                  36  
    Development  開發                            40                  36    
    Analysis      需求分析 (包括學習新技術)          2                   1 
    Design Spec   生成設計文檔                     1                    1  
    Design Review  設計復審                        2                        1    
    Coding Standard 代碼規範                  0                    0     
    Design      具體設計                           3                      4
    Coding      具體編碼                  27                    22   
    Code Review  代碼復審                          2                      1  
    Test       測試(自我測試,修改代碼,提交修改        2                     4  
    Reporting   報告                             1                   2

七、源代碼
碼雲項目地址:https://gitee.com/liangs96_master/FourOperations

四則運算程序(java基於控制臺)