1. 程式人生 > 實用技巧 >js獲取年月日星期時分秒

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.主要類與函式

- 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  改題目,判斷是否正確
graph LR A[generateArithmetic] -->B[calculationOfRandomArithmetic] A -->C[outputArithmetic] B -->D[outputAnswer]

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,提高效率。
合作專案更加考驗一個人的寫程式碼水平。希望以後能夠多多練習這種模式。