3

私のマトリックスクラスでは、次のことを行いました。

template<typename T, std::uint32_t Height, std::uint32_t Width>
class Matrix
{
    private:
        std::array<std::array<T, Width>, Height> Elements;
        static_assert(std::is_arithmetic<T>::value, "Argument T must be of arithmetic type.");

    public:
        Matrix();
        Matrix(T* Data);
        Matrix(T** Data);
        Matrix(T Data[Height][Width]);
        Matrix(const std::array<std::array<T, Width>, Height> &Data);

        inline int size() {return Width * Height;}
        inline const int size() const {return Width * Height;}

        inline int width() {return Width;}
        inline const int width() const {return Width;}

        inline int height() {return Height;}
        inline const int height() const {return Height;}

        std::array<T, Width>& operator[](int Index);
        const std::array<T, Width>& operator[](int Index) const;

        Matrix& operator = (const Matrix &M);

        Matrix& operator + (const Matrix &M);

        Matrix& operator - (const Matrix &M);

        Matrix& operator * (const Matrix &M);
};

template<typename T, std::uint32_t Height, std::uint32_t Width>
Matrix<T, Height, Width>::Matrix() {std::memset(&Elements, 0, sizeof(T) * Width * Height);}

template<typename T, std::uint32_t Height, std::uint32_t Width>
Matrix<T, Height, Width>::Matrix(T* Data) {if (Data) std::memcpy(&Elements, Data, sizeof(T) * Width * Height);}

template<typename T, std::uint32_t Height, std::uint32_t Width>
Matrix<T, Height, Width>::Matrix(T** Data) {if (Data) std::memcpy(&Elements, &Data[0][0], sizeof(T) * Width * Height);}

template<typename T, std::uint32_t Height, std::uint32_t Width>
Matrix<T, Height, Width>::Matrix(T Data[Height][Width]) {std::memcpy(&Elements, &Data[0][0], sizeof(T) * Width * Height);}

template<typename T, std::uint32_t Height, std::uint32_t Width>
Matrix<T, Height, Width>::Matrix(const std::array<std::array<T, Width>, Height> &Data) {std::memcpy(&Elements, &Data[0][0], sizeof(T) * Width * Height);}

template<typename T, std::uint32_t Height, std::uint32_t Width>
std::array<T, Width>& Matrix<T, Height, Width>::operator[](int Index) {return Elements[Index];}

template<typename T, std::uint32_t Height, std::uint32_t Width>
const std::array<T, Width>& Matrix<T, Height, Width>::operator[](int Index) const {return Elements[Index];}

私はオンラインで読み、ベクトルを使用せず、代わりに配列を使用するか、std::valarray を使用するという多くのコメントを読んだためです。

今私が尋ねている理由は、私がやり続ける必要がないようにマトリックスクラスを書き直したいからMatrix<Type, Width, Height>です.毎回..コンストラクターで一度それを行い、それを入力する必要はありませんすべての単一の機能について..上記のように。たとえば、各関数と各 Matrix 引数に対して、長いテンプレート宣言を書き出す必要があります。また、ベクトルのサイズ変更/プッシュバックを削除する方法がわからなかったので、ユーザーがベクトルにインデックスを付けたときにサイズを変更できないため、配列を使用しました。

1D 配列を使用してインデックスを作成しようとしましたが (I * Width + J)、[][] 演算子が失われます。

ベクトルのベクトルを使うのは悪いことですか? クラスを改善し、RAII 準拠を維持するためのアイデアはありますか? valarray の使用方法がよくわかりません。上記は維持するのが面倒です。どんなアイデアでも大歓迎です。

4

3 に答える 3

12

ベクトルのベクトルが最良のアプローチではないことは事実です。データが長方形 (ギザギザではない) であると仮定すると、ベクトルのベクトル アプローチによって行われる割り当てには非効率性があり、言うまでもなく、やや一般的な「形状変更」操作 (「2x3 マトリックスを 3x2 または 6x1 なしで扱う」コピー」)。

1D 配列を使用してインデックスを作成しようとしましたが (I * Width + J)、[][] 演算子が失われます。

もちろん、1D ベクトルを使用してください。それは素晴らしいことです。次に、サイズを変更したり、形状を変更したりして、多くの操作でほぼ最適なパフォーマンスを得ることができます。そして、あなたはRAIIを維持します。

しかし、二重添え字 ( ) の機能を失いたくないです[x][y]か? わかった。リターンをプロキシオブジェクトにするだけoperator[]です(実装します)。operator[]プロキシには、2 番目の軸で動作する独自のプロキシがあります。つまり、最初[]のオブジェクトは、2 番目のオブジェクトを実装するのに十分なだけのことを知っている軽量オブジェクトを返します[]

于 2013-06-09T02:13:27.520 に答える
0

vector<T>密行列クラスのバッキング ストアに使用してもまったく問題vector<T>ありませんが、naive ではなく 1 つを使用してくださいvector<vector<T>>。また、幅、高さ、および行/列の主要な順序付けを、マトリックス クラスのランタイム プロパティにします。

問題vector<vector<T>>は、N 個の動的割り当てを使用することです。ここで、N は行または列の数です。1 つの動的割り当てを使用するため、行列を 1 つの次元優先順序ブロックに格納する方が効率的です。

また、行/列の主要な順序付けをランタイム プロパティにすることで、転置操作は一定時間行われます。

クラスの実際の行列演算には、オペランドと結果インスタンスのバッキング ストアを渡すことができる BLAS と呼ばれる標準インターフェイスがあります。特定の CPU の非常に低レベルのパフォーマンス機能を使用するすべてのプラットフォーム用に高度に最適化された BLAS 実装があり、標準の C++ で表現できるものよりもはるかに高速です。

于 2013-06-09T11:14:27.707 に答える
0

1D 配列を使用する場合でも、[][] 演算子を実装できますが、セキュリティが少し低下します。

内部データが T* (最も基本的な形式) であるとしましょう。行の最初の要素へのポインターを返すことができます。

template<typename T>
class Matrix
{
    private:
        int height_, width_;
        T* data_;
    public:
        Matrix(int height, int width):
                height_(height),
                width_(width) {
            data_ = new T[height * width];
            std::fill(data_, data_ + height * width, T());
        }
        T* operator[](const int &row) { // i'm returning a pointer to the start of the row
            return data_ + width_ * row;
        }

        const T* operator[](const int &row) const {
            return data_ + width_ * row;
        }
};

int main() {
    Matrix<int> M(5, 5);

    M[3][3] = 1;
    M[3][5] = 2; // this is bad but will work and actually fill the next cell

    std::cout << M[4][0] << std::endl;
}

これは2を印刷します

于 2013-06-10T10:52:29.843 に答える