Try   HackMD

2017q1 Homework5 (matrix)

contributed by < ryanwang522 >

開發環境

  • OS: ubuntu 16.04 LTS
  • L1d cache: 32K
    L1i cache: 32K
    L2 cache: 256K
    L3 cache: 3072K
  • Architecture:x86_64
  • CPU op-mode(s): 32-bit, 64-bit
  • Byte Order: Little Endian
  • CPU(s): 4
  • Model name: Intel® Core™ i5-4200H CPU @ 2.80GHz

開發紀錄

matrix.h

  • 看不太懂 macro 的寫法,參考 Concatenation 的說明,利用 ## operator 連接字串,讓宣告更為方便。
struct command commands[] = { { "quit", quit_command }, { "help", help_command }, … };
  • 例如上面這段 code 可以替換成
#define COMMAND(NAME) { #NAME, NAME ## _command } struct command commands[] = { COMMAND (quit), COMMAND (help),};

所以原本 matrix.h 裡的寫法就可以替換成兩次的

typedef struct { float values[3][3]; } Mat3x3 typedef struct { float values[4][4]; } Mat4x4

嘗試支援不同的 data type 和 matrix size

  • 剛看完 macro 的資料就想說來練習怎麼使用好了,雖然直接寫函式比較直觀,不過就試試看吧~
#define DECLARE_MATRIX_FLEXIBLE(type, cols, rows) \                                
    type **mat ## cols ## rows = (type **) malloc(sizeof(type *) * rows); \
    for (int i = 0; i < rows; i++) \
        mat ## cols ## rows[i] = (type *) malloc(sizeof(type) * cols)

DECLARE_MATRIX_FLEXIBLE(float, 4, 4);
  • 一開始的想法,後來弄懂 macro 後才發現這樣寫不太 ok
  • 上面這段 code 會產生 initializer element is not constant 的編譯錯誤,參考網路上的資料應該是對全域變數進行了不合法的初始化
    • 嘗試將要執行的程式碼放在函式,並藉由 define 宣告函式,在 define 一個額外的函式呼叫
#define DECLARE_MATRIX_TYPE(type) \ static type **matrix_##type(int cols, int rows) { \ type **mat ## cols ## rows = (type **) malloc(sizeof(type *) * rows); \ for (int i = 0; i < rows; i++) \ mat ## cols ## rows[i] = (type *) malloc(sizeof(type) * cols); \ return mat ## cols ## rows; } DECLARE_MATRIX_TYPE(float); #define CREATE_MATRIX(type, cols, rows) \ type **type##_mat##cols##x##rows = matrix_##type(cols, rows)
  • 藉由 DECLARE_MATRIX_TYPE(float) 定義可以動態配置一個二維陣列的 function,接著只要在 .c 檔呼叫 CREATE_MATRIX(float, 4, 4) 就可以產生一個 float ** 型態的變數 float_mat
  • 不過有個嚴重的問題就是因為變數名稱寫死所以只能用一次,雖然覺得做了不少白工,但沒關係就當作個經驗吧XD

修改 matrix_naive.cassign 函式

  • 遇到問題!
    • 如果同時要支援不同 data type ,函式的參數型態會無法區分
    • 先實作支援不同大小的矩陣
  • 直接傳 2D Array

實作支援不同大小的矩陣

  • 把之前嘗試的 macro 拿掉,修改 main()
    • 動態配置二維陣列作為 matrix
    • 捨棄先前直接寫死的矩陣,產生亂數矩陣方便測試
      • 增加一些方便的函式
      ​​​​​​​​float **alloc(int row, int col) ​​​​​​​​{ ​​​​​​​​ float **result; ​​​​​​​​ if (!(result = (float **) malloc(row * sizeof(float *)))) ​​​​​​​​ return NULL; ​​​​​​​​ for (int i = 0; i < col; i++) ​​​​​​​​ if (!(result[i] = (float *) malloc(col * sizeof(float)))) { ​​​​​​​​ free(result); ​​​​​​​​ return NULL; ​​​​​​​​ } ​​​​​​​​ return result; ​​​​​​​​} ​​​​​​​​void free_space(float ***target, int col) ​​​​​​​​{ ​​​​​​​​ for (int i = 0; i < col; i++) ​​​​​​​​ free((*target)[i]); ​​​​​​​​ free(**target); ​​​​​​​​ **target = NULL; ​​​​​​​​}
      • 學到了如何亂數產生浮點數,記得要加上 srand(time(NULL))
float randFloat(float range) { return ((float)rand() / (float)(RAND_MAX)) * range; }
  • 接著修改 assign 函式如下
static void assign(Matrix *thiz, int rows, int cols, float **data) { thiz->row = rows; thiz->col = cols; thiz->priv = malloc(cols * rows * sizeof(float)); PRIV(thiz)->values = (float **) malloc(rows * sizeof(float *)); for (int i = 0; i < cols; i++) PRIV(thiz)->values[i] = (float *) malloc(cols * sizeof(float)); for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) PRIV(thiz)->values[i][j] = data[i][j]; }
  • 這裡有個問題
    • thiz->priv = malloc(cols * rows * sizeof(float));
    • 這裡配置給 void *priv 一塊記憶體,在將 thiz->priv cast 成 struct naive_priv * ,但不懂為什麼要給 cols * rows 的大小呢
    • 先紀錄一下,再想想
  • 要注意 values 是宣告成 float ** ,要記得 malloc 空間給她否則直接存取會造成 segmentation fault

參考資料