# 2017q1 Homework5 (matrix) contributed by<`zhanyangch`> ###### tags:`zhanyangch` `sysprog2017` `week5` ## 執行環境 ``` Architecture: x86_64 CPU 作業模式: 32-bit, 64-bit Byte Order: Little Endian CPU(s): 4 On-line CPU(s) list: 0-3 每核心執行緒數: 2 每通訊端核心數: 2 Socket(s): 1 NUMA 節點: 1 供應商識別號:   GenuineIntel CPU 家族: 6 型號: 42 Model name: Intel(R) Core(TM) i7-2640M CPU @ 2.80GHz 製程: 7 CPU MHz:      855.421 CPU max MHz: 3500.0000 CPU min MHz: 800.0000 BogoMIPS: 5587.06 虛擬: VT-x L1d 快取: 32K L1i 快取: 32K L2 快取: 256K L3 快取: 4096K NUMA node0 CPU(s): 0-3 ``` ## 原本設計的優缺點 * 閱讀程式碼 matrix.h ```cstlye #define DECLARE_MATRIX(col, row) \ typedef struct { float values[col][row]; } Mat ## col ## x ## row DECLARE_MATRIX(3, 3); DECLARE_MATRIX(4, 4); ``` `##` 為 C preprocessor 的 Concatenation,用來將兩個 token 連結,例如:DECLARE_MATRIX(3, 3);會替換成 ```clike typedef struct { float values[3][3]; } Mat3x3 ``` MatrixAlgo 函式的界面 ```clike typedef struct { void (*assign)(Matrix *thiz, Mat4x4); bool (*equal)(const Matrix *l, const Matrix *r); bool (*mul)(Matrix *dst, const Matrix *l, const Matrix *r); } MatrixAlgo; extern MatrixAlgo NaiveMatrixProvider; ``` matrix_native.c 將 priv 轉型儲存資料,在這裡是給固定大小,如果要能夠動態分配大小,要如何改寫? ```clike struct naive_priv { float values[4][4]; }; #define PRIV(x) \ ((struct naive_priv *) ((x)->priv)) ``` 浮點數無法直接比較相等,需加入誤差容許值,[此篇](http://novus.pixnet.net/blog/post/30654542-back-to-basic%3A-%E8%AB%87%E6%B5%AE%E9%BB%9E%E6%95%B8%E7%9A%84%E6%AF%94%E8%BC%83)提到當數值距離0很遠時,使用 FLT_EPSILON 絕對誤差會有問題,選取合適的絕對誤差,或是改用需較大計算量的相對誤差? ```clike static const float epsilon = 1 / 10000.0; static bool equal(const Matrix *l, const Matrix *r) { for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) if (PRIV(l)->values[i][j] + epsilon < PRIV(r)->values[i][j] || PRIV(r)->values[i][j] + epsilon < PRIV(l)->values[i][j]) return false; return true; } ``` * 優點: 利用 MatrixAlgo 切換不同實作 * 缺點: 1.函式使用不直覺, algo->function(mat),而不是 mat->function(arg) 2.只能支援 4x4 矩陣 3.mul 並未考慮 cache 的影響 ```clike #include<stdio.h> static const float epsilon = 1 / 10000.0; //static const float epsilon = 1.19209290E-07F; int main(){ float test = 0.0f; while(test + epsilon != test) test += epsilon; printf("%f\n",test); } ```