2013年9月10日 星期二

Round 2: Improvements

回顧(L)讓我們得知程式有使用者相關的議題仍待解決。這讓我們有理由進入第二輪U-D-C-L。

U步驟這兩個議題都和使用者有關,但它們在第一輪進行時並不明顯。事實上,我們可以說透過操作第一輪得到的working software,我們發現了與原問題息息相關的新問題 -- 在正常操作下,程式必須強健;使用者犯錯時,程式必須能容忍並引導使用者

我們將增加兩個子問題(sub-problem):

SP1. 身為使用者,當我輸入的兩個向量維度不同時,程式在示警後,仍能正常執行。

SP2. 身為使用者,當我輸入的向量格式不對時,程式在示警,仍能正常執行。

SP1與SP2屬於改善程式品質的需求。我們以使用者觀點寫下這些需求,前半段敘述使用者的動作

        身為使用者,當我輸入向量格式不對時,...

後半段敘述程式採取的措施

        .... 程式示警,仍能正常執行。

這種寫法稱為user stories,廣泛地使用於敏捷開發(agile development),例如Scrum。你可以調整出自己的寫法,但以使用者觀點列出的需求,都應該包含這兩個元素。

先做哪個?SP1發生於原問題期待的正常操作下:
...
    [1,0] 與 [1,1,0] 提示無法計算內積
...
而SP2則進一步涉及使用者犯的錯誤,需要能解析使用者的輸入,問題較為複雜。

在此第二輪,讓我們先處理SP1;SP2以後再說。

D步驟為SP1增加兩個工作:

T5. 修改內積計算函數,使其在傳入的兩個向量維度不同時,避免結束程式的執行。
T6. 修改主程式,改用新的內積函數

D步驟完成。我們的問題與工作列表如下:




C步驟:先做T5。

完成程式如下:

/* T2 inner product */
double innerProduct(double u[], int dim_u, double v[], int dim_v){
double p=0;
if (dim_u != dim_v){
cout << "Dimension error!" << endl;
exit(EXIT_FAILURE);
}
else {
for (int i=0; i < dim_u; ++i){
p += u[i]*v[i];
}
return p;  
}
}

/* T2(R1), T5(R2) inner product */
bool innerProduct(double *product, double u[], int dim_u, double v[], int dim_v){
double p=0;
if (dim_u != dim_v){
return false;
}
else {
for (int i=0; i < dim_u; ++i){
p += u[i]*v[i];
}
*product = p;
return true;  
}
}

原來的innerProduct回傳double,不能涵蓋兩向量維度不同時之回傳,選擇以exit(EXIT_FAILURE)結束程式。
innerProduct則回傳bool - 內積可計算時回傳true,否則回傳false - 並增加一個輸出參數 prod,在可計算時回傳內積值。

接著做T6,修改主程式如下:

/* T3(R1), T5(R2) main */
int main(int argc, char** argv) {
        ...
char ch = 'c';
while (ch == 'c'){
                            ...
double prod;
if (innerProduct(&prod,u,dim_u,v,dim_v))
cout << "inner product is " << prod << endl;
else
cout << "Dimension error!" << endl;
...
  }
cout << "bye..." << endl;
return 0;
}

新舊二版innerProduct可並存,因新版多了一個參數,C++認定二者是不同的函示。此稱為function overloading:一個function名稱,二(或以上)個意義。留下舊版?當然不,因為它有錯;有錯的程式不該被留下來,以免日後混淆!


編譯、執行程式以驗證達到預期改善:



L步驟下篇繼續。

© Y C Cheng, 2013. All rights reserved.

沒有留言:

張貼留言