項目 | 內容 |
---|---|
這個作業屬於哪個課程 | 2020春季計算機學院軟件工程(羅傑 任建) |
這個作業的要求在哪里 | 個人項目作業 |
我在這個課程的目標是 | 完成一次完整的軟件開發經歷 並以博客的方式記錄開發過程的心得 掌握團隊協作的技巧 做出一個優秀的、持久的、具有實際意義的產品 |
這個作業在哪個具體方面幫助我實現目標 | 體驗《構建之法》中提到的 效能分析及個人軟件開發流程對於項目開發帶來的幫助 |
教學班級 | 006 |
項目地址 | Intersections | q2l's GitHub |
Personal Software Process Table (PSP)
在開始實現程序之前,在下述 PSP 表格記錄下你估計將在程序的各個模塊的開發上耗費的時間。(0.5')
PSP2.1 | Personal Software Process Stages | 預估耗時(分鍾) | 實際耗時(分鍾) |
---|---|---|---|
Planning | 計划 | 10 | 10 |
· Estimate | · 估計這個任務需要多少時間 | 10 | 10 |
Development | 開發 | 115 | 180 |
· Analysis | · 需求分析 (包括學習新技術) | 20 | 15 |
· Design Spec | · 生成設計文檔 | 10 | 10 |
· Design Review | · 設計復審 (和同事審核設計文檔) | 0 | 0 |
· Coding Standard | · 代碼規范 (為目前的開發制定合適的規范) | 5 | 5 |
· Design | · 具體設計 | 10 | 20 |
· Coding | · 具體編碼 | 30 | 60 |
· Code Review | · 代碼復審 | 10 | 10 |
· Test | · 測試(自我測試,修改代碼,提交修改) | 30 | 60 |
Reporting | 報告 | 80 | 80 |
· Test Report | · 測試報告 | 30 | 30 |
· Size Measurement | · 計算工作量 | 20 | 20 |
· Postmortem & Process Improvement Plan | · 事后總結, 並提出過程改進計划 | 30 | 30 |
合計 | 235 | 270 |
解題思路
解題思路描述。即剛開始拿到題目后,如何思考,如何找資料的過程。(3')
首先拿到題干,是一道 幾何題目 ,具體分析如下:
對於直線交點的求解我們有很多種方法,從直接的暴力運算到矩陣表示等等,考慮到代碼的風格和可擴展性我們不采取直接暴力求每個交點然后存儲的方式,我們選用了克萊姆法則求解線性方程組的方法,將直線表示為參數方程處理。
所以我們加以定義結構體存儲(x, y),由於單位向量和點的表示方式是一樣的,所以不必額外定義。
我們可以自定義一個庫來存儲這些結構體的定義和關於結構體的運算符的重載。
此外,本次作業雖然 輸入都是整數點,但是線段的斜率(即單位向量)並不是整數,還要考慮到浮點的精度問題,這里我們可以采用 重新定義為0的情況 來抵消一部分精度帶來的損失。
由於這段時間任務較重,所以側重於基礎題的拿分,對於附加題選擇放棄的做法。
設計實現
設計實現過程。設計包括代碼如何組織,比如會有幾個類,幾個函數,他們之間關系如何,關鍵函數是否需要畫出流程圖?單元測試是怎么設計的?(4')
由於本次作業較為簡單,所以只定義了一個項目的類 Intersection
,而對於 Point
和 Vector
所構成的直線方程並沒有設計類,而是直接使用 struct
的結構體完成一系列的操作。
因為自己只實現了基礎部分,所以用到的只有基本的線性代數的知識,目前階段暫時不需要流程圖的形式呈現出來。
單元測試的主要目的是 覆蓋邊角的情況,這種邊角的情況包括三種:
- 平行直線
- 對於平行直線而言是否能夠檢測到並不發生 除零 操作。
- 得到的交點平行於x軸和y軸的時候能否得到正確結果。
- 垂直直線
- 垂直直線只是相交線的一種特殊情況,主要在后面的直線和圓的計算中會使用到,這里只是預留下來。
- 數據邊界
- 一個是數據范圍的邊界是否能保證精度,這里采用了
eps=1e-12
的精度來進行精度丟失的處理。 - 數據量壓力測試,在給定的直線的數據分別是 1000 和 50000 的時候能否在規定的時間內完成運算並得到正確結果。
- 一個是數據范圍的邊界是否能保證精度,這里采用了
對於每一種情況我們都設計了若干個單元測試的樣例進行測試,具體可見目錄中的 UnitTest
中的 resources
。
改進思路
對於我的實現,改進的路線是這樣的:
- 一開始使用了
Set
結構體,因為交點的個數的計算是無重復的。 - 分析了
Set
數據結構的性能,其內部是 紅黑樹 實現,紅黑樹能時刻保證是一個有序的狀態,但是要時刻維護,每次尋找是否已經存在交點的時候所花費的時間和層高相關,大致都是log(cnt_n)
其中cnt_n
是已經存入的交點個數。 - 嘗試使用
Hashset
,HashSet
的內部實現是桶和哈希表的實現,每個元素被先存到一個桶內,桶內的元素通過一張哈希表進行連接。 - 嘗試
List
加Sort
加Unique
的新特性,在最后進行重復數據的篩除。
性能分析圖
Code Quality Analysis
已消除所有警告,之前的警告是由於部分變量定義未使用和文件的忽略了某些函數的返回值所導致的。
代碼說明
void Intersection::solveLineLineIntersection() {
int i, j, n, ssize;
Vector u, v, w;
n = (int) vectors.size();
ssize = (int) intersects.size();
for (i = 0; i < n; i++) {
for (j = i + 1; j < n; j++) {
u = points[i] - points[j];
v = vectors[i];
w = vectors[j];
double denominator = Cross(v, w);
if (dcmp(denominator) == 0) { // parallel case
continue;
}
double t = 1.0 * Cross(w, u) / denominator;
intersects.push_back(points[i] + v * t);
}
}
}
即利用了 克雷姆法則 實現直線交點的求解。
總結
本次對於Personal Software Process 的體驗有一點感觸,因為真實發現了自己的缺陷——編碼很快但是其中的錯誤也存在。之所以測試部分花了這么久的時間是因為在撰寫 "myIntersection.h" 的時候出現了筆誤,對於 int dcmp(double x)
的函數使用弄反了,在重載 ==
符號的時候語義變為了 當兩個點的x值相等且y值不等 的時候兩個點相等,導致在使用 unique
函數求解的時候出現了平行於x軸的線上有兩個交點的時候會只保留一個點,出現了正確性的錯誤。
之前沒有做過PSP的類似的時間規划,但這次使用了之后發現每次記錄自己在哪里投入了 額外多的時間 是非常重要的,因為這些額外的時間肯定是 自己的估計發生了偏差,並且 在實踐的過程中 暴露了自己不知道的缺點。我的缺點就是會出現一些細節上的錯誤,導致自己花費大量的額外時間在測試的尋找漏洞上面。
這段時間擠壓了太多的課內和課外的學習任務導致這次沒能完成附加題的部分,實屬可惜,不過學習不是一門課的成績決定的,適當做出選擇,這種選擇也包括 放棄。只要能做到問心無愧,不是因為娛樂耽誤了學習上的正事就可以了,下次繼續努力吧。
2020年3月10日。