專案
內容這個作業屬於哪個課程
2020春季計算機學院軟體工程(羅傑 任健)
(北京航空航天大學 - 計算機學院)
這個作業的要求在**
個人專案作業
我的教學班級
005這個專案的github位址
psp2.1
personal software process stages
預估耗時(分鐘)
實際耗時(分鐘)
planning
計畫
· estimate
· 估計這個任務需要多少時間105
development
開發
· analysis
· 需求分析 (包括學習新技術)
240180
· design spec
· 生成設計文件
9060
· design review
· 設計複審 (和同事審核設計文件)
3030
· coding standard
· **規範 (為目前的開發制定合適的規範)
1010
· design
· 具體設計
6090
· coding
· 具體編碼
9090
· code review
· **複審
2020
· test
· 測試(自我測試,修改**,提交修改)
90180
reporting
報告
· test report
· 測試報告
3030
· size measurement
· 計算工作量
3030
· postmortem & process improvement plan
· 事後總結, 並提出過程改進計畫
3030
合計730
755從實際結果來看,整個專案的實現時間還是太長了。我碼**的能力果然還是令人捉急,雖然前期有過很複雜的想法,但在具體編碼時並沒有得到實現,對最後的程式效能也不太滿意。雖然不熟悉c++可以作為一部分原因,但總的來說在效率上還是有很大的提公升空間,今後還是要加強自己的編碼能力,避免有想法而實現不了的情況。
為了避免各種誤差對結果造成的影響,解題中避免了使用浮點數,具體的實現方式上,使用了以下三個類:
1. 直線類line
直線採用最萬能的標準式
\[ax+by+c=0
\]來儲存,通過給定的兩點計算出三個引數即可,並且無需化簡。
這個類中還實現了檢驗兩條直線是否平行的函式,由於不考慮重合,只需對兩條直線
\[\left\
& a_x + b_y + c_=0\\
& a_x + b_y + c_=0
\end\right.
\]驗證是否成立
\[a_b_=a_b_
\]即可。
2. 交點類intersection
題目要求已經確保直線不會重合,通過函式驗證兩條直線不平行後,方程
\[\left\
& a_x + b_y + c_=0\\
& a_x + b_y + c_=0
\end\right.
\]的唯一解是
\[\left\
x = \frac}b}-c_b_}}a}-b_a_}\\
y = \frac}c}-a_c_}}a}-b_a_}
\end\right.
\]在儲存時,分別儲存\(x, y\)的分子和分母(都是整數),這樣就避免了浮點數導致的精度問題。如果接下去考慮把圓加進來的話,可以再額外儲存根式下的分子和分母。但程式中沒有實現圓相關的部分,故不再贅述。
3. 交點數統計類counter
每讀入一條直線便與每一條現有直線比較,若兩條直線不平行,則計算交點值並放入set容器中,最後將新讀入的直線放入vector容器中。這樣做的話,如果使用unordered_set,在平均情況下的時間複雜度為\(o(n^)\),若使用set則為\(o(n^logn)\)。
在set與unordered_set的選擇中,發現程式在輸入規模 \(n = 10000\) 時,使用set會導致超過60秒時間限制,但使用unorder_set會導致bad_alloc異常。經過權衡,既然想不到更好的方法提公升效能,不如使用set盡可能保證準確性,也能避免使用unorder_set後因hash函式導致的bug。
4. 優化上的一些沒實現的想法
程式中,儲存和計算交點是必不可少的工作量。對每個交點,如果在計算中,發現直線通過某個交點,那麼該直線和通過這個交點的所有直線,都不可能再有其他交點,這樣就可以省去和一些直線計算交點的步驟。考慮到效能測試中交點個數\(h\)遠小於\(n(n-1)/2\),暗示多線共點的情況較多,那麼這種方法能起到比較大的優化作用。
針對平行線的優化可能收效不大,舉個例子,若一條直線與一組\(m\)條平行線中的某一條相交,可以知道該直線與該組平行線共產生了\(m\)個交點,但由於存在多線共點的情況,仍需要計算每個交點的位置。
如上一段所說,我實現了line,intersection,counter三個類,並採用了上面所說的容器。在命令列引數的識別上,採用比較普通的while迴圈來實現引數的讀取和處理。下面主要講一下使用的測試方法與測試樣例的構建。
在構建的單元測試樣例中,我做了基本的功能測試和邊界測試。在基本的功能測試中,我盡可能測試了每個函式的功能是否正確,包括直線標準式是否正確、交點計算是否正確(也就是line和intersection的建構函式),同時構建了幾個比較基礎的樣例測試。在邊界測試中,考慮了諸如邊界點確定直線、兩條直線的交點非常接近的情況進行樣例構建,測試結果並沒有問題。下面這張圖描述了其中乙個測試樣例的構建:
在效能方面的壓力測試中,我另寫了乙個cpp檔案(**不在git倉庫中),使用隨機生成的方法構建大量樣例。雖然這樣生成的直線並不能保證不重合(實際上概率非常小),但在我自己的程式邏輯中,兩條直線重合被視為平行,不會引發崩潰性的bug,故在效能測試中可以接受。實際上,隨機生成的直線幾乎不存在平行或重合的情況,得出的交點數基本都是\(n(n-1)/2\)。
程式寫好以後,實際上並沒有做大的框架上的改動,但在細節處理上還是改過很多地方。例如,判斷兩條直線是否平行的函式和counter類中插入新直線的函式,由於函式體較為簡短,故改成了inline函式提高效能。另外,程式中還嘗試使用double代替之前介紹的分數表示方法來儲存交點,實際顯示效能提公升不是那麼明顯。如下是在使用set容器儲存交點集合,\(n = 5000\)時效能測試的截圖:
從截圖中可以看出,程式執行時間中相當一部分都在set的rb樹構建上(當然之前測試的時候也對其他時間佔比較大的地方進行了優化)。
若把set替換成unordered_set的話,效能會有比較明顯的提公升(經測試,在相同\(n\)值下,平均可減少\(1/3\)執行時間),但由於沒辦法很好解決掉記憶體分配異常的問題,加上hash函式可能存在錯誤,故還是採用set容器盡可能保證程式正確性。
首先展示交點的建構函式,這裡的a1, b2等使用了巨集定義,對應了兩條直線標準式的相應引數,具體含義之前的部分已經提及:
intersection::intersection(line* line1, line* line2)
**中的xnume對應交點x座標的分子,xdeno對應x的分母,y座標依此類推。通過分子分母分別儲存的方法,避免了浮點數可能帶來的精度問題。
下面是整個程式的核心函式countintersections:
int counter::countintersections()
} }return intersectionset->size();
}
**的邏輯在上文中已經介紹過了,這段函式中的isparallel()
為平行線的判定函式,並寫成了內聯函式以提高效能。若想要繼續提高這個函式的效能,除了將set改成unordered_set之外,只能從迴圈條件出發,略去一些不必要的交點計算。
還請老師助教提出批評意見。
3/10追記:在和結對搭檔對拍程式的時候,發現了比較嚴重的bug,初步判斷是intersection類中運算子過載錯誤引起的,但短時間內難以找出消除bug的方法。在之前和搭檔對double精度的討論中,同伴的觀點是double精度足夠完成實驗需求,所以在最後一次提交時,利用程式中預留的巨集定義開關將intersection類改為double實現,直接儲存交點x, y座標的double值(在部落格**的基礎上做除法即可得到)。
2020軟工個人專案作業
專案 內容這個作業屬於哪個課程 2020計算機學院軟體工程 羅傑 任健 這個作業的要求在 個人專案作業 教學班級 006專案位址 個人專案作業 psp2.1 personal software process stages 預估耗時 分鐘 實際耗時 分鐘 planning 計畫15 15 estim...
2020軟工個人專案作業
專案內容 這個作業屬於哪個課程 2020春季計算機學院軟體工程 羅傑 任健 這個作業的要求在 個人專案作業 我在這個課程的目標是 通過這門課鍛鍊軟體開發能力和經驗,強化與他人合作的能力 這個作業在哪個具體方面幫助我實現目標 進一步應用所學的軟體工程知識,構建專案 psp2.1 personal so...
2020軟工 個人專案作業
q a這個作業屬於哪個課程 2020春季計算機學院軟體工程 羅傑 任健 這個作業的要求在 個人專案作業 我在這個課程的目標是 系統地學習軟體工程開發知識,掌握相關流程和技術,提公升工程化開發的能力 這個作業在哪個具體方面幫助我實現目標 了解熟悉個人軟體開發流程 psp 教學班級 005專案位址 ps...