小學生四則運算(java編程)201571030135


       任務1源碼在Github的倉庫主頁鏈接地址:

       https://github.com/zhanghh2018/Four-primary-school-pupils

需求分析:

  1. 作業總體效果:隨機產生n道加減乘除練習題;
  2. 練習題的構成:數字和運算符且每個數字在 0 和 100 之間,運算符在3個到5個之間且每個練習題至少要包含2種運算符;
  3. 練習題的結果:練習題在運算過程中不出現負數與非整數;
  4. 最終提交結果:學號與生成的n道練習題及其對應的正確答案;樣例如下:

       

功能設計:

  1. 表達式的生成模塊。首先需要生成運算符與數字,每個等式中運算符的個數加一就等於該等式中的數字個數,之后將生成的符號與數字組合成String,傳入逆波蘭計算模塊進行結果的輸出。在此模塊中將除法中分母為零的情況、運算符只有一種的情況以及分子分母除不盡的情況排除。
  2. 表達式的計算模塊。利用逆波蘭表達式計算結果,在該模塊中排除例如30/6/3這樣的情況,在之前的模塊中排除的只是除號前后的分子分母的情況,並未考慮除號連續的情況,當除號連續時,需要考慮第一個除號運算完之后的結果能否繼續除以下一個數的情況,當遇到前后余數不為0的情況以及中間結果為負數的情況就跳出該函數,繼續產生新的等式直至滿足條件。寫這個模塊的時候借鑒這位博主的寫法(http://blog.csdn.net/u010485491/article/details/51483720);
  3. 結果寫入文件模塊。將自己的學號與根據用戶輸入的題目個數生成的等式寫入文件。
  4. 異常情況的處理。排除輸入為非數字的情況以及輸入的數字大於1000、小於1以及等於0的情況。

基本功能:

  • 實現每道練習題運算符在3個到5個之間,至少要包含2種運算符
  • 運算結果無負數以及非整數;
  • 將最終結果保存在文檔中以樣例為模板;
  • 每道練習題的結果不超過一定的范圍(考慮到小學生計算能力有限,當時問了鄭老師,在老師的提示下,設置了用戶輸入想要生成結果的范圍這一塊內容,並進行了異常處理)。

設計實現

      利用Visio進行流程圖的繪制,具體流程圖如下:其中ContentToTxt(將結果寫入文件) Main(主程序可以從命令行接收參數) ReversePolish (逆波蘭表達式) RandomEquation(產生等式) result.txt(運行后產生的結果)

測試運行

 

核心代碼

1) 隨機產生等式模塊:為了看起來整潔,去掉了測試過程中注釋掉的打印輸出部分。等式生成是將生成的數字與運算符依次拼接,之后加上等號構成等式,在構建過程中去除運算符只有一種的情況、分母為0的情況,分子分母有余數的情況。

  1 public class RandomEquation {
  2     public static String randomEquation (){
  3         
  4         // Previous expressions
  5         
  6         String sBefore = new String();
  7         
  8         // The later expression
  9         
 10         String sLater = new String();
 11         char[] equation;
 12         int k = 6;
 13         int n;
 14         int m;
 15         int j;
 16         int i;
 17         int[] number;
 18         char[] symbol;
 19         number = new int[k];
 20         symbol = new char[k];
 21         equation = new char[2 * k];
 22         char[] cSymbol = {'+','-','*','÷'};
 23         Random random = new Random();
 24         
 25         // Generating operator
 26         
 27         for(i = 0;i<(int)(Math.random()*3)+3;i++){
 28             int index = random.nextInt(cSymbol .length); 
 29             char resultChar = cSymbol[index];
 30             symbol[i] = resultChar;
 31             
 32         }
 33         for(m = 0;m < i;m++){
 34             if(symbol[i - 1] != symbol[m]){
 35                 break;
 36             }
 37         }
 38         
 39         /*
 40          * Removal of only one operator
 41          * If the last symbol is the same as the previous one, the last one generates a symbol at random.
 42          */
 43         
 44         if(m == i){
 45             do{
 46                 int index = random.nextInt(cSymbol.length); 
 47                 char resultChar = cSymbol[index];
 48                 symbol[i - 1] = resultChar;
 49             }while(symbol[i - 1] == symbol[i - 2]);
 50         }
 51         
 52         // Generating number
 53         
 54         for(j = 0;j < i + 1;j++){
 55                 
 56             int num = (int)(Math.random()*100);
 57             number[j] = num;
 58             
 59         }
 60         
 61         // Generating equation
 62         
 63         for(n = 0;n < i;n++){
 64             sBefore += String.valueOf(number[n])+String.valueOf(symbol[n]);
 65         }
 66         sBefore += String.valueOf(number[i]);
 67     
 68         // Save symbols and numbers into a equation array 
 69         
 70         for(n = 1;n < 2 * i;n = n+2){
 71             
 72             equation[n] = symbol[(n - 1) / 2];
 73         }
 74         for(n = 0;n < 2 * j - 1;n = n+2){
 75             
 76             equation[n] = (char)number[(n + 1) / 2];
 77             
 78         }
 79        
 80       // The removal ÷ denominator is 0 and the molecular denominator is incompatible
 81         
 82         for(n = 1;n < i + j && n + 1 < i + j;n = n + 2){
 83             if(equation[n] == '÷'){
 84                 if(equation[n + 1]==0){
 85                     do{
 86                         int num2 = (int)(Math.random()*100);
 87                         equation[n + 1] = (char)num2;
 88                     }while(equation[n + 1] == 0);
 89                 }
 90                 else if((int)equation[n - 1] % (int)equation[n + 1]!=0 || (int)equation[n - 1]<(int)equation[n + 1]){
 91                     do{
 92                         
 93                         int num2 = (int)(Math.random()*100) + 1;
 94                         equation[n + 1] = (char)num2;
 95                         if(equation[n + 1] == 0){
 96                             do{
 97                                 int num3 = (int)(Math.random()*100);
 98                                 equation[n + 1] = (char)num3;
 99                             }while(equation[n + 1] == 0);
100                         }
101                         
102                     }while((int)equation[n - 1] % (int)equation[n + 1]!= 0 || (int)equation[n - 1]<(int)equation[n + 1]);
103                 }
104                 
105             }
106             
107             
108         }
109         // The equation after excluding special circumstances
110         
111         for(n = 0;n < i+j && n + 1 < i + j;n = n + 2){
112             
113             sLater += String.valueOf((int)equation[n]);
114             sLater += String.valueOf(equation[n + 1]);
115             
116         }
117         sLater += String.valueOf((int)equation[i + j - 1]);
118         sLater += String.valueOf('=');
119        
120         return sLater;
121     }
122     
123 }

2)逆波蘭模塊借鑒這位博主的寫法,並在理解的基礎上進行了代碼的加工。當中間結果小於0或者a%b!=0時,利用return跳出該函數,並在下邊的模塊中利用返回值進行等式的重新生成。 http://blog.csdn.net/u010485491/article/details/51483720

 1 public static int calcInt(int a, int b, String stmp) 
 2     {
 3         int res = 0;
 4         char s = stmp.charAt(0);
 5         switch (s) {
 6           case '+': {
 7             res = a + b;
 8             break;
 9           }
10           case '-': {
11             res = a - b;
12             if(res < 0){
13                 return -1;
14             }
15             break;
16           }
17           case '*': {
18             res = a * b;
19             break;
20           }
21           case '÷': {
22             res = a / b;
23             if( a % b != 0){
24                 return -1;
25             }
26             break;
27           }
28         }
29         return res;
30     }

 3)結果寫入文件模塊,由於隨機產生等式,所以需要一直將該等式保存到字符串里,並對該字符串進行逆波蘭求解,否則若隨機產生式子randomEquation(),之后又利用ReversePolish(randomEquation()))產生的隨機等式的結果,這樣會出現等式計算結果與最終運算結果不匹配的情況。在該模塊中利用返回值的不同進行結果的保存,若返回值為-1或者大於用戶輸入的結果值result,就將i的值自減,這樣就相當於重新產生符合條件的式子。

 1 for(int i = 0;i < questionAmount;i++){
 2             
 3             String randoms = randomEqual.randomEquation();
 4             final boolean existed = reversePolish.reversePolish(randoms) != -1 && reversePolish.reversePolish(randoms) < 500;
 5             if(existed){
 6                 
 7                 contentToTxt.contentToTxt(strFilePath,String.valueOf(randoms+reversePolish.reversePolish(randoms)));
 8                 contentToTxt.contentToTxt(strFilePath,String.valueOf("\n"));
 9             }else{
10                 i--;
11             }
12         }

總結:

  1. 在拿到題目的時候,並沒有急着去完成代碼而是首先進行了需求分析,根據需求分析將本次作業分為三大模塊,並對這三個模塊進行了功能的划分,每個模塊都有要實現的功能,且盡量降低模塊之間的聯系。以這樣的做法書寫下來發現思路很清晰,由於不再在一個函數體內書寫程序,一個模塊出了問題不必全篇找,直接在這個模塊中修改即可。
  2. 由於參加完藍橋杯之后就沒有與java打交道了,一直與c語言打交道,所以java當中的語法也遺忘了不少,使用new這一關鍵字創建對象也給忘記啦,突然想到一則笑話(甲說都大三了,連女朋友都沒有。乙說:new一個‘對象’),這下子就忘不了啦。
  3. 在書寫代碼的過程中使用了do while語句,不需要判斷循環次數,以前一直在使用while語句,這次在產生表達式的過程中大量使用了do while,深刻體會到了該語句的妙處。
  4. 在考慮情況的時候並不是一次性完成的,而是在編寫代碼的過程中慢慢想出來的,到了最后計算結果的時候發現結果已經有上萬的啦,所以將輸出結果限制在用戶要求的范圍內,這樣就和小學生實際情況相符合。
  5. 在生成表達式中去除分子分母不能整除的時候,例如a/b/c判斷,若a/b不能整除就再隨機產生a,b;若同時b/c不能整除則再隨機產生b,c;這樣下來發現會產生a/b不能整除的情況,因為b隨機了兩次,后一次隨機就無法保證a/b是整數了,所以想到在逆波蘭計算的時候進一步排除連續除號除不盡的情況。
  6. 最后寫的是文件模塊,由於是將之前寫的文檔import進去的,在測試是否寫好文件的時候發現在目錄JRE System Library下邊沒有產生文件,最后在打開的文件夾中找到了,所以之后的每一次運行就拿Windows自帶的記事本打開,明明寫了換行符但仍在一行上,測試了好幾次都不對,最后和同學交流了才發現這個問題,利用notepad++打開結果就是合適的。
  7. 本來是想進行附加功能的添加,然而做的時候將一些特殊請款考慮到生成表達式的模塊中,導致這些附加功能無法實現,比如真分數的計算,在生成表達式的過程中,將分子分母除不盡的情況已經排除,另外就是加括號的情況,在此模塊中將除法中出現的分母為零的情況排除,排除的時候只看除號后邊的數字,如果加上括號就沒辦法進行特殊情況的判斷。所以還是在寫的時候全盤考慮,不能只想着實現這些基本功能,使得算法沒有拓展性。

PSP:

PSP2.1 任務內容 計划完成需要的時間(min) 實際完成需要的時間(min)
Planning 計划  20  25
Estimate  估計這個任務需要多少時間,並規划大致工作步驟   20  25
Development 開發  360  418
Analysis  需求分析 (包括學習新技術) 10
 10
Design Spec 生成設計文檔   10  8
Design Review  設計復審 (和同事審核設計文檔)   10 15
Coding Standard 代碼規范 (為目前的開發制定合適的規范)   20  20
Design 具體設計  30 35
Coding 具體編碼  240  280
Code Review 代碼復審  20  25
Test 測試(自我測試,修改代碼,提交修改)  20  25
 Reporting 報告  20  27
Test Report 測試報告  5  5
Size Measurement 計算工作量  5  12
Postmortem & Process Improvement Plan 事后總結 ,並提出過程改進計划  10  10


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM