1. 程式人生 > 其它 >BUAA_OO 第一單元總結

BUAA_OO 第一單元總結

1.結構

1.1 大體思路

  • 建立Term,Expression分別表示項和表示式;
  • 建立Lexer,Parser解析表示式;

1.2 項 Term

  • 筆者將項處理成形如axb∏sin(expi)cos(expi)
  • axb :a--constant;b--exponent;
  • ∏sin(expi)cos(expi):parameter整型陣列儲存三角函式型別,expression表示式陣列儲存參與三角運算的表示式
  • public class Term {
        private BigInteger constant;
        private BigInteger exponent;
        private ArrayList<Integer> parameter = new ArrayList<Integer>();
        private ArrayList<Expression> expression = new ArrayList<Expression>();
    
        
        }

1.3 表示式 Expression

  • 筆者將表示式處理成∑termi形式,通過Term類陣列儲存各個項
  • public class Expression {
        private ArrayList<Term> expression = new ArrayList<>();}

1.4 詞法分析 Lexer

  • 筆者認為可將每一次運算簡化成 expi?/num? [+/-/*/**/sin/cos] expi/num? 
  • 建立lexer處理運算表示式expi,運算數num,運算子
  • 處理運算表示式:構建String類expression1和expression2儲存表示式,作為hashmap的key,並傳入Parser進一步解析
  • 處理運算數:筆者在此模組將運算數與表示式視作一類,儲存入expression1和expression2中,傳入Parser進一步解析
  • 處理運算子:筆者將運算細分成取反(neg),正弦(sin),餘弦(cos),加(add),減(sub),乘(*),乘方(**),取正(pos);將八類運算按Lexer-Parser運算子表解析,用整形parser表示,傳入Parser進一步解析
  • 運算 parser值
    neg 1
    sin 2
    cos 3
    add 4
    sub 5
    mul 6
    pow 7
    pos 8
  • public class Lexer {
        private String curline;
        private String name;
        private String expression1 = "1";
        private String expression2 = "1";
        private int parser;}
    

     

    1.5 解析 Parser 
  • 建立hashmap<String,Expression>,以Lexer傳入的expression1,expression2為key,以解析表示式類作為value
  • 通過Lexer傳入的整形lexer進行表示式或數的運算
  • public class Parser {
        private Lexer lexer;
        private HashMap<String, Expression> map;
    
        public Parser(Lexer lexer, HashMap<String, Expression> map) {
            this.lexer = lexer;
            this.map = map;
        }

  

2.演算法

2.1 大體思路

  • 逐層運算:將表示式之間的複雜運算逐層解析項之間的簡單運算

2.2 表示式運算

  • 筆者將表示式的運算分成:加(add),減(sub),乘(*),乘方(**),正弦(sin),餘弦(cos)六類
  • 加(add):由於筆者以Term陣列表示表示式,故表示式的相加可通過Term陣列相加實現,在此不再贅述
  • 減(sub):需要將作為減數的表示式取反,可通過將Term陣列中的所有Term取反實現,其餘與加法相同
  • 乘(*):需要遍歷表示式的Term陣列,將表示式乘法轉化成若干Term相乘,最後將結果相加
  • 乘方(**):可視作若干次表示式與自身的乘法,不再贅述
  • 正弦/餘弦(sin/cos):表示式進行該運算後降級為Term類,儲存入新建Term的三角部分

2.3 解析方式

  • 通過整形parser值來表示運算方式,parser值在Term,Expression,Lexer,Parser類內通用
  • 筆者將運算細分成表示式之間,運算數之間,表示式與數之間三種情況。在解析前先判斷Lexer傳入的String類表示為expi或num

2.4 項運算

  • 筆者將項的運算分成:加(add),減(mul),乘(*),乘方(**),取反(neg),取正(pos),正弦(sin),餘弦(cos)
  • 由於項的運算相對簡單,筆者不再贅述

3.細節

3.1 UML類圖

3.2 度量分析

可以看出,在Parser類的next()複雜度過高,原因是該函式是解析表示式的主函式。所以筆者的解析方式並不巧妙,以後會盡量改進優化。

3.3 化簡

筆者對於化簡的做法較為簡單,僅實現了表示式的合併同類項,sin0=0,cos0=1,對於二倍角公式,sin2x+cos2x=1等三角恆等式沒有過多涉及,以後會盡量改進優化

3.4 bug修復

筆者在評測過程中遇到了一下bug:

      • Term的係數constant的資料型別過小(Integer),計算時容易出現溢位,後改為BigInteger解決
      • 程式無法處理形如sin(1)的項,後發現將1等運算數視為項導致出錯,應將其視作表示式
      • 計算乘方時沒有考慮0次方情況,導致出錯
      • 程式無法處理形如+1,+x等表示式,後發現java內建函式無法將其直接轉化,應特判正號

4.總結

在本單元oo作業中,筆者深刻理解了面向物件的理念,並且深入熟悉了java語言,希望在以後的學習過程中可以不斷進步,少些bug!