項目 | 內容 |
---|---|
這個做業屬於那個課程 | 班級博客 |
這個做業的要求在哪裏 | 做業要求 |
我在這個課程的目標是 | 學習軟件工程相關知識,鍛鍊軟件開發能力。 |
這個做業在哪一個具體方面幫我實現目標 | 完成我的項目,體會單元測試和PSP流程 |
做業正文 | 做業正文 |
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | ||
·Estimate | 估計這個任務須要多少時間 | 60(7.2%) | 40(閱讀具體要求,完成了博客框架) |
Development | 開發 | ||
·Analysis | 需求分析 (包括學習新技術) | 120(14.5%) | 90(c++複習,相關插件資料閱讀) |
·Design Spec | 生成設計文檔 | 60(7.2%) | 30 |
·Design Review | 設計複審 (和同事審覈設計文檔) | 10(1.2%) | 10 |
·Coding Standard | 代碼規範 (爲目前的開發制定合適的規範) | 10(1.2%) | 10 |
·Design | 具體設計 | 60(7.2%) | 30 |
·Coding | 具體編碼 | 180(21.6%) | 90 |
·Code Review | 代碼複審 | 60(7.2%) | 60 |
·Test | 測試(自我測試,修改代碼,提交修改) | 120(14.5%) | 90 |
Reporting | 報告 | ||
·Test Report | 測試報告 | 60(7.2%) | 30 |
·Size Measurement | 計算工做量 | 30(3.6%) | 20 |
·Postmortem & Process Improvement Plan | 過後總結, 並提出過程改進計劃 | 60(7.2%) | 30 |
合計 | 830 | 530 |
因爲對C++的諸多特性沒有很好的掌握,預估時對每一個部分的時間估計都過於寬鬆。實際完成時間大體會比預估少1/3-1/2。html
剛拿到題目時,考慮如何計算兩條直線的交點。模擬解方程的過程過於複雜,且不夠簡便,因而考慮其餘方法,搜索資料後發現能夠採用計算幾何的方法,利用向量求解交點。ios
參考1:直線交點c++
參考2:圓交點git
總體結構如上,開始設計時基本決定分兩類,Point(點類,包含點的減法,叉乘與點乘方法)/Line(線類,包含求該對象與另外一線對象交點的方法),並決定採起map/queue分別存放交點與已讀入的直線。github
完成初版後,爲了改進性能對原始設計進行了一些修改,最終的類結構以下所示框架
class Point { public: double x; double y; Point(); Point(double _x, double _y); Point operator -(const Point& b)const; double operator *(const Point& b)const; double operator ^(const Point& b)const; bool operator <(const Point& b)const; bool operator ==(const Point& b)const; };
#pragma once #include "Point.h" #include <vector> #include <set> #include<iostream> using namespace std; class Line { public: Point s; Point e; Line(); Line(Point _s, Point _e); void intersect(set<Point>* pointset, const Line& b); };
因爲總體邏輯比較簡單,並未對關鍵函數繪製流程圖。函數
單元測試方面,則是對點類與線類的每一個方法分別進行測試,確保在給定數據範圍內的正確性。着重測試了求交點的intersect方法,利用隨機數生成數據,並利用Geogebra畫圖求得交點的數值解,進而保證了intersect方法的正確性。工具
性能改進與單元測試編寫共150分鐘,性能
經過性能分析工具,對原始代碼進行分析,發現本來使用的交點map插入前須要調用find方法判斷是否已存在該交點。所以放棄map轉而使用set+trycatch塊,將消耗時間大量減小。單元測試
最終的性能分析圖如圖所示,其中Intersect方法佔用時間最多(90.45%)
void Line::intersect(set<Point>* pointset, const Line& b) { Point res = s; if (sgn((s - e) ^ (b.s - b.e)) == 0) { return; } //判斷平行(本應判斷是否重合,因爲本題不會出現重合狀況,故舍去部分代碼) double t = ((s - b.s) ^ (b.s - b.e)) / ((s - e) ^ (b.s - b.e)); res.x += (e.x - s.x) * t; res.y += (e.y - s.y) * t; //計算幾何求交點過程 try { pointset->insert(res); }catch (exception e){} //利用set的不重複特性,添加交點結果至set中 }
關鍵代碼爲Line的intersect方法,說明在註釋中。
for (int i = 0; i < n; i++) { if (cmdin) in >> sub >> x1 >> y1 >> x2 >> y2; else cin >> sub >> x1 >> y1 >> x2 >> y2; Line tempLine = Line(Point(x1, y1), Point(x2, y2)); if (i != 0) { for (Line b : lineVector) { tempLine.intersect(&points,b); } } lineVector.push_back(tempLine); } if (cmdout) out << points.size() << endl; else cout << points.size() << endl;
外部調用則集成在IntersectLine函數中,如上所示,其主要部分是一個二重循環,對每個讀入的Line,與以前讀入並存在lineVector中的Line依次求交點。
消除 Code Quality Analysis 中的全部警告
單元測試數目:
覆蓋率:
查看後添加了一部分單元測試,但沒有增加,因爲覆蓋率與代碼正確性無必然關係,所以沒有再添加單元測試內容