C ++で行列をどのように表す必要がありますか?


7

私は自分に3D数学を教えており、その過程で自分の基本的なエンジン(一種)を構築しています。私のC ++マトリックスクラスを構造化する最良の方法は何だろうと思っていました。いくつかのオプションがあります:

  1. 個別のメンバー変数:

    struct Mat4 {
        float
            m11, m12, m13, m14,
            m21, m22, m23, m24,
            m31, m32, m33, m34,
            m41, m42, m43, m44;
    
        // methods
    
    }
  2. 多次元配列:

    struct Mat4 {
        float[4][4] m;
    
        // methods
    
    }
  3. ベクトルの配列

    struct Mat4 {
        Vec4[4] m;
    
        // methods
    
    }

それぞれに良い面と悪い面があると思います。

以下からのグラフィックスとゲーム開発のための3D数学入門、第2版の P.155:

n行m列の行列。 ソース(ウィキペディア)

行列は1ベースのインデックスを使用するため、最初の行と列には1の番号が付けられます。たとえば、a12aa12」ではなく「1つ2つ」と読む)は、最初の行、2列目の要素です。これは、0ベースの配列インデックスを使用するC ++やJavaなどのプログラミング言語とは異なることに注意してください。行列には列0または行0がありません。実際の配列データ型を使用して行列が格納されている場合、このインデックスの違いにより混乱が生じる可能性があります。このため、幾何学的な目的で使用される型の固定サイズの小さな行列を格納するクラスでは、float a11floatなどの言語のネイティブ配列サポートを使用する代わりに、各要素にのような独自の名前付きメンバー変数を与えるのが一般的ですelem[3][3]

つまり、メソッド1に対する1票です。

これは本当に受け入れられる方法ですか?唯一の利点が従来の数学表記に固執することであるならば、それはかなり扱いにくいようです。


2
最初にマトリックスのインターフェイス(パブリックメンバー関数)について考えます。たとえば、GetRowまたはGetForwardVectorが必要になる場合があります。それらを最も効率的に実装する方法を考えてから、内部データ構造が自然に配置されます
Maik Semder

2
C ++では、配列とメンバー変数の両方を同時に使用できますが、Union :)
API-Beast

1
多くの線形代数では、行列にいくつかの特定のセルが必要なので、私は間違いなく方法1を選びます。配列には必要な配列だけが含まれることはないため、上記の前方ベクトルのように、単純な質問では常に複数の配列にインデックスを付ける必要があります。これは、MicrosoftがXNAフレームワークでそれを行う方法でもあります(もちろん、1つの会社がそれを行うことは最善の議論ではありません)
Roy T.

2
私は間違いなくゼロインデックス配列にこだわるでしょう-私は多くの科学計算を行っており、数学とコードの間を移動するときにインデックスを変換することは、コード内で矛盾するよりもはるかに混乱しにくいです。オプション2または3を使用する場合、ルーチンが任意のサイズの行列で動作するようにする方が簡単です。これは、最終的に何かが必要になる可能性があります(たとえば、おそらく行列乗算ルーチンがあり、行列行列または行列ベクトルに使用できます)。
ジェームズ

回答:


12

なぜ選ぶのですか?あなたは両方を持つことができます。(ユニオンにより、ロジックに複雑さを追加することなく、追加のメモリ要件もありません。

struct Mat4
{
    union
    {
        struct
        {
          float m11, m12, m13, m14,
                m21, m22, m23, m24,
                m31, m32, m33, m34,
                m41, m42, m43, m44;
        };
        float[4][4] m;
    };
// methods
}

1
+1、通常はfloat [4] [4] m4x4とfloat [16] m16、および個々の要素を使用しますが、これは独自のプログラムの要件に合わせて調整するものです。
Maximus Minimus

1
ISO C ++では匿名構造が許可されていないため、この特定の機能を機能させるには、コンパイラ固有の拡張機能が必要になることがよくあります(ただし、実際には、拡張機能を備えたほとんどの主要コンパイラで機能します)。

このアプローチでうまくいくと思いますが、... ISO c ++によると、「m11、m22、...」と書かれたときに「m」と読むことは「許可」されますか?
アンドレ

1
@AndreはC ++では明示的に許可されていませんが、主要なコンパイラはすべて、文書化された拡張機能としてサポートしています(匿名ユニオンによる型パンニングと呼ばれます)。また、明示的にC.で許可されている
サム・ホスバー

1
私のケーキを食べて食べてもいいですか?たくさんの仲間に感謝します!(Dでも機能します)
bjz
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.