# 2017q1 Homework5 (matrix) contributed by `<yangyang95>` ###### tags: `sysprog2017` `HW5` `yangyang95` 開發環境看 [這裡](https://hackmd.io/s/HJ2c_XYKx) 作業要求看 [這裡](https://hackmd.io/s/rkrrpHm2e#作業要求) github page 看 [這裡](https://github.com/yangyang95/matrix_oo) ## Makefile 解說 這次作業的 makefile 寫的非常簡潔漂亮,趕快來學習一下 下面這段使用萬用字元 `%` 產生 object file ```makefile== OBJS := \ stopwatch.o \ matrix_naive.o deps := $(OBJS:%.o=%.o.d) OBJS := $(addprefix $(OUT)/,$(OBJS)) deps := $(addprefix $(OUT)/,$(deps)) ``` 這行 `deps := $(OBJS:%.o=%.o.d)` 把 `OBJS` 內所有的 .o 改成 .o.d 再傳到 `deps` 再來 `OBJS := $(addprefix $(OUT)/,$(OBJS))` 利用字串函式 `addprefix` 加入<s>資料夾</s> 目錄路徑 :::danger directory 的中文翻譯是「目錄」,不是「資料夾」(folder),UNIX 使用 directory 這詞,請注意 --jserv ::: 最後得到的結果是: OBJS = .build/stopwatch.o .build/matrix_naive.o deps = .build/stopwatch.o.d .build/matrix_naive.o.d 我對這段稍微修改一下,程式變短卻可得到一樣結果 ```makefile== OBJS := \ stopwatch.o \ matrix_naive.o OBJS := $(addprefix $(OUT)/,$(OBJS)) deps := $(OBJS:%.o=%.o.d) ``` .d 檔可以把~~程式碼內 `#include` 的函式庫資訊~~ 個別 compilation unit 的相依性儲存起來 :::danger 不是函示庫的資訊,是個別 compilation unit 的相依性。你可以送一個簡化 Makefile 的 pull request 到 GitHub 上 --jserv ::: :::info PR已送 --yangyang95 ::: 下面說明這段 ```makefile== $(OUT)/%.o: %.c $(OUT) $(CC) $(CFLAGS) -c -o $@ -MMD -MF $@.d $< ``` `-MMD` 標籤是用來自動生成依賴性 (連結 .d 檔) `-MF file` : When used with -M or -MM, specifies a file to write the dependencies to 參考資料: * [twzjwang HackMD 筆記](https://hackmd.io/s/rkFhTyK3x#解析) ## matrix 解說 這段程式碼太漂亮惹... ```C== #define DECLARE_MATRIX(col, row) \ typedef struct { float values[col][row]; } Mat ## col ## x ## row DECLARE_MATRIX(3, 3); DECLARE_MATRIX(4, 4); ``` 定義矩陣使用 `DECLARE_MATRIX(col, row);` ,就可以把這個結構漂漂亮亮的拿來用 ``` (Mat4x4) { .values = { { 1, 2, 3, 4, }, { 5, 6, 7, 8, }, { 1, 2, 3, 4, }, { 5, 6, 7, 8, }, } ``` ## n*m 矩陣處理 ```C== static float* matrix_alloc(int row, int col) { float *values = (float *)calloc(row * col, sizeof(float)); return values; } static Matrix* create(int row, int col) { Matrix *matrix = (Matrix*)malloc(sizeof(Matrix)); matrix->row = row; matrix->col = col; matrix->priv = matrix_alloc(row, col); return matrix; } ``` 改用 float 陣列儲存矩陣的資料,並建立 `matrix_alloc` 函式來做陣列動態宣告 並且在矩陣結構加入 `create` 的方法,用以宣告矩陣的大小 實際使用: ```C== float A[4][5] = { { 1, 2, 3, 4, 5,}, { 5, 6, 7, 8, 9,}, { 1, 2, 3, 4, 5,}, { 5, 6, 7, 8, 9,}, }; Matrix *m; m = algo->create(4, 5); algo->assign(m, *A); ``` ## 矩陣列印 加入新的方法用來列印矩陣 ```C== static void print(Matrix *thiz) { int col = thiz->col; for (int i = 0; i < thiz->row; i++) { for (int j = 0; j < thiz->col; j++) { printf("%5g ", PRIV(thiz)[i*col + j]); } printf("\n"); } } ``` ## StopWatch 直接來看 `test-stopwatch.c` 的程式碼 ```C== int main() { watch_p ctx = Stopwatch.create(); if (!ctx) return -1; Stopwatch.start(ctx); for (int i = 0; i < 5; i++) { printf("\b %d\r", i);; fflush(stdout); sleep(1); } double now = Stopwatch.read(ctx); Stopwatch.destroy(ctx); return !now; } ``` 用法相當好懂 `create -> start -> read -> destroy` 大部分的 `stopwatch.c` 程式碼都挺好理解的,這邊拉出其中一個 helper function `time_add` 說明 ```C== static struct timespec time_add(struct timespec t1, struct timespec t2) { long sec = t2.tv_sec + t1.tv_sec; long nsec = t2.tv_nsec + t1.tv_nsec; if (nsec >= 1000000000) { nsec -= 1000000000; sec++; } return (struct timespec) { .tv_sec = sec, .tv_nsec = nsec }; } ``` 這邊在做時間進位,nanosecond 超過 $10^9$ 時進位成 second 特別的是,return 的地方先宣告一個矩陣賦值後才回傳,這樣的寫法可以學習一下