1. 程式人生 > >2016011990小學四則運算練習軟件項目報告

2016011990小學四則運算練習軟件項目報告

相對路徑 4.5 編碼 cells 路徑 思想 技術 i++ 工作量

小學四則運算練習軟件項目報告

項目克隆地址:https://git.coding.net/chenf640/workhome2_2.git

目錄:

一、需求分析

二、功能設計

三、設計實現

四、算法詳解

五、測試運行

六、代碼展示

七、psp

八、總結

——————————————————————————————————————————————————

一、需求分析

(一)功能需求

基本功能:

  • 程序可接收一個輸入參數n,然後隨機產生n道加減乘除(分別使用符號+-*÷來表示)練習題。
  • 每個數字在 0 和 100 之間,運算符在3個到5個之間;
  • 每個練習題至少要包含2種運算符;
  • 所出的練習題在運算過程中不得出現負數與非整數,比如3÷5+2=2.6,2-5+10=7等是不合法的;
  • 練習題生成好後,將你的學號與生成的n道練習題及其對應的正確答案輸出到文件“result.txt”中,不要輸出額外信息,文件目錄與程序目錄一致;
  • 當程序接收的參數為4時,以下為一個輸出文件示例。

2018010203

13+17-1=29

11*15-5=160

3+10+4-16=1

15÷5+3-2=4

擴展功能

  • 支持有括號的運算式,包括出題與求解正確答案。
  • 擴展程序功能支持真分數的出題與運算(只需要涵蓋加減法即可),例如:1/6 + 1/8 + 2/3= 23/24。註意在實現本功能時,需支持運算時分數的自動化簡,比如 1/2+1/6=2/3,而非4/6,且計算過程中與結果都須為真分數。

(二)程序需求

1、只能使用Java語言。

2、生成文件時請使用相對路徑,生成的txt 文件需在項目的根目錄下,可直接查看演示示例。

3、使用的JDK版本為 jdk8u161,使用的JRE版本為jre8u161。

4、不得使用除限定版本jdk與jre外的額外依賴包。

二、功能設計

(一)基本功能

1、保證輸入的是數字或者特定字符,如果不符合要求,會有提示,並且可以重新輸入。

2、當輸入一個參數n,隨機產生n道加減乘除算術題。保證生成的每個練習題至少要包含2種運算符。且保證在算數過程中,不出現負數,和小數。

3、將生成的n道練習題及其對應的正確答案輸出到文件“result.txt”中,不要輸出額外信息,文件目錄與程序目錄一致;

4、為保證隨機產生的四則運算更滿足用戶的需求,當輸入參數n決定產生四則運算的個數時,另外輸入一個參數m,決定產生的n道四則運算包含運算符的個數(3、4、5)

(二)擴展功能

1、保證生成的分數運算,在運算過程中不產生假分數。並且實現自動化簡。

2、產生帶有括號的運算式時保證不產生沒有意義的括號。

三、設計實現

該程序我的設計思想是一個類實現一個功能,提高代碼的重用性,減少冗雜度。讓代碼更清晰。

技術分享圖片

(一)Main類

功能:是主函數,包含 public static void main(String[] args) 方法。並且包含判斷 輸入的參數是否為整數的 函數,如果不是函數,可提示用戶重新輸入。

目的:確保用戶輸入滿足要求的整數的參數(產生四則運算數量1-1000,每個四則運算包含運算符3-5)

(二)Algorithm類

功能:產生符合要求的一個四則運算,不產生括號。該類中包含一個 帶參的返回類型為字符串的函數。該函數參數為產生四則運算中包含的符號個數,可以產生包含任意多符號數量的四則運算,在該函數中,為滿足用戶需求,運算符數量可以為三、四、五,即該函數參數可以為3、4、5。

目的:產生滿足用戶需求的四則運算。(包含的參數個數、在運算過程中不能產生負數、小數)

關系:公有類,可直接調用。

(三)BracketsAlgo類

功能:產生符合要求的帶有括號的四則運算該類中包含一個 帶參的返回類型為字符串的函數。該函數參數為產生四則運算中包含的符號個數,可以產生包含任意多符號數量的四則運算,在該函數中,為滿足用戶需求,運算符數量可以為三、四、五,即該函數參數可以為3、4、5。

目的:產生括號,增大運算難度。

(四)Fraction類

功能:生成分數運算,保證在運算過程中不產生假分數。並且實現自動化簡。該函數參數為產生四則運算中包含的符號個數,可以產生包含任意多符號數量的四則運算,在該函數中,為滿足用戶需求,運算符數量可以為三、四、五,即該函數參數可以為3、4、5。

目的:練習分數運算。

(五)CreatFile類

功能:生成規定數量的四則運算,並將運算式與結果輸出到result.txt文件中。該類中包含一個帶參無返回的函數,該函數參數為要打印四則運算的數量。
目的:將符合要求的四則運算輸出到txt文件中,方便保留與查看。
關系:公有類,可直接調用。

(六)Symbol類

功能:將產生的代表運算符的數字轉換為對應的運算符。(0代表“+”,1代表“-”,2代表“*”,3代表“÷”)
目的:輸出符合規範的運算符

(七)Test測試類

功能:測試方法。

四、算法詳解(具體代碼分析)

(一)重要算法

1.Algorithm類中的Algorithm算法

算法功能:產生,符合要求的四則運算(運算過程中不產生負數、小數,每個四則運算至少包括兩種運算符)

算法思想

1.1.判斷產生的運算符不完全相等(至少包括兩種)。

  • 用while循環,如果隨機產生的數字完全相等,則一直循環,直到不完全一致。
  • 用數字0-3分別代表運算符的加減乘除,將隨機生成的數字進行比較,如果四個數字完全相等,則重新生成,最終將滿足要求的代表運算符的數字存到數組中。

1.2.運算符之間優先級比較。

  • 將運算符從前到後兩兩比較,先計算優先級高的運算符,先乘除後加減,同級運算符從左向右依次計算。
  • 通過運算符兩兩比較,每循環一次就將生成的結果代替原來的數字,循環結束後,最終的結果會放到數組的最後一位。在計算過程中判斷是否產生負數、是否產生小數,是否除數為0等,如果產生不滿足要求的運算式,則舍去,重新開始。

以一次循環為例:這是不完整的流程圖,只包含其中一部分情況。

技術分享圖片

技術分享圖片

1.3 .產生包含任意多運算符的四則運算。

  • 只需改變循環的次數

1.4.將生成的正確的四則運算和結果放到一個字符串中,返回該字符串給 CreatFilel類中的寫入文件方法。

  • 為了避免在比較優先級的循環中,改變存放數組與運算符的數組,因此,在進行循環判斷前,將運算數與運算符交錯放到數組中,如果通過驗證證明該四則運算符合要求,則返回給 CreatFilel類中的寫入文件方法,寫入result.txt文件。
  • 在輸出時,用for進行判斷,如果是運算數子部分則直接輸出,如果是運算符部分,則將數字轉化為對應的運算符號進行輸出。

如圖所示:

技術分享圖片

2.CreatFile中的creatFile將生成結果寫入指定文件

  • 將返回的字符串寫入指定路徑下的result.txt文件中,並在該文件第一行輸出學號。
  • 該算法比較簡單,需要導入java.io這個jar包。
  • 通過main方法調用,傳入兩個參數,生成算法的數量和每個算法包含的運算符數量。

3.Fraction類中的fractionArithmetic算法

算法功能:生成符合要求的分數運算式。

算法實現:

  • 隨機產生隨機數字(0、1)來代表運算符(+、-)
  • 隨機產生兩個數字,一個做分母、一個做分子(不能為0)。在運算過程中,不斷判斷產生的分數是否大於等於一、並不斷將分數進行化簡。

(二)其他算法

1.Symbol方法中的symbol算法

算法思想:輸出運算符時,將數字與字符一一對應。用switch()語句即可完成。

2.驗證輸入的為符合要求的整數(包括生成四則運算的數量、生成的四則運算中包含運算符的數量)

算法思想:將輸入的內容進行驗證,先驗證是否為整數,如果是整數,再驗證該整數是否符合要求。若不符合要求,則對用戶進行提示,要求重新輸入

在命令行結果如下:

技術分享圖片

3.BracketsAlgo類中的bracketsAlgo算法

算法功能:產生帶有括號的符合要求的四則運算

算法實現:

  • 將隨機生成的運算符從左向右兩兩比較。如果前面的優先級高,則進行運算,保存結果;如果前面運算符的優先級低,則加上括號。
  • 該算法一定是從左向右依次運算。

缺點:該算法可以生成帶有括號的四則運算,但產生括號的數量不能確定。

五、測試運行

為了更好地實現用戶的要求,在運行代碼時需要輸入你要打印的題目的具體數量、包含運算符的具體數量、以及是否有括號、是否是分數運算等參數。

1.進入src文件夾;

2.在命令行輸入javac -encoding utf-8 Main.java;

3.回車再輸入java Main 20;

4回車.輸入你要打印的題目數量;

5回車.輸入你要打印的題目所帶符號的數量;

6.回車.輸入你要打印的題目的類型(y-分數運算;n- 整數運算);

7.如果輸入的是y,回車.result.txt文件生成,分數運算式寫入result.txt文件(如圖一,結果對應圖三)。

如果輸入的是n,回車選擇產生的算式是否包括括號(y--包括;n--不包括,回車.result.txt文件生成,對應的運算式寫入result.txt文件(如圖二,結果對應圖四)。

 圖一技術分享圖片  圖二技術分享圖片
運算結果:

圖三技術分享圖片 圖四技術分享圖片

六、代碼展示:

Algorithm類中的Algorithm算法:

       /* 將運算符從前到後兩兩比較,先計算優先級高的運算符,先乘除後加減,同級運算符從左向右依次計算
              在計算過程中判斷是否產生負數、是否產生小數,是否除數為0等,如果產生不滿足要求的運算式,
              則舍去,如果符合要求,則打印出來。
             */
            for (int i = 0; i < m.length; i++) {
                if ((m1[i] < m1[i + 1]) && (m1[i + 1] == 2)) {
                /* 包含情況為 0<2;1<2 計算優先級高的(乘法) 區域運算,並將結果放到 存放數字的數組中,運算過的運算符也被取代*/
                    num[i + 2] = num[i + 1] * num[i + 2];
                    num[i + 1] = num[i];
                    m1[i + 1] = m1[i];
                    number++;
                } else if ((m1[i] < m1[i + 1]) && m1[i + 1] == 3 && m1[i] != 2) {
                /* 包含情況為 0<3;1<3計算優先級高的(除法) 區域運算,並將結果放到 存放數字的數組中,運算過的運算符也被取代*/
                    if (num[i + 2] != 0) {              //首先除數不能為0
                        int a = num[i + 1] % num[i + 2];  //是否整除
                        if (a == 0) {                  //如果整除,進行除法運算
                            num[i + 2] = num[i + 1] / num[i + 2];
                            num[i + 1] = num[i];
                            m1[i + 1] = m1[i];
                            number++;
                        } else {                     //如果不能整除,重新進行四則運算的產生
                            number = 0;
                            for (int k = 0; k < m.length; k++) {
                                m[k] = 0;
                            }
                            break;
                        }
                    } else {                       //除數為0,重新進行四則運算的產生
                        number = 0;
                        for (int k = 0; k < m.length; k++) {
                            m[k] = 0;
                        }
                        break;
                    }
                } else if (m1[i] == 2 && m1[i + 1] == 3) {
                 /* 包含情況為 2<3計算從左向右進行,並將結果放到 存放數字的數組中*/
                    m[i + 1] = m[i] * m[i + 1];
                    number++;
                } else if ((m1[i] < m1[i + 1]) && (m1[i + 1] == 1)) {
                 /* 包含情況為 0<1  計算從左向右進行,並將結果放到 存放數字的數組中*/
                    m[i + 1] = m[i] + m[i + 1];
                    number++;
                } else if ((m1[i] > m1[i + 1]) && m1[i] == 3) {
                /* 包含情況為 3>2;3>1;3>0  計算從左向右進行,並將結果放到 存放數字的數組中*/
                    if (num[i + 1] != 0) {              //被除數不能為0
                        int a = num[i] % num[i + 1];
                        if (a == 0) {                 //能夠整除
                            num[i + 1] = num[i] / num[i + 1];
                            number++;
                        } else {
                            number = 0;
                            for (int k = 0; k < m.length; k++) {
                                m[k] = 0;
                            }
                            break;
                        }
                    } else {                      //被除數為0
                        number = 0;
                        for (int k = 0; k < m.length; k++) {
                            m[k] = 0;
                        }
                        break;
                    }
                } else if ((m1[i] > m1[i + 1]) && m1[i] == 2) {
                /* 包含情況為 2>1;1>0  計算從左向右進行,並將結果放到 存放數字的數組中*/
                    num[i + 1] = num[i] * num[i + 1];
                    number++;
                } else if ((m1[i] > m1[i + 1]) && m1[i] == 1) {
                /* 包含情況為 1>0  計算從左向右進行,並將結果放到 存放數字的數組中*/
                    if (num[i] > num[i + 1]) {     //是否產生負數
                        num[i + 1] = num[i] - num[i + 1];
                        number++;
                    } else {
                        number = 0;
                        for (int k = 0; k < m.length; k++) {
                            m[k] = 0;
                        }
                        break;
                    }
                } else {
                /* 包括情況為0==0;1==1;2==2  3==3*/
                    if (m1[i] == m1[i + 1]) {
                        if (m1[i] == 0) {       //加法
                            num[i + 1] = num[i] + num[i + 1];
                            number++;
                        } else if (m1[i] == 1) {  //減法,判斷是否產生負數
                            if (num[i] > num[i + 1]) {
                                num[i + 1] = num[i] - num[i + 1];
                            } else {
                                number = 0;
                                for (int k = 0; k < m.length; k++) {
                                    m[k] = 0;
                                }
                                break;
                            }
                        } else if (m1[i] == 2) {    //乘法
                            num[i + 1] = num[i] * num[i + 1];
                            number++;
                        } else {                //除法運算,判斷除數不能為0,不能產生小數
                            if (num[i + 1] != 0) {
                                int a = num[i] % num[i + 1];
                                if (a == 0) {
                                    num[i + 1] = num[i] / num[i + 1];
                                    number++;
                                } else {
                                    for (int k = 0; k < m.length; k++) {
                                        m[k] = 0;
                                    }
                                    number = 0;
                                    break;
                                }
                            } else {
                                for (int k = 0; k < m.length; k++) {
                                    m[k] = 0;
                                }
                                number = 0;
                                break;
                            }
                        }
                    }
                }
            }

2.判斷你要打印的題目數量的個數是否為整數

以打印題目數量為例:

     /**
     * 判斷 輸入你要打印的題目數量的個數是否為整數
     * @return
     */
    public static int numberTest() {
        Scanner input = new Scanner(System.in);
        int number =0;
        while(number<1||number>1000){
            System.out.print("請輸入你要打印的題目數量 (1-1000):");
            String s = input.next();
            while (!(s != null && s.matches("^[0.0-9.0]+$"))) {// [0-9]沒辦法識別小數,[0.0-9.0]可以識別小數和整數
                System.out.print("請輸入正確的題目數量,類型為整數 (1-1000):");
                s = input.next();
            }
            number = Integer.parseInt((s));
        }
        return number;
    }

七、psp:

本次編碼並沒有嚴格計算時間,剛開始也沒有預測所有用到的時間,下表所填的時間是估計的,可能不是很準確,下次再做作業時會更加準確的記錄時間。

PSP2.1

任務內容

計劃共完成需要的時間(min)

實際完成需要的時間(min)

Planning

計劃

20

· Estimate

· 估計這個任務需要多少時間,並規劃大致工作步驟

20

Development

開發

15*60

27*60

· Analysis

· 需求分析 (包括學習新技術)

60

· Coding Standard

· 代碼規範 (為目前的開發制定合適的規範)

30

· Design

· 具體設計

60

· Coding

· 具體編碼

14.5*60

· Code Review

· 代碼復審

60

· Test

· 測試(自我測試,修改代碼,提交修改)

9*60

Reporting

報告

6.5*60

· Size Measurement

· 計算工作量

10

· Postmortem & Process Improvement Plan

· 事後總結, 並提出過程改進計劃

20

寫博客

6*60

八、總結:

(一)實現軟件的‘模塊化‘原則:

  • 對功能進行分析,並分解成若幹子任務,每個函數只實現一種功能,並將一類功能放到一個類中。通過函數之間的調用來實現所有功能。
  • 避免代碼冗雜,提高代碼的重用性跟規範性。

(二)缺點:

雖然實現了作業的基本要求和附加要求,但關於附加功能的第一條完成得不是很好,雖然不會產生無意義的括號,如 (3*4)*5,但是因為符號的產生是隨機的 ,所以很難保證括號的數量。而且,自己的代碼還是過於冗雜,還有待提高。

(三)優點:

  • 除了附加一的一些問題,本作業的其他要求都以實現。
  • 代碼書寫規範
  • 有詳細地註釋
  • 雖是一個基本功能,但是我用了三種方法去寫(從剛開始最復雜的多重循環(Arithmetic3類中的Arithmetic_test()方法到邏輯更加嚴謹的算法(Algorithm類中的algorithm()方法再到最後更加簡潔的(BracketAlgo類中的bracketsAlgo()算法)。雖然看上去浪費了很多時間,但是這也讓我認識到了算法的強大,逐漸進步。

(四)個人感受

首先,先談談我寫這個作業的過程。

對於這次作業,剛開始我是低估了難度的。我認為只要兩天左右的課余時間就可以完成。結果,這次實際花的時間遠遠超過我預想的。並且,由於剛開始我的不恰當的想法,導致我前面浪費了許多時間。後面又用了一種更加簡便的方法去做,成功的實現了基本功能中的所有要求。於是我開始去做附加要求,對於附加要求,剛開始並沒有什麽想法,於是,我上網查了些資料,看了同學們的一些博客,漸漸的發現附加功能並沒有自己想的那麽難。可能剛開始寫的時候思路比較順暢,這次附加功能並沒有占用我很長時間(敲代碼時間的三分之一左右)。最後,就是,寫博客啦。寫博客對我而言還是挺費時間,大概花了六個小時。終於,個人項目完成啦!

這次項目,於我而言還挺能難的,也挺費時間的,主要還是自己算法不是很好,不能找到最優解,導致自己浪費了一些時間。通過這次項目,我收獲最大的就是互相學習、交流的重要性。如果沒有看同學們、看網上的博客,沒有跟同學們討論,我可能還會限制在自己的思路中。還有就是在敲代碼前一定要有明確的思路,要不然敲了半天可能會是無用功。這做這個項目過程中,debug也花費了很多時間。

雖然這周很忙,最後幾天忙到晚上兩點多,電腦沒電了才睡覺。但是我很喜歡這種專註於一件事的感覺,以前沒事的時候會看看劇,聊聊天,但是最近這幾天,有時間就是敲代碼,有時走在路上也會想怎麽更好的實現功能,之間的邏輯是什麽。在項目最終完成時,很激動也很有滿足感。我想,這就是軟件工程的魅力吧。

最後,依舊一句話結尾。也依舊是 越努力、越幸運!

2016011990小學四則運算練習軟件項目報告