一些 matrix 之範例碼在 main function 那裡覺得老是放不是重點的 code ,很麻煩,

建議自己先包過一些常用的 function 出來。

 

Basic unity

 

double** mat_new(const size_t row, const size_t col)
{
    size_t i;
    double *ptr;
    double** mat = (double**)malloc(sizeof(double) * row * col + 
                                    sizeof(double*) * row);
    if(mat==NULL) return NULL;

    ptr = (double*)( (char*)mat + sizeof(double*)*row );
    for(i=0; i<row; ++i)
        mat[i] = ptr, ptr+=col;
    return mat;
}

double** mat_new_arg(const size_t row, const size_t col, ...)
{
    size_t i, j;
    va_list p;
    double** mat = mat_new(row, col);
    
    if(!mat) return NULL;
    va_start(p, col);
    for(i=0; i<row; ++i) for(j=0; j<col; ++j)
        mat[i][j] = va_arg(p, double);
    va_end(p);
    return mat;
}

void mat_print(const double** mat, const size_t row, const size_t col)
{
    size_t i, j;
    for(i=0; i<row; ++i){
        for(j=0; j<col; ++j){
            printf("% 6.2lf ", mat[i][j]);
        }
        puts("");
    }
    puts("");
}

 

以前習慣會再多下面這幾個

Rix  : 將 mat 第 i 列乘上 x。
Rij   : 交換 mat 之第 i 列與第 j 列。
Rijx : 將 mat 第 i 列乘上 x,加到第 j 列。

一樣會做 Cix, Cij, Cijx 版本。

後來沒再要求一定要包這六個 function 原因是,在真正的分析時,這些函式可能會對於不同 matrix 呼叫二次,但這些行為是可以在同一個 for-loop 裡面完成的,所以沒再強求。

至於 matrix 要用一維還是二維表示可以探討一段時間。考慮到 heap 有限時,一維可以表示的範圍稍稍大一些 (只有大一點而已);二維有個好處,在做 Rij ( swap row ) 時,只需要交換 pointer 即可,不需逐一 assigned (當然也是必須要用 allocate 方式為前提才可行)。

至於 Cij 有沒有辦法交換 pointer 即可達成需求,答案是不可能。同一份程式語言只會有 management in row 或 management in column,不可能二個同時存在。而 C / C++ 是 management in row ,故這想法應是不可行。

matrix 問題大多實數係與複數係之演算法是一樣的,只有一點細節需要注意而已,但若已包成 class 型態,建議不妨以 template 撰之,有些演算法可以一次解掉 for real / for complex 問題。

另以前在寫 matrix 的時候,發現 M$ 似乎有封裝了一份簡易的 Matrix class ( 開發時從 tips 上看到 ),有興趣可 到 msdn 上看這篇

 

Error Handle 

 

例外處理它永遠是個討論不完的議題,特別是 team work 時一定要確定這部份要從哪些做起,銜接的函式在前端是必做的,那後端要不要再做 double check ? 藝術。

一些較基本的錯誤例外處理,較建議先從 caller 那裡自己做判定,如:維度是否大於 0?rowi 是否小於 row ?pointer 是否為 NULL 等問題。

筆者手邊以前開發時之例外處理範例供參考,可再自定義自己的例外處理部份。

 

xmat.h 片斷

 

//////////////////////////////////////////////////////////////////////////
// error handle
// last_error = 0 : success.
// last_error = 1 : dim error, row count / col count error.
// last_error = 2 : allocate memory fail.
// last_error = 3 : input param pointer is NULL
// last_error = 4 : has no solution
// last_error = 5 : have infinite solution
#define MAT_SUCCESS 0
#define MAT_DIM_ERR 1
#define MAT_ALLOCATE_FAIL 2
#define MAT_NULL_POINTER 3
#define MAT_HAS_NO_SOl 4
#define MAT_HAVE_INF_SOL 5
#define MAT_SPEC_MATRIX_ERR 6

// static int last_error ; // in math.c
int   mat_last_error();
const char * mat_last_error_msg();

 

xmat.c 片斷

 

//////////////////////////////////////////////////////////////////////////
// error message
static int last_error ; 
int   mat_last_error()
{
    return last_error;
}
const char * mat_last_error_msg()
{
    const char* err_msg[] = {
        "success", 
        "dim error ( row/col = 0 , or ri >= row / ci >= col )", 
        "allocate memory fail",
        "input param is a NULL pointer", 
        "has no solutions", 
        "have infinite solutions"
    };
    return err_msg[last_error];
}

 

此後所有 xmat.h 裡之 function,都必須對  static int last_error; 變數做嚴格之定義與控管,這部份我倒認為沒什麼大問題。強調的是這種方法在 multi-thread 時會死很慘

 

Bad Architecture

 

第一次開發 xmat.h / xmat.c 時,架構其實弄得不算很好 (當下認為是應是較佳的格局),

認為可改善地方於此記下 note。

 

1. xmat.c 太過於包山包海

 

事實上所有關於 matrix 運算我都寫了進來,每份 matrix 運算還分 for real / for complex,連 basic unity operator 也都加上進來,一份 xmat.h 含蓋了超過 50 個 function declare,而這 50 個 function define,全都在 xmat.c 實作。

如果對於 matrix 議題有要細做的話,建議所有 algorithm 都獨立包成一個 .c 便可。

 

2. 太過強調例外處理

 

這問題見個見智。我拿 complex 做除法問題為例,有二份 prototype 做為選擇

 

int comp_div(struct comp * dst, struct comp a, struct comp b);  // a / b 存到 dst, 失敗傳回 0, 成功傳回 1

struct comp comp_div( struct comp a, struct comp b) ; // 直接將 a/b 結果傳回去,不做防呆措施。

 

一開始在規劃時認為直接 return value 沒做防呆很危險,於是所有函式均採用第一種方法實作下去。

開發到後面,發現沒辦法用結合性真的很麻煩[Lemma]!再選一次架構的話會挑第二種方式實作,防呆措施一律由 caller 保證。

 

最後建議,matrix 議題真的非常多,光是乘法就可以研究一小陣子,不建議在一個小地方卡著,先把所有的東西搞完一遍後,還有時間再針對有興趣的地方做深入即可。

 

[Lemma]

又想到一個面試題:為什麼 strcpy 要設計成 return pointer ?

我不知道這題有沒有正確答案,我的想法是:結合性。

len = strlen ( strcpy (buf, "EdisonX")  );

edisonx 發表在 痞客邦 PIXNET 留言(0) 人氣()