本單元的任務爲求導。html
即將一個含自變量x的多項式F求導成爲另一個含自變量x的多項式f。使得 dF/dx = f正則表達式
爲下降咱們的難度,這個任務被分解成了三個階段:算法
(1)對冪函數進行求導(不容許嵌套)express
(2)對冪函數和三角函數進行求導(不容許嵌套,三角函數中只能有x)vim
(3)對冪函數和三角函數進行求導(容許嵌套,三角函數中只能有因子)數組
1、聊聊思路函數
一、字符串處理:工具
在第一和第二個階段中,對輸入的處理時相對比較容易的,由於咱們可使用正則表達式對整個輸入字符串進行匹配。測試
以第一階段爲例,咱們能夠將每一個項分爲三種狀況 數字、x^n、a*x^n。這裏的n能夠爲任何值,甚至能夠在等於1的時候直接省略。spa
那麼這三種狀況能夠分別匹配兩個正則表達式:「[+-]?[0-9]+」,「([+-]?[0-9]?\\s*\\*\\s*)[x]\\s*(^\\s*[+-][0-9]?)?」,第二個正則表達式匹配後三種狀況(瞭解更多關於正則表達式)
可是在第三階段中,因爲嵌套的出現,除非在處理過程當中作很是嚴格的限制將正則表達式分析的範圍進行縮減,不然正則表達式沒法完成對函數嵌套的字符串處理。
好比對於如下文法:
A::=aAb|i
那麼咱們理所固然的寫正則表達式A="i",A="a"+A+"b"。在這兩條正則表達式的字符串匹配完了以後,咱們發現其實A裏面並不包含着嵌套的內容,它僅僅只能匹配"aib",而不能匹配「aaibb」。固然,這是一個很是簡單的例子,能夠用其餘的方法來解決這個問題。然而任務中的狀況比這個要複雜的多,舉這個例子也只是爲了闡明在這個階段不適合使用正則表達式罷了。
這個時候應該用上另一項利器,詞法分析。在計算機編譯程序中,一般就是使用詞法分析對輸入程序進行處理。(瞭解更多關於詞法分析)
二、求導處理:
因爲在前一個部分中,三個階段使用了兩種不一樣的方法對字符串進行處理,在這個部分依舊分開講這個問題。
在1-2次任務中,形式和所需存儲的內容仍是相對單一的,第一次任務每一個項能夠寫成 a*x^b 的形式,也就是說咱們能夠只存儲a和b 便可。而第二次任務中,每一個項能夠寫成「a*x^b*sin(x)^c*cos(x)^d」的形式。那麼咱們須要存儲a,b,c,d便可。咱們只須要一次取一項,而後提取出對應的參數,而後按照規則求導,而後將參數組返回,這樣能夠完成求導。
在第三次任務中,形式變得至關的複雜,三角函數中能夠塞入項,函數相互嵌套等狀況,從而讓咱們不能用有限的參數表示一個項。上面的方法已經不適用了。
因此在求導時只能作這樣的處理:咱們按求導類型,分爲expression,item,factor。expression能夠由多個item加減得到,每一個item能夠由factor相乘得到。每一個factor由三角函數,冪函數,常數,或者嵌套函數(函數+factor)組成。每個類別都向上一層傳遞本身讀了字符串的什麼內容,本身對這段內容的求導結果是什麼。每一層在接受本身的下一層傳輸的信息的同時,也要對信息按照規則進行整合。在最底層的factor中對sin、cos、冪函數應該有本質性的處理方式(好比sin->cos之類的)。
2、程序分析
(1)基於度量來分析本身的程序結構
廢話很少說,直接上三次做業的度量數據以及類圖。
①OO度量數據(使用插件MetricsReloaded)
重要符號意義說明:
P1
LOC | NCLOC | |
Entry | 90 | 85 |
Main | 10 | 5 |
PolyDerivate | 239 | 217 |
P2
LOC | NCLOC | |
Entry | 96 | 86 |
Main | 10 | 5 |
Poly | 330 | 288 |
Term | 156 | 146 |
P3
LOC | NCLOC | |
Compact | 14 | 11 |
Entry | 28 | 24 |
Expression | 32 | 32 |
Factor | 181 | 170 |
Filter | 86 | 77 |
Item |
115 | 108 |
Main | 14 | 14 |
Reader | 88 | 83 |
②類圖(使用工具是intellij(旗艦版)自帶的diagram)
P1
P2
P3
缺點:其實很容易看出來,每一次做業的後半部分都有很是大的改動,主要是本身的程序並無考慮那麼複雜的應用,也就是須要什麼就寫什麼。在後面的任務中,幾乎要所有重構。
優勢:在最前面,Main後面一直是調用Entry。這裏的Entry是用與放置不一樣的使用模式(release,debug,batch_test)。在進行測試的時候大大的方便了本身。
(2)分析本身程序的bug
說實話,本身寫出了很多的bug,主要的緣由是沒有進行足夠嚴格的測試。並且在一些細節問題上沒有想清楚致使出現一些小錯誤,e.g.正負號寫反,沒有考慮0之類的。
我總結了一下,我犯的錯誤不少都是在細節實現時反覆更改實現方式,從而致使在更改實現方式時,另一部分的代碼的處理結果與另外一部分代碼須要的函數輸入不匹配,致使bug出現。
(3)分析本身發現別人程序bug所採用的策略
雖然我沒有參加互測,可是我仍是想聊一聊bug查找的一些bug的方法(白盒和黑盒測試)。
白盒測試:是經過程序的源代碼進行測試而不使用用戶界面。這種類型的測試須要從代碼句法發現內部代碼在算法,溢出,路徑,條件等等中的缺點或者錯誤,進而加以修正。
這個須要你去逐行閱讀代碼,同時,要嘗試設計測試樣例去覆蓋程序中的全部的分支。並且你也能夠順便檢查一下代碼邏輯。
黑盒測試:是經過使用整個軟件或某種軟件功能來嚴格地測試, 而並無經過檢查程序的源代碼或者很清楚地瞭解該軟件的源代碼程序具體是怎樣設計的。
直白來講就是,就是知道已有的需求限制,劃分等價類進行測試的方法。e.g. 若是隻容許輸入0-100的數字,那麼我麼能夠劃分爲如下等價類:非法字符輸入;<0; >100; 0-50; 50-100 共5個類型進行測試。對於具體的問題須要具體分析。這能夠在宏觀層面上發現迅速發現bug,而不須要閱讀任何代碼。
(4)Applying Creational Pattern
在個人觀點看來,助教第1、第二次的目的達到了:讓咱們習慣面向對象的方法和麪向對象的程序編寫。
可是第三次的題目,目的應該沒有達到:使用繼承和接口。在此次做業中,更加核心的東西應該是(文法分析,單例化等)。3個類之間除了2個private變量名和3個函數名相同以外,幾乎沒有什麼共同之處。不管是解析、求導、化簡都不同,在此次做業中繼承和藉口的使用的急迫程度依舊不存在。