1

3D ジオメトリ ライブラリ用の 4x4 マトリックス C++ クラスを開発しています。行列データ値をより効率的な方法で表現する方法について少し混乱しています。

それは、The Matrix and Quaternions FAQ に次のように書かれているからです。

2 次元配列を使用すると、C コンパイラが配列インデックス操作を解決するために乗算操作を使用することが多いため、CPU パフォーマンスが低下します。したがって、線形配列に固執する方が効率的です。

  1. 多次元配列へのアクセスは、線形配列へのアクセスよりも本当に遅いですか?
  2. 4x4 行列データ値を格納するために、多次元配列よりも線形配列を本当に好むべきでしょうか?
4

2 に答える 2

3

私が知っているほとんどの実装では、2D データにアクセスするために MACROS またはメソッドのいずれかを介して、1D 配列とラッパーを使用しています。私自身、どちらが速いかは言えませんし、これが本当に問題になるケースもほとんど見当たりません。

ただし、次の理由から 1D 配列を使用することをお勧めします。

  1. 動的に割り当てて解放するのが簡単です (データを動的に割り当てて、matrix[i][j] パターンを維持したい場合は、配列の配列を割り当てます - 割り当てが遅くなり、バグが発生しやすく、各配列を個別に解放する必要があります)
  2. 動的に割り当てて、データをOpenGLやOpenCVなどのサードパーティライブラリにコピーする必要がある場合、データが連続している必要があるため、問題が発生します。
  3. ファイルまたはその他の永続的なストレージからマトリックスを保存および読み取る方が簡単です。
  4. 動的に割り当てなくても、3d パーティ ライブラリへのメモリの転送を処理するために、あらゆる種類の醜いキャストを行う必要があります。
  5. 乗算や不明確なインデックスを使用せずに、データへの効率的な 2 次元アクセスを行うメソッドを使用して構造を作成するのは非常に簡単です。または、MACROS を使用して醜い乗算をカプセル化します。
  6. 次のサンプルのように見える構造を作成して、2 次元配列の読みやすさで 1 次元配列と同じ利点を維持することもできます。

template<typename T>
struct Matrix4x4
{
    struct index
    {
        int row, col;
        index(int r = 0, int c = 0)
            : row(r), col(c){}
        index(index const & cp)
            : row(cp.row), col(cp.col)
        {
        }
        //Assignment ommited for brevity
    };
    /*
        Constructors, Assignments etc. ommited for brevity
    */
    T m00, m01, m02, m03;
    T m10, m11, m12, m13;
    T m20, m21, m22, m23;
    T m30, m31, m32, m33;

    T * toArray() const
    {
        return &m00;
    }
    T * toArray()
    {
        return &m00;
    }

    T * row(int r)
    {
        return (&m00) + r*4;
    }
    T * row(int r) const
    {
        return (&m00) + r*4;
    }

    T & operator()(int r, int c)
    {
        return *row(r)[c];
    }
    T const & operator()(int r, int c) const
    {
        return *row(r)[c];
    }

    T & operator[](index const & idx)
    {
        return row(idx.row)[idx.col];
    }
    T const & operator[](index const & idx) const
    {
        return row(idx.row)[idx.col];
    }

};

あなたのコードでは、次のことができます。

typedef Matrix4x4<double> Matrix4x4d;

Matrix4x4d mat;
/* You can do any of the following */
mat.m23 = 6.0;
mat(2,3) = 6.0;
mat[Matrix4x4d::index(2,3)] = 6.0;
mat.row(2)[3] = 6.0;
mat.toArray()[2*4 + 3] = 6.0;

#define M(m,r,c) (*((&m.m00) + r*4 + c))

M(mat,2,3) = 6.0;

私自身、何年にもわたっていくつかの行列ライブラリを実装し、常に 1d ソリューションを選択しました。

于 2012-11-10T14:58:35.627 に答える
0

最初の次元に 1 次元配列へのポインターを格納し、2 番目の次元に行の長さを含む 1 次元配列を格納できます。

私の記憶では、間接法は乗算よりもコストがかかりません。

メンバーへのアクセス/編集の構文は同じです。唯一の違いは、配列を割り当て/割り当て解除するときです。

于 2012-11-06T19:47:30.320 に答える