Try   HackMD

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
#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);會替換成

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

MatrixAlgo 函式的界面

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 轉型儲存資料,在這裡是給固定大小,如果要能夠動態分配大小,要如何改寫?

struct naive_priv {
    float values[4][4];
};

#define PRIV(x) \
    ((struct naive_priv *) ((x)->priv))

浮點數無法直接比較相等,需加入誤差容許值,此篇提到當數值距離0很遠時,使用 FLT_EPSILON 絕對誤差會有問題,選取合適的絕對誤差,或是改用需較大計算量的相對誤差?

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 的影響
#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);
}