個人實踐項目——四則運算
個人實踐——四則運算
一、需求分析:
(一)功能需求
1、基本功能:
程序可接收一個輸入參數n,然後隨機產生n道加減乘除練習題。
2、擴展功能
支持有括號的運算式,包括出題與求解正確答案。
支持真分數的出題與運算。
(二)非功能需求
1、每個數字在 0 和 100 之間,運算符在3個到5個之間。
2、所出的練習題在運算過程中不得出現負數與非整數,比如3÷5+2=2.6,2-5+10=7等是不合法的。
3、算式中存在的括號必須大於2個,且不得超過運算符的個數。
4、真分數只需要涵蓋加減法
5、支持運算時分數的自動化簡,且計算過程中與結果都須為真分數。
6、格式要求如下:
當程序接收的參數為4時,以下為一個輸出文件示例。
2018010203
13+17-1=29
11*15-5=160
3+10+4-16=1
15÷5+3-2=4
(三)設計需求
1、只能使用Java語言。
2、生成文件時請使用相對路徑,生成的txt 文件需在項目的根目錄下,可直接查看演示示例。
3、使用的JDK版本為 jdk8u161。
4、使用的JRE版本為jre8u161。
5、不得使用除限定版本jdk與jre外的額外依賴包。
二、功能設計:
(一)基本功能
1、能生成文件,假如文件生成有誤,會報錯,會有提示。
2、輸入的保證是數字,如果不是數字,會有提示,並且可以重新輸入。
3、輸入一個參數n,然後隨機產生n道加減乘除算術題。保證加減乘除四個運算符的相對平衡,出現的次數相對均等。盡量能出現連除,連減的算術題。且保證在算數過程中,不出現負數,和小數。
4、在沒仔細看要求之前,我打算生成一個窗口,同學可以輸入答案,並且可以進行判斷正誤,然後給出結果。
(二)擴展功能
1、在生成括號的過程中,打算隨機生成括號,並且保證括號的合法性。比如(3*8)+5=29; 6+(7)*8=62; (2*3+4)=10; 等式子是不合法的。
2、在生成分數的過程中,保證生成真分數,並且化成最簡的。
3、在計算真分數的過程中,保證過程中不會出現假分數和負數。因為沒有乘除運算,所以不用考慮優先級,可以邊生成邊運算。且保證結果是最簡真分數。
三、設計實現
(一)優先級類
功能:此類是一個帶參的有返回值的類,返回的是一個整數(int)。
目的:通過返回來的int的大小,從而來判斷符號的優先級。
關系:此類是一個內部類,可以直接調用使用。
此類較簡單,未畫流程圖。
(二)gcd 類
功能:此類是一個帶參的有返回值的類,返回的是一個整數,此整數是兩個數的最大公因數。
目的:此類通過輾轉相除法計算兩個數的最大公因數,為了生成最簡真分數和化簡最終結果。
關系:此類還是一個內部類,可以直接調用。
流程圖:
(三)兩個函數相互獨立。
四、算法詳解
(一)文件生成
要求:能生成文件,假如文件生成有誤,會報錯,會有提示。
要完成這個功能,需要使用PrintStream類,為了生成的txt 文件需在項目的根目錄下,則需要直接使用"result.txt",不加任何路徑。
1 try { 2 PrintStream ps = new PrintStream("result.txt"); 3 System.setOut(ps); 4 }catch(Exception e) { 5 System.out.println("文件生成錯誤"); 6 }
(二)輸入整數
要求:輸入的保證是數字,如果不是數字,會有提示,並且可以重新輸入。
要實現這個功能,需要使用字符轉化來判斷是否是數字字符串,從而轉化成數字。需要使用Integer.valueOf(String);語句。為了能重新輸入需要使用while(true)加break;
1 while(true) 2 { 3 n=input.nextLine(); 4 flag=1; 5 try 6 { 7 int num=Integer.valueOf(n);//把字符串強制轉換為數字 8 } 9 catch (Exception e) 10 { 11 System.out.println("輸入的不是數字,請重新輸入:"); 12 flag=0; 13 } 14 if(flag==1)break;//退出循環 15 }
(三)隨機數的使用
要求:保證加減乘除四個運算符的相對平衡,出現的次數相對均等,不出現負數,和小數。需要使用“數組+隨機數”。
1 char[] arr= {‘+‘,‘-‘,‘*‘,‘÷‘}; 2 int temp=rand.nextInt(4); 3 charArr=arr[temp]; 4 5 while(a0%a1!=0) 6 { 7 a0=rand.nextInt(100); 8 a1=rand.nextInt(99)+1; 9 } 10 while(a0<a1) 11 { 12 a0=rand.nextInt(100); 13 a1=rand.nextInt(100); 14 }
如果不能乘除或者a0-a1<0,則會重新生成隨機數。
(四)保證括號的合法性
為了不生成(3*8)+5=29; 6+(7)*8=62; (2*3+4)=10;此類括號。我們需要對優先級進行判斷,如果前者優先級低於後者,則會生成括號。
1 if(panduan(charArr)<panduan(charArr2))//優先級判斷 2 { 3 if(charArr2==‘÷‘) 4 { 5 if(b0==0)b0++; 6 while(sum%b0!=0)//如果不能整除 重新生成隨機數 7 { 8 b0=rand.nextInt(99)+1; 9 } 10 sum=sum/b0; 11 } 12 if(charArr2==‘*‘)sum=sum*b0; 13 brr="("+brr+")"+""+charArr2+""+b0;//滿足條件 生成括號 14 }
註釋:panduan()是一個內部類,用來判斷符號優先級。
(五)panduan——優先級類的實現
1 public static int panduan(char c)//判斷優先級 2 { 3 if(c==‘(‘)return 0; 4 if(c==‘+‘||c==‘-‘)return 1; 5 if(c==‘*‘||c==‘÷‘)return 2; 6 return -1; 7 }
(六)最大公因數——gcd類
要求:在生成分數的過程中,保證生成真分數,並且化成最簡的。需要使用輾轉相除法求最大公因數,然後分子分母同除以最大公因數化簡。保證是真分數的代碼和保證非負數的代碼類似,就不寫出來了。
1 public static int gcd(int x,int y) 2 { 3 while(true) 4 { 5 if(x%y==0)return y; 6 int temp=y; 7 y=x%y; 8 x=temp; 9 } 10 }
五、測試運行
六、代碼
在計算值得過程中,用到了棧的思想。但是我的思路主要還是,邊生成邊運算。即生成完畢後,結果就直接出來了。
1 for(int i=1;i<charCoun;i++) 2 { 3 int temp1=rand.nextInt(4); 4 char charArr2=arr[temp1]; 5 int b0=rand.nextInt(100); 6 if(panduan(charArr)<panduan(charArr2))//優先級判斷 7 { 8 if(charArr2==‘÷‘) 9 { 10 if(b0==0)b0++; 11 while(sum%b0!=0)//如果不能整除 重新生成隨機數 12 { 13 b0=rand.nextInt(99)+1; 14 } 15 sum=sum/b0;//計算 16 } 17 if(charArr2==‘*‘)sum=sum*b0; 18 brr="("+brr+")"+""+charArr2+""+b0;//滿足條件 生成括號 19 } 20 else 21 { 22 if(charArr2==‘÷‘) 23 { 24 if(b0==0)b0++; 25 while(sum%b0!=0) 26 { 27 b0=rand.nextInt(99)+1; 28 } 29 sum=sum/b0;//計算 30 } 31 if(charArr2==‘-‘) 32 { 33 while(sum<b0) 34 { 35 b0=rand.nextInt(100); 36 } 37 sum=sum-b0; 38 } 39 if(charArr2==‘+‘)sum=sum+b0;//計算 40 if(charArr2==‘*‘)sum=sum*b0;//計算 41 brr=brr+""+charArr2+""+b0; 42 } 43 charArr=charArr2; 44 } 45
此代碼根據優先級,生成括號。
1 if(panduan(charArr)<panduan(charArr2))//優先級判斷 2 { 3 if(charArr2==‘÷‘) 4 { 5 if(b0==0)b0++; 6 while(sum%b0!=0)//如果不能整除 重新生成隨機數 7 { 8 b0=rand.nextInt(99)+1; 9 } 10 sum=sum/b0; 11 } 12 if(charArr2==‘*‘)sum=sum*b0; 13 brr="("+brr+")"+""+charArr2+""+b0;//滿足條件 生成括號 14 }
七、總結
1、對任務進行逐步分解和細化,分成若幹個子任務,每個子任務只完成部分完整功能,並且可以通過函數來實現;比如此四則運算中的panduan類和gcd類。通過生成兩個內部類,使程序模塊化,來簡化代碼。最後在主函數中進行調用實現。
2、降低耦合,控制了程序設計的復雜性,提高了代碼的重用性。但是由於個人編程習慣問題,仍有一些功能沒有進行模塊化。之後我會對博客和代碼進行更新。
八、PSP
PSP |
任務內容 |
計劃時間(min) |
完成時間(min) |
Planning |
計劃 |
3 |
3 |
Estimate |
估計這個任務需要多少時間,並規劃大致工作步驟 |
3 |
3 |
Development |
開發 |
145 |
305 |
Analysis |
需求分析 |
10 |
15 |
Design Spec |
生成文檔 |
0 |
0 |
Design Review |
設計復審 |
0 |
0 |
Coding Standard |
代碼規範 |
0 |
0 |
Design |
具體設計 |
30 |
50 |
Coding |
具體編碼 |
90 |
60 |
Code Review |
代碼復審 |
0 |
0 |
Test |
測試 |
15 |
180 |
Reporting |
報告 |
120 |
210 |
Test Report |
測試報告 |
0 |
0 |
Size Measurement |
計算工作量 |
0 |
0 |
Postmortem& ProcessImprovement Plan |
事後總結, 並提出過程改進計劃 |
120 |
210 |
1、因為沒有生成文件等一系列過程,導致在具體設計和代碼編寫的時候花了大量時間。尤其是測試,一直出現bug,調bug花了我大量時間。
2、因為是個人項目,所以感覺自己能看懂就行,不用管其他人,所以一些過程就直接略過了。在以後團隊工作中,我會認真完成各項工作,方便未來的修改。
九、完整代碼
1 import java.util.Random; 2 import java.util.Scanner; 3 import java.io.PrintStream; 4 public class Main { 5 6 public static int panduan(char c)//判斷優先級 7 { 8 if(c==‘(‘)return 0; 9 if(c==‘+‘||c==‘-‘)return 1; 10 if(c==‘*‘||c==‘÷‘)return 2; 11 return -1; 12 } 13 14 public static int gcd(int x,int y) 15 { 16 while(true) 17 { 18 if(x%y==0)return y; 19 int temp=y; 20 y=x%y; 21 x=temp; 22 } 23 } 24 25 public static void main(String[] args) { 26 // TODO Auto-generated method stub 27 Scanner input = new Scanner(System.in); 28 String n; 29 int flag=1; 30 try { 31 PrintStream ps = new PrintStream("result.txt"); 32 System.setOut(ps); 33 }catch(Exception e) { 34 System.out.println("文件生成錯誤"); 35 } 36 while(true) 37 { 38 n=input.nextLine(); 39 flag=1; 40 try 41 { 42 int num=Integer.valueOf(n);//把字符串強制轉換為數字 43 } 44 catch (Exception e) 45 { 46 System.out.println("輸入的不是數字,請重新輸入:"); 47 flag=0; 48 } 49 if(flag==1)break;//退出循環 50 } 51 int n1=Integer.valueOf(n); 52 System.out.println("2016012090"); 53 Random rand = new Random(); 54 char charArr; 55 int coun=0; 56 while(true) 57 { 58 if(coun==n1)break; 59 int temp2=rand.nextInt(4); 60 if(temp2!=0) 61 { 62 char[] arr= {‘+‘,‘-‘,‘*‘,‘÷‘}; 63 String brr=""; 64 int sum=0; 65 int charCoun=rand.nextInt(3)+3; 66 int temp=rand.nextInt(4); 67 charArr=arr[temp]; 68 int a0=rand.nextInt(100); 69 int a1=rand.nextInt(100); 70 if(charArr==‘÷‘) 71 { 72 if(a1==0)a1++; 73 while(a0%a1!=0) 74 { 75 a0=rand.nextInt(100); 76 a1=rand.nextInt(99)+1; 77 } 78 sum=a0/a1; 79 } 80 if(charArr==‘-‘) 81 { 82 while(a0<a1) 83 { 84 a0=rand.nextInt(100); 85 a1=rand.nextInt(100); 86 } 87 sum=a0-a1; 88 } 89 if(charArr==‘+‘)sum=a0+a1; 90 if(charArr==‘*‘)sum=a0*a1; 91 brr=a0+""+charArr+""+a1; 92 for(int i=1;i<charCoun;i++) 93 { 94 int temp1=rand.nextInt(4); 95 char charArr2=arr[temp1]; 96 int b0=rand.nextInt(100); 97 if(panduan(charArr)<panduan(charArr2))//優先級判斷 98 { 99 if(charArr2==‘÷‘) 100 { 101 if(b0==0)b0++; 102 while(sum%b0!=0)//如果不能整除 重新生成隨機數 103 { 104 b0=rand.nextInt(99)+1; 105 } 106 sum=sum/b0; 107 } 108 if(charArr2==‘*‘)sum=sum*b0; 109 brr="("+brr+")"+""+charArr2+""+b0;//滿足條件 生成括號 110 } 111 else 112 { 113 if(charArr2==‘÷‘) 114 { 115 if(b0==0)b0++; 116 while(sum%b0!=0) 117 { 118 b0=rand.nextInt(99)+1; 119 } 120 sum=sum/b0; 121 } 122 if(charArr2==‘-‘) 123 { 124 while(sum<b0) 125 { 126 b0=rand.nextInt(100); 127 } 128 sum=sum-b0; 129 } 130 if(charArr2==‘+‘)sum=sum+b0; 131 if(charArr2==‘*‘)sum=sum*b0; 132 brr=brr+""+charArr2+""+b0; 133 } 134 charArr=charArr2; 135 } 136 System.out.println(brr+"="+sum); 137 } 138 else 139 { 140 String brr2=""; 141 char[] arr1= {‘+‘,‘-‘}; 142 int sumx=0; 143 int sumy=0; 144 int charCoun1=rand.nextInt(3)+3; 145 int temp1=rand.nextInt(2); 146 charArr=arr1[temp1]; 147 int num0x=rand.nextInt(20); 148 int num0y=rand.nextInt(19)+1; 149 int num1x=rand.nextInt(20); 150 int num1y=rand.nextInt(19)+1; 151 int g; 152 g=gcd(num0x,num0y); 153 num0x/=g; 154 num0y/=g; 155 g=gcd(num1x,num1y); 156 num1x/=g; 157 num1y/=g; 158 while(num0x>=num0y||num1x>=num1y) 159 { 160 num0x=rand.nextInt(20); 161 num0y=rand.nextInt(19)+1; 162 num1x=rand.nextInt(20); 163 num1y=rand.nextInt(19)+1; 164 g=gcd(num0x,num0y); 165 num0x/=g; 166 num0y/=g; 167 g=gcd(num1x,num1y); 168 num1x/=g; 169 num1y/=g; 170 } 171 if(charArr==‘-‘) 172 { 173 while(num0x*num1y-num0y*num1x<0) 174 { 175 num1x=rand.nextInt(20); 176 num1y=rand.nextInt(19)+1; 177 g=gcd(num1x,num1y); 178 num1x/=g; 179 num1y/=g; 180 } 181 sumx=num0x*num1y-num0y*num1x; 182 sumy=num0y*num1y; 183 } 184 if(charArr==‘+‘) 185 { 186 while(num0x*num1y+num0y*num1x>=num0y*num1y) 187 { 188 num1x=rand.nextInt(20); 189 num1y=rand.nextInt(19)+1; 190 g=gcd(num1x,num1y); 191 num1x/=g; 192 num1y/=g; 193 } 194 sumx=num0x*num1y+num0y*num1x; 195 sumy=num0y*num1y; 196 } 197 brr2=num0x+"/"+num0y+""+charArr+""+num1x+"/"+num1y; 198 for(int i=1;i<charCoun1;i++) 199 { 200 temp1=rand.nextInt(2); 201 charArr=arr1[temp1]; 202 int num2x=rand.nextInt(20); 203 int num2y=rand.nextInt(19)+1; 204 while(num2x>=num2y) 205 { 206 num2x=rand.nextInt(20); 207 num2y=rand.nextInt(19)+1; 208 g=gcd(num2x,num2y); 209 num2x/=g; 210 num2y/=g; 211 } 212 if(charArr==‘-‘) 213 { 214 while(sumx*num2y-sumy*num2x<0) 215 { 216 num2x=rand.nextInt(20); 217 num2y=rand.nextInt(19)+1; 218 g=gcd(num2x,num2y); 219 num2x/=g; 220 num2y/=g; 221 } 222 sumx=sumx*num2y-sumy*num2x; 223 sumy=sumy*num2y; 224 } 225 if(charArr==‘+‘) 226 { 227 while(sumx*num2y+sumy*num2x>sumy*num2y) 228 { 229 num2x=rand.nextInt(20); 230 num2y=rand.nextInt(19)+1; 231 g=gcd(num2x,num2y); 232 num2x/=g; 233 num2y/=g; 234 } 235 sumx=sumx*num2y+sumy*num2x; 236 sumy=sumy*num2y; 237 } 238 brr2=brr2+""+charArr+""+num2x+"/"+num2y; 239 } 240 g=gcd(sumx,sumy); 241 if(sumx==0)System.out.println(brr2+"="+sumx); 242 else System.out.println(brr2+"="+sumx/g+"/"+sumy/g); 243 } 244 coun++; 245 } 246 } 247 248 }
個人實踐項目——四則運算