JAVA實現表達式求導運算的分析總結


1第一次作業

1.1題目描述

  對形如4*x+x^2+x的多項式求導。

1.2類圖

1.3度量分析

  在完成第一次作業時,我的寫法沒有特別的“面向對象”。唯一封裝起來的是Node,代表多項式的一個項。PolyDerivation是一個方法龐雜的類,先判斷輸入是否合法,再將多項式拆分成獨立的項,接着求導,同時也包含了程序的入口main。這無疑是一個面向方法的寫法。

  寫valid方法判斷合法性的時候,經歷過一次波折。一開始的思路是用一個很長的大正則表示出整個多項式,寫完發現超過了100個字符,很不美觀。而且如果表達式的項數過多,遞歸層數太深會爆棧。然后我換了一種思路,正則每次只匹配一個項,而項又可以根據x有沒有系數和指數分為5類,所以我一共寫了5種很短的正則分別匹配5種項。

  但是我有一個地方多此一舉了。就是用parsePoly和parseOp兩個方法分別取得獨立的項和他們之前的符號。其實連接各個項的符號可以歸並到每個項里。

1.4BUG分析

  我公測和互測階段都沒有bug。其實提交之前,我改了很多自己的bug。比如優化之后,出現了求導之后如果約掉了所有項就沒有輸出的情況。

  互測階段,我hack到別人的bug有爆棧,特殊空白字符,化簡之后格式錯誤這三類問題。

 

2第二次作業

2.1題目描述

  增加sin(x)和cos(x),每個乘積項可以有多個因子。

  樣例:cos(x)*sin(x)*5+x^233+sin(x)^+2

2.2類圖

2.3度量分析

  多項式的每一個乘積項其實只有四種因子:常數,x,sin(x),cos(x)。延續作業一的思想,我把乘積項封裝在Term類里面,有四個重要屬性,分別為常數項和后三種因子的指數。為了保留一個簡潔的main入口,我設置了一個只包含main方法的Main類。需要對字符串進行三步處理,即合法判斷,拆分乘積項,和求導,這些方法都放在了另一個類DealString里面。Derivation類實現了對x和三角函數的冪求導,他沒有屬性,只有方法,在需要使用他的功能時創建一個引用,然后直接調用他的方法即可。

  第二次作業我把精力放在了結果化簡上面。除了合並同類項,sin(x)^2+cos(x)^2也可以化簡。每一次對三角函數化簡之后得到的新項,可能會繼續滿足化簡條件。所以我使用for循環,並設置flag記錄某次遍歷有沒有化簡出新的項,直到不能再化簡為止就停止遍歷。

2.4BUG分析

  我通過了所有公測,但是互測被hack了合法性判斷問題,我有一處正則表達式漏掉了一個空白字符。

  互測時使用了shell腳本,可以同時輸出小組內所有人的求導結果。結合matlab,可以很快判斷他們的運算結果是否正確。我是這樣使用matlab的:

>>x=2 sin(x)+3*x^2

1*sin(x)^1+3*x^2 ...... 3*x^2+sin(x)

  先設置x的值,后面粘貼同組人輸出結果,敲擊回車,比較數值是否一致。

3第三次作業

3.1題目描述

  增加多項式因子,sin(...)和cos(...)內部可以嵌套因子。

  樣例:sin((2*x))^2*(cos(x)+1)

3.2類圖

3.3度量分析

 

  Factor類代表了因子,它有常數,x的冪,sin的冪,cos的冪,乘類,加類,這6個子類。他們都重寫了合法性判斷和求導的方法。

  第三次作業與前兩次最大的不同是,采用了繼承的結構,將合法性判斷和求導交給不同的因子類自行解決。

  合法性判斷思路:對於常數,x的冪,sin,cos因子,valid方法的傳入參數是一個長字符串,應該判斷字符串的前綴是否為合法因子。如果包含則返回true,並且捕獲前綴中的相關信息,初始化這個因子類的屬性(指數等)。對於加類,需要從頭至尾地判斷傳入字符串是否為合法的AddClass類,而不僅僅是前綴。具體方法是判斷前綴是否為一個合法的因子,其后如果是*(乘號),把該因子加入到動態創建的MulClass實例的屬性里,如果是+-號,把這個mulClass加入到這個加類的ArrayList<MulClass>里。一邊判斷合法性,一邊存儲合法因子。

  求導思路:根據乘積和嵌套的求導法則,分別調用所包含的因子實例的求導參數。結果返回一個字符串。

  下表為不同因子之間的包含關系:

類名 屬性
AddClass ArrayList<MulClass>
MulClass

BigInteger coeff

BigInteger xexp

ArrayList<Sin>

ArrayList<Cos>

ArrayList<AddClass>

Sin

BigInteger exp

AddClass inside

Cos

BigInteger exp

AddClass inside

Xexp

BigInteger exp

Constant

BigInteger val

 

  其中加類AddClass比較特殊,輸入的多項式就是一個加類,帶括號的多項式因子也是一個加類。

3.4BUG分析

  強測多個點超時,受到了毀滅性打擊。以上的類圖是在bug修復環節我重構一遍的架構,不會超時。重構之前的加類里面,我用for循環掃描字符串從start到end的子串是不是合法因子,如果不是就end++,再判斷一次;如果是就start=end+1,判斷后續因子。這個辦法for循環層數很深,處理((((((((x))))))))這種多層括號的數據點時很容易超時。

  互測hack別人的數據點大多數是導數計算錯誤,少數優化的很好的同學存在過度化簡問題(比如輸出sin(2*x))。

4問題反思

4.1方法過長

  checkstyle要求方法長度不超過60行,我超長的方法內基本都有一個很長的while循環。我的解決方式是將while內部,功能相對獨立的語句合並成一個新的方法。即將大方法的步驟分化成小方法,並在大方法里調用小方法。

4.2大段重復代碼

  sin和cos這兩個類極為相像,因此有很多重復的代碼。我目前的思路是給他們一個共同的Tri父類,將原來重復的代碼放在父類里面實現,子類只體現區別。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM