# 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 的地方先宣告一個矩陣賦值後才回傳,這樣的寫法可以學習一下