代碼倉庫地址:https://dev.tencent.com/u/qingYinGuo/p/software_homework/git
測試效果見result.txt文件
一、 需求分析與功能設計
任務1:
使用JAVA編程語言,獨立完成一個3到5個運算符的四則運算練習的軟件。
軟件基本功能要求如下:
- 程序可接收一個輸入參數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
軟件附加功能要求如下:(請有餘力的同學完成)
- 支持有括號的運算式,包括出題與求解正確答案。注意,算式中存在的括號數必須大於2對,且不得超過運算符的個數。
- 擴展程序功能支持真分數的出題與運算(只需要涵蓋加減法即可),例如:1/6 + 1/8 + 2/3= 23/24。注意在實現本功能時,需支持運算時分數的自動化簡,比如 1/2+1/6=2/3,而非4/6,且計算過程中與結果都須爲真分數。
二、 設計實現
項目的目錄結構
- Main類:主類,負責接收命令行的參數並啓動程序。
- GenerateFile類:創建文件類,負責每次出題類型併產生result.text文件,將學號與練習題寫入文件。
- GenerateFormula類:式子類,負責根據調用產生各類型的式子,簡單四則運算、帶括號的四則運算、真分數加減運算。
- Calculator類:計算類,負責各種計算,含有結果運算、有條件產生減數、有條件產生除數、有條件產生分子、有條件產生分母、判斷數的大小、求取最大公因數、求取最小公倍數、分數相加、分數相減等方法。
二、收穫點
1.利用js的eval函數對生成的四則運算進行計算,簡化了很多的代碼
static ScriptEngine scriptEngine=
new ScriptEngineManager().getEngineByName("JavaScript");
public static Object calulate(String str){
//爲什麼定義時一定要帶上=0?
Object result=0;
try {
result=scriptEngine.eval(str);
} catch (ScriptException e) {
e.printStackTrace();
}
return result;
}
2.最小公倍數簡單算法的實現
//最小公倍數
public static int lcm(int num1,int num2){
int lcm=num1;
while(lcm%num1!=0||lcm%num2!=0){
lcm++;
}
return lcm;
}
3.對小數的判斷
// 對於小數的判斷
public static boolean decimals(String result){
boolean hasDecimals=false;
if (result.contains(".")){
hasDecimals=true;
}
return hasDecimals;
}
4.最大公因數
// 對於小數的判斷
public static boolean decimals(String result){
boolean hasDecimals=false;
if (result.contains(".")){
hasDecimals=true;
}
return hasDecimals;
}
三、整個項目最麻煩也最關鍵的生成計算式的類
public class GenerateFormula {
//形成運算式子
public static String simpleArithmetic(){
//標準形式
char[] stanSympol = new char[] { '*', '+', '/', '-' };
//輸出形式
char[] outSympol = new char[] { '*', '+', '÷', '-' };
String str1="";
String str2="";
//生成符號的個數
int symbolCount= (int) (Math.random()*3+3);
//生成數字數組
int num[]=new int[symbolCount+1];
for(int i=0;i<=symbolCount;i++){
num[i]= (int) (Math.random()*100+1);
}
//生成符號數組
//符號的個數比數字少一
int symbol[]=new int[symbolCount];
for (int i=0;i<symbolCount;i++){
if (i>0&&symbol[i-1]==3){
//減號之後必須是加號
symbol[i]=1;
}
else if(i>0&&symbol[i-1]==2){
//除號之後必須是乘法或加法
symbol[i]= (int) (Math.random()*2);
}
else {
symbol[i]= (int) (Math.random()*4);
}
str1+=String.valueOf(num[i])+String.valueOf(stanSympol[symbol[i]]);
str2+=String.valueOf(num[i])+String.valueOf(outSympol[symbol[i]]);
if (symbol[i]==2){
num[i+1]=Calculator.divisor(num[i],num[i+1]);
}
else if(symbol[i]==3){
num[i+1]=Calculator.subtractor(num[i],num[i+1]);
}
}
int j=0;
while (j<(symbolCount-1)&&symbol[j]==symbol[j+1]){
j++;
}
if(j==(symbolCount-1)){
return simpleArithmetic();
}
else {
str1+=String.valueOf(num[symbolCount]);
str2+=String.valueOf(num[symbolCount]);
return str2+"="+Calculator.calulate(str1);
}
}
//生成分數
public static String fraction(){
char[] symbol={'+','-'};
String str="";
int symCount= (int) (Math.random()*3+3);
//分子
int x[]=new int[symCount+1];
//分母
int y[]=new int[symCount+1];
//符號集
int z[]=new int[symCount];
//中間運算結果
int mid[]=new int[2];
//生成分數數字集
for (int i=0;i<=symCount;i++){
x[i]= (int) (Math.random()*35+1);
y[i]=Calculator.stfraction(x[i]);
}
mid[0]=x[0];
mid[1]=y[1];
//生成符號集
for (int i=0;i<symCount;i++){
z[i]= (int) (Math.random()*2);
if (z[i]==0){
int a1[]=new int[2];
a1=Calculator.addFraction(mid[0],mid[1],x[i+1],y[i+1]);
//中間的運算結果也要爲真分數
if (a1[0]>=a1[1]){
z[i]=1;
}
else {
mid=a1;
}
}
if (z[1]==1){
int a1[]=new int[2];
a1=Calculator.subFraction(mid[0],mid[1],x[i+1],y[i+1]);
if (a1[0]<0){
x[i+1]=Calculator.stfraction2(mid[0],mid[1]);
y[i+1]=mid[1];
a1=Calculator.subFraction(mid[0],mid[1],x[i+1],y[i+1]);
}
mid=a1;
}
str+=String.valueOf(x[i])+"/"+String.valueOf(y[i])+String.valueOf(symbol[z[i]]);
}
int j=0;
while (j<(symCount-1)&&z[j]==z[j+1]){
j++;
}
if (j==(symCount-1)) {
return fraction();
}
else {
str+=String.valueOf(x[symCount])+"/"+String.valueOf(y[symCount]);
return str+"="+mid[0]+"/"+mid[1];
}
}
//隨機產生括號的四則運算
public static String addBracket() {
//標準形式
char[] stanSympol = new char[]{'*', '+', '/', '-'};
//輸出形式
char[] outSympol = new char[]{'*', '+', '÷', '-'};
String str1 = "";
String str2 = "";
//生成括號的個數
int bracket = 0;
//未匹配的左括號的個數
int bracket_left = 0;
//符號個數
int symCount = (int) (Math.random() * 3 + 3);
//存儲符號的數組
int[] symbol = new int[symCount];
//存儲數字的數組
int[] num = new int[symCount + 1];
//隨機產生數字
for (int i = 0; i <= symCount; i++) {
num[i] = (int) (Math.random() * 100 + 1);
}
//隨機生成符號
for (int j = 0; j <= (symCount - 1); j++) {
symbol[j] = (int) (Math.random() * 4);
}
//形成運算式
for (int i = 1; i <= (symCount - 1); i++) {
//減數時防止產生負數
if (symbol[i] == 3) {
num[i] = Calculator.subtractor(num[i - 1], num[i]);
} else if (symbol[i] == 2) {
num[i] = (int) (Math.random() * 100 + 1);
}
str1 += num[i];
str2 += num[i];
int bracket_left1 = bracket_left;
for (int j = 0; j < bracket_left1; j++) {
if ((int) (Math.random() * 3) > 1) {
bracket_left--;
str1 += ")";
str2 += ")";
}
}
str1 += stanSympol[symbol[i]];
str2 += outSympol[symbol[i]];
if (((bracket * 2) <= symCount) && (((int) (Math.random() * 9)) > 1)) {
str1 += "(";
str2 += "(";
bracket++;
bracket_left++;
str1 += num[++i];
str2 += num[i];
str1 += stanSympol[symbol[i - 1]];
str2 += outSympol[symbol[i - 1]];
}
}
int k = 0;
while (k != symCount) {
if (symbol[k] == 3) {
num[k + 1] = Calculator.subtractor(num[k], num[k + 1]);
} else if (symbol[k] == 2) {
num[k + 1] = (int) (Math.random() * 100 + 1);
}
str1 += num[k];
str2 += num[k];
str1 += stanSympol[symbol[k]];
str2 += outSympol[symbol[k]];
k++;
}
if (symbol[symCount - 1] == 3) {
num[symCount] = Calculator.subtractor(num[symCount - 1], num[symCount]);
}
str1 += num[symCount];
str2 += num[symCount];
while (bracket_left != 0) {
str1 += ")";
str2 += ")";
bracket_left--;
}
str2 += "=";
String result = String.valueOf(Calculator.calulate(str1));
if (Calculator.decimals(result) || result.contains("Infinity")) {
return addBracket();
} else if (bracket >= 2) {
int result1 = Integer.parseInt(result);
if (result1 < 0) {
return addBracket();
} else {
return str2 + result;
}
}
else {
return addBracket();
}
}
}
5.本地命令行運行報錯
a.中文亂碼
b.編譯問題
四、總結
這個項目我開始想的時候式很簡單的,但是真正寫起來才發現並不如我所想的那樣簡單。開始寫簡單四則運算的時候,我就開始要寫代碼的數量發愁,偶然發現了eval()方法,心底真的式發出了感嘆,居然會有如此神奇的算法,編程世界的前輩們真的是太優秀啦!
有了這種方法的幫助,四則運算也很快的就完成了。對於附加功能的實現,我是借鑑了學長學姐的方法,當然。我相信只要給我時間,擁有耐心,我相信,我也是可以成功實現的。前輩們的方法好則好矣,卻是使我減少了思考過程的探險,少了許多項目完成時的欣喜。