js獲取年月日星期時分秒
結對專案
這個作業屬於哪個課程 | 軟體工程 |
---|---|
這個作業要求在哪裡 | 作業要求 |
這個作業的目標 | 學會與搭檔合作完成專案 |
合作者(學號):
陳金海:3118001626
林凡(其他專業)
GitHub地址: https://github.com/alanthegoat/AutogenerationOfArithmetic
PSP表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 60 | 60 |
Estimate | 估計這個任務需要多少時間 | 40 | 30 |
Development | 開發 | 600 | 840 |
Analysis | 需求分析 (包括學習新技術) | 20 | 40 |
Design Spec | 生成設計文件 | 15 | 20 |
Design Review | 設計複審 | 15 | 10 |
Coding Standard | 程式碼規範 (為目前的開發制定合適的規範) | 20 | 20 |
Design | 具體設計 | 200 | 220 |
Coding | 具體編碼 | 250 | 230 |
Code Review | 程式碼複審 | 100 | 200 |
Test | 測試(自我測試,修改程式碼,提交修改) | 300 | 240 |
Reporting | 報告 | 120 | 120 |
Test Repor | 測試報告 | 100 | 60 |
Size Measurement | 計算工作量 | 10 | 5 |
Postmortem & Process Improvement Plan | 事後總結, 並提出過程改進計劃 | 30 | 30 |
合計 | 1880 | 2385 |
1.主要類與函式
graph LR A[generateArithmetic] -->B[calculationOfRandomArithmetic] A -->C[outputArithmetic] B -->D[outputAnswer]- src - com.alanthegoat - autogenerationofarithmetic - GenerationOfRandomArithmetic.java - GenerationOfRandomNumber.java - calculation - CalculationOfRandomArithmetic.java - outputfile - OutputAnser.java - OutputArithmetic.java - utils - BinaryTree.java - LinkedStack.java - Fraction.java - Utils.java - GetMaxGcd.java - src - com.alanthegoat - grade - Grade.java >主要模組功能: >1.GenerationOfRandomArithmetic 隨機生成表示式 >2.GenerationOfRandomNumber 隨機生成數值和運算子,供1使用 >3.CalculationOfRandomArithmetic 計算表示式值 >4.OutputAnser 輸出答案 >5.OutputArithmetic 輸出表達式 >6.Grade 改題目,判斷是否正確
2.程式碼分析
graph LR A[生成隨機表示式] -->C{判斷} C -->|false| A[生成隨機表示式] C -->|true| E[計算結果] E[計算結果]-->寫入檔案2.1生成隨機表示式(部分程式碼)
public String generateArithmetic(BinaryTree<String> binaryTree,int bound){
random = new Random();
//隨機生成運算子數量
operationNum = random.nextInt(4);
if(operationNum==0)
operationNum++;
//根據運算子數量決定數值數量
switch (operationNum){
case 1: numberNum = 2;break;
case 2: numberNum = 3;break;
case 3: numberNum = 4;break;
}
int flag = 0;
Random random = new Random();
Number number = null;
Character character = null;
Double decimalNumber = null;
Integer integer = null;
//隨機產生數值,並生成表示式樹
if(operationNum==1){
character = GenerationOfRandomNumber.getRandomOperation();
binaryTree.insert(character.toString());
for (int i = 0; i < numberNum; i++) {
flag = random.nextInt(2);
number = decimalNumberOrInteger(flag,bound);
if(number instanceof Integer){
integer = number.intValue();
binaryTree.insert(integer.toString());
}
else {
decimalNumber = number.doubleValue();
//如果是小數,則轉換成真分數
binaryTree.insert(Utils.decimalNumberToProperFraction(decimalNumber));
}
}
}else{
for (int i = 0; i < operationNum; i++) {
character = GenerationOfRandomNumber.getRandomOperation();
binaryTree.insert(character.toString());
}
for (int i = 0; i < numberNum; i++) {
flag = random.nextInt(2);
number = decimalNumberOrInteger(flag,bound);
if(number instanceof Integer){
integer = number.intValue();
binaryTree.insert(integer.toString());
}
else {
decimalNumber = number.doubleValue();
binaryTree.insert(Utils.decimalNumberToProperFraction(decimalNumber));
}
}
}
//新增括號
String arithmetic = binaryTree.inorderTraversal();
StringBuilder sb = new StringBuilder();
String[] strings = arithmetic.split(" ");
if(operationNum==2){
if(getPriority(strings[3])>getPriority(strings[1])){
sb.append("(");
for (int i = 0; i < strings.length; i++) {
if(i==3)
sb.append(")");
sb.append(strings[i]);
}
}
}
2.2測試(生成10個數值範圍在10以內的表示式)
public static void main(String[] args){
int count = 1;
GenerationOfRandomArithmetic generationOfRandomArithmetic = new GenerationOfRandomArithmetic();
BinaryTree<String> binaryTree;
for (int i = 0; i < 10; i++) {
binaryTree = new BinaryTree<>();
System.out.println(count++ + ". " +generationOfRandomArithmetic.generateArithmetic(binaryTree,10));
}
}
2.3結果
1. 1'9/10 + 2
2. 7'2/5 + 1
3. 9'9/10 + 9 - 9
4. 6'3/5 × 4 - 2 × 7'4/5
5. 4 ÷ 1/10
6. (7'3/10-5'7/10)÷6
7. 7/10 ÷ 9
8. 4'3/5 ÷ 5
9. (9/10+8'3/10)÷9/10
10. 8÷1÷(5'1/2+0)
2.4計算表示式(部分程式碼)
public class CalculationOfRandomArithmetic {
//arithmetic為字尾表示式
public String calculationOfRandomArithmetic(String arithmetic){
//獲取表示式中的數值
String[] strings = arithmetic.split(" ");
//建立一個棧來計算表示式
LinkedStack<String> linkedStack = new LinkedStack<>();
String num1,num2;
Fraction fraction1,fraction2;
//遍歷表示式
for (int i = 0; i < strings.length; i++) {
//是整數直接壓棧
if (Utils.isInteger(strings[i])) {
linkedStack.push(strings[i]);
}
//是分數先把真分數轉換成假分數,方便後面計算
else if (Utils.isDecimal(strings[i])) {
linkedStack.push(Utils.properFractionToFraction(strings[i]).toString());
}
//是運算子,彈出兩個數值,根據數值型別進行計算
else {
num1 = linkedStack.pop();
num2 = linkedStack.pop();
if(Utils.isDecimal(num1)||Utils.isDecimal(num2)){
fraction1 = Utils.fractionize(num1);
fraction2 = Utils.fractionize(num2);
switch (strings[i]) {
case "+":
fraction1 = fraction2.add(fraction1);
linkedStack.push(Utils.properFractionToFraction(fraction1.toString()).toString());
break;
case "-":
fraction1 = fraction2.sub(fraction1);
//子表示式中運算出現負數,結果返回null,不寫入檔案
if(fraction1.toString().startsWith("-"))
return null;
linkedStack.push(Utils.properFractionToFraction(fraction1.toString()).toString());
break;
case "×":
fraction1 = fraction2.muti(fraction1);
linkedStack.push(Utils.properFractionToFraction(fraction1.toString()).toString());
break;
case "÷":
//除數為0,結果返回null,不寫入檔案中
if(fraction1.getNumerator()==0)
return null;
fraction1 = fraction2.div(fraction1);
linkedStack.push(Utils.properFractionToFraction(fraction1.toString()).toString());
break;
}
}
3.效能分析
3.1 用時分析
發現把表示式和答案寫到檔案時花費很多時間,如close和init,檢視程式碼,發現在寫入檔案時,每寫入一個表示式或者答案之前,都重新初始化輸出流和檔案流,最後還關閉了流,浪費了大量無關的時間。
3.2改進程式碼(把重複的工作提取出來)
public class OutputArithmetic {
static int count = 1;
static private String filePath ="d://Exercises.txt";
static private BufferedWriter bufferedWriter;
static {
try {
bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void outputArithmetic(String arithmetic) throws IOException {
bufferedWriter.write((count++) +". " + arithmetic+" = ");
bufferedWriter.newLine();
}
public static void close() throws IOException {
bufferedWriter.close();
}
}
3.3改進後的消耗!
原來的生成1000道題目計算答案再寫出檔案需要600ms,現在只需353ms,檔案的寫出工作只佔6.7%和0.7%,不再消耗那麼多時間,速度提高了0.3秒。
3.4改進判斷條件
改進後的時間是計算表示式結果和生成表示式結果花費最多時間,分別為%37.3和%26.4,發現在計算表示式值時,判斷數值是否是分數(Utils.isDecimal(String s))時和分數的轉換,消耗了很多時間。
原來程式碼如下:
public static boolean isDecimal(String str){
if(str==null)
return false;
return str.matches("\\d+/\\d+")||str.matches("\\d+'\\d+/\\d+");
}
可以簡化判斷表示式如下
public static boolean isDecimal(String str){
if(str==null)
return false;
return str.matches(".+/.+");
}
速度提升了4%。
3.5程式碼改進(部分程式碼)
在原來程式碼的基礎上新增一個分數類Fraction
public class Fraction {
private int numerator; // 分子
private int denominator; // 分母
private Integer integer;
public Fraction() {
}
public void setInteger(int integer) {
this.integer = integer;
}
public Fraction(int a, int b) {
if (a == 0) {
numerator = 0;
denominator = 1;
} else {
setNumeratorAndDenominator(a, b);
}
}
private void setNumeratorAndDenominator(int a, int b) { // 設定分子和分母
int c = f(Math.abs(a), Math.abs(b)); // 計算最大公約數
numerator = a / c;
denominator = b / c;
if (numerator < 0 && denominator < 0) {
numerator = -numerator;
denominator = -denominator;
}
}
public Fraction add(Fraction r) { // 加法運算
Fraction result = null;
int a = r.getNumerator();
int b = r.getDenominator();
int newNumerator = numerator * b + denominator * a;
int newDenominator = denominator * b;
if(newNumerator>newDenominator){
a = newNumerator/newDenominator;
newNumerator = newNumerator%newDenominator;
result = new Fraction(newNumerator, newDenominator);
result.setInteger(a);
return result;
}
result = new Fraction(newNumerator, newDenominator);
return result;
}
//減法、乘法、除法運算...
有了這個類,在計算表示式值時,對於分數和分數或者分數和整數的運算可以簡化,不用在進行額外的轉化,提高計算效率。
4.打分模組
4.1程式碼
public static void grade() throws IOException {
result1 = "correct:";
result2 = "wrong:";
sb1.append("(");
sb2.append("(");
String str = null, str1 = null;
String[] strings = null, strings1 = null;
while ((str = br2.readLine()) != null && (str1 = br1.readLine()) != null) {
strings = str.split("=");
strings1 = str1.split("\\. ");
if (strings[1].equals(strings1[1])) {
rightCount++;
sb1.append(strings1[0] + ",");
} else {
wrongCount++;
sb2.append(strings1[0] + ",");
}
}
sb1.append(")");
sb2.append(")");
//構造最終結果
result1 += rightCount + sb1.toString();
result2 += wrongCount + sb2.toString();
bw.write(result1);
bw.newLine();
bw.write(result2);
br1.close();
br2.close();
bw.close();
}
4.2測試
先在命令列中生成表示式並生成答案檔案
命令如下:
E:\IdeaProjects\AutogenerationOfArithmetic\out\artifacts\AutogenerationOfArithmetic_jar>java -jar AutogenerationOfArithmetic.jar -n 5 -r 10 表示生成5道題目,數值範圍在10以內
<生成的題目如下:
答案如下:
自行書寫答案,故意寫錯幾個
在命令列中使用命令進行改題評分
命令如下:
java -jar Grade.jar
結果如下:
結果正確!
5.專案小結
5.1我的專案小結:
在本次結對專案中我主要負責書寫程式碼,在與同伴書寫程式碼之前,我們共同商討了程式碼的主要結構和程式碼的實現方法,決定了專案的骨架,比如需要哪些包,書寫哪些類,書寫哪些方法。
這很重要,因為結對專案不是一個人的工作,需要相互合作交流才能更好的完成專案。若做專案前不交流,則後面很有可能每個人編寫的介面都不適合另一個人書寫的程式碼。
軟體工程的目標是:在給定成本、進度的前提下,開發出具有適用性、有效性、可修改性、可靠性、可理解性、可維護性、可重用性、可移植性、可追蹤性、可互操作性和滿足使用者需求的軟體產品。
追求這些目標有助於提高軟體產品的質量和開發效率,減少維護的困難。在本次專案中,我遵循了程式碼的可重用性、可互操作性、可修改性。更加理解了軟體工程這門課的重要性。
5.2同伴的專案小結:
在修改程式碼時,需要注意不要改變原來的介面。在debug程式碼時,靈活運用idea的debug模式可以更加輕鬆找出bug,提高效率。
合作專案更加考驗一個人的寫程式碼水平。希望以後能夠多多練習這種模式。