C++矩阵类

发布于 2024-08-18 05:53:47 字数 469 浏览 3 评论 0原文

在 C 中,如果我想创建一个矩阵结构,我会使用:

struct matrix {
  int col, row;
  double data[1]; // I want the matrix entries stored
                  // right after this struct
}

然后我可以使用分配它

matrix* allocate_matrix(int row, int col) {
  matrix* m = malloc(sizeof(matrix) + sizeof(double) * (row * col - 1));
  m->row = row; m->col = col;
  return m;
}

现在我在 C++ 中做等价吗?

编辑:

我想知道在 C++ 中实现矩阵类的规范方法。

In C, if I wanted to create a matrix struct, I would use:

struct matrix {
  int col, row;
  double data[1]; // I want the matrix entries stored
                  // right after this struct
}

Then I can allocate it with

matrix* allocate_matrix(int row, int col) {
  matrix* m = malloc(sizeof(matrix) + sizeof(double) * (row * col - 1));
  m->row = row; m->col = col;
  return m;
}

Now do I do the equiv in C++?

EDIT:

I want to know the cannonical way to implement a matrix class in C++.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

小忆控 2024-08-25 05:53:47

注意。

这个答案现在有 20 票赞成,但它并不是对 std::valarray 的认可。

根据我的经验,最好花时间安装和学习使用成熟的数学库,例如 Eigen。 Valarray 的功能比竞争对手少,但它并不更高效或特别易于使用。

如果您只需要一点点线性代数,并且您坚决反对向工具链中添加任何内容,那么也许 valarray 会适合。但是,无法用数学上正确的方式表达问题的解决方案是一个非常糟糕的处境。数学是无情且无情的。使用适合工作的正确工具。


标准库提供 std::valarraystd::vector<>,由其他一些人建议,旨在作为对象的通用容器。 valarray 由于更加专业化(不使用“专业化”作为 C++ 术语)而鲜为人知,它具有以下几个优点:

  • 它不分配额外的空间。 向量在分配时向上舍入到最接近的2的幂,因此您可以调整它的大小,而无需每次都重新分配。 (您仍然可以调整 valarray 的大小;它仍然与 realloc() 一样昂贵。)
  • 您可以对其进行切片以轻松访问行和列。
  • 算术运算符按您的预期工作。

当然,相对于使用 C 的优点是不需要管理内存。维度可以驻留在堆栈上或切片对象中。

std::valarray<double> matrix( row * col ); // no more, no less, than a matrix
matrix[ std::slice( 2, col, row ) ] = pi; // set third column to pi
matrix[ std::slice( 3*row, row, 1 ) ] = e; // set fourth row to e

nota bene.

This answer has 20 upvotes now, but it is not intended as an endorsement of std::valarray.

In my experience, time is better spent installing and learning to use a full-fledged math library such as Eigen. Valarray has fewer features than the competition, but it isn't more efficient or particularly easier to use.

If you only need a little bit of linear algebra, and you are dead-set against adding anything to your toolchain, then maybe valarray would fit. But, being stuck unable to express the mathematically correct solution to your problem is a very bad position to be in. Math is relentless and unforgiving. Use the right tool for the job.


The standard library provides std::valarray<double>. std::vector<>, suggested by a few others here, is intended as a general-purpose container for objects. valarray, lesser known because it is more specialized (not using "specialized" as the C++ term), has several advantages:

  • It does not allocate extra space. A vector rounds up to the nearest power of two when allocating, so you can resize it without reallocating every time. (You can still resize a valarray; it's just still as expensive as realloc().)
  • You may slice it to access rows and columns easily.
  • Arithmetic operators work as you would expect.

Of course, the advantage over using C is that you don't need to manage memory. The dimensions can reside on the stack, or in a slice object.

std::valarray<double> matrix( row * col ); // no more, no less, than a matrix
matrix[ std::slice( 2, col, row ) ] = pi; // set third column to pi
matrix[ std::slice( 3*row, row, 1 ) ] = e; // set fourth row to e
暖心男生 2024-08-25 05:53:47

C++ 主要是 C 的超集。您可以继续做您正在做的事情。

也就是说,在 C++ 中,您应该做的是定义一个适当的 Matrix 类来管理自己的内存。例如,它可以由内部 std::vector 支持,并且您可以覆盖 operator[]operator() 以索引到适当地向量(例如,请参阅:如何为Matrix 类? 来自 C++ FAQ)。

让您开始使用:(

class Matrix
{
public:
    Matrix(size_t rows, size_t cols);
    double& operator()(size_t i, size_t j);
    double operator()(size_t i, size_t j) const;

private:
    size_t mRows;
    size_t mCols;
    std::vector<double> mData;
};

Matrix::Matrix(size_t rows, size_t cols)
: mRows(rows),
  mCols(cols),
  mData(rows * cols)
{
}

double& Matrix::operator()(size_t i, size_t j)
{
    return mData[i * mCols + j];
}

double Matrix::operator()(size_t i, size_t j) const
{
    return mData[i * mCols + j];
}

请注意,上面的内容不执行任何边界检查,我将其作为模板化的练习,以便它适用于 double 之外的其他内容。)

C++ is mostly a superset of C. You can continue doing what you were doing.

That said, in C++, what you ought to do is to define a proper Matrix class that manages its own memory. It could, for example be backed by an internal std::vector, and you could override operator[] or operator() to index into the vector appropriately (for example, see: How do I create a subscript operator for a Matrix class? from the C++ FAQ).

To get you started:

class Matrix
{
public:
    Matrix(size_t rows, size_t cols);
    double& operator()(size_t i, size_t j);
    double operator()(size_t i, size_t j) const;

private:
    size_t mRows;
    size_t mCols;
    std::vector<double> mData;
};

Matrix::Matrix(size_t rows, size_t cols)
: mRows(rows),
  mCols(cols),
  mData(rows * cols)
{
}

double& Matrix::operator()(size_t i, size_t j)
{
    return mData[i * mCols + j];
}

double Matrix::operator()(size_t i, size_t j) const
{
    return mData[i * mCols + j];
}

(Note that the above doesn't do any bounds-checking, and I leave it as an exercise to template it so that it works for things other than double.)

梦旅人picnic 2024-08-25 05:53:47

可以那样做。唯一的区别是您需要从 malloc 转换结果。

相反,您可以使用向量,作为具有计算索引的一维数组或嵌入向量。 (前者更符合您的代码。)

例如:

template <typename T> // often, they are templates
struct matrix
{
    // should probably be hidden away, and the class would
    // provide `at` and `operator()` for access
    int col, row;
    std::vector<T> data;

    matrix(int columns, int rows) :
    col(columns), row(rows), 
    data(col * row)
    {}

}

matrix m(4, 4);
m.data[1 + 1 * 4] = /* ... */;

或者:

template <typename T>
struct matrix
{
    int col, row;
    std::vector<std::vector<T> > data;

    matrix(int columns, int rows) :
    col(columns), row(rows), 
    data(col, std::vector(row))
    {}
}

matrix m(4, 4);
m.data[1][1] = /* ... */;

但这些只是示例。你想要开设一个成熟的课程;如果您需要更多建议,请编辑您的问题并澄清您想知道实现矩阵类的规范方法。

有预先存在的矩阵类。我最喜欢的是 boost,UBLAS。

You could do it that way. The only difference is you'd need to cast the result from malloc.

Rather, you would use a vector, either as a 1D array with computed indexing or an embedded vector. (The former matches your code better.)

For example:

template <typename T> // often, they are templates
struct matrix
{
    // should probably be hidden away, and the class would
    // provide `at` and `operator()` for access
    int col, row;
    std::vector<T> data;

    matrix(int columns, int rows) :
    col(columns), row(rows), 
    data(col * row)
    {}

}

matrix m(4, 4);
m.data[1 + 1 * 4] = /* ... */;

Or:

template <typename T>
struct matrix
{
    int col, row;
    std::vector<std::vector<T> > data;

    matrix(int columns, int rows) :
    col(columns), row(rows), 
    data(col, std::vector(row))
    {}
}

matrix m(4, 4);
m.data[1][1] = /* ... */;

But these are only examples. You'd want to make a full-fledged class; if you want more advice on that, edit your question and clarify you'd like to know the canonical way of implementing matrix classes.

There are pre-existing matrix classes. My favorite is that from boost, UBLAS.

神仙妹妹 2024-08-25 05:53:47

设置高效且高质量的矩阵类有很多微妙之处。值得庆幸的是,有一些很好的实现。

仔细考虑一下您是否需要固定大小的矩阵类还是可变大小的矩阵类。
即你能做到这一点吗?

// These tend to be fast and allocated on the stack.
matrix<3,3> M; 

或者你需要能够做到这一点吗?

// These tend to be slower but more flexible and partially allocated on the heap 
matrix M(3,3); 

有一些很好的库支持任一风格,有些库同时支持两种风格。
它们有不同的分配模式和不同的性能。

如果您想自己编码,那么模板版本需要一些模板知识(废话)。如果在紧密循环中使用,动态分配需要一些技巧来绕过大量小分配。

There's lots of subtleties in setting up an efficient and high quality matrix class. Thankfully there's several good implementations floating about.

Think hard about whether you want a fixed size matrix class or a variable sized one.
i.e. can you do this:

// These tend to be fast and allocated on the stack.
matrix<3,3> M; 

or do you need to be able to do this

// These tend to be slower but more flexible and partially allocated on the heap 
matrix M(3,3); 

There's good libraries that support either style, and some that support both.
They have different allocation patterns and different performances.

If you want to code it yourself, then the template version requires some knowledge of templates (duh). And the dynamic one needs some hacks to get around lots of small allocations if used inside tight loops.

腹黑女流氓 2024-08-25 05:53:47

您可以使用类似的模板:

#include <iostream>
using std::cerr;
using std::endl;

//qt4type
typedef unsigned int quint32;

template <typename T>
void deletep(T &) {}
template <typename T>
void deletep(T* & ptr) {
    delete ptr;
    ptr = 0;
}
template<typename T>
class Matrix {
    public:
        typedef T value_type;
        Matrix() : _cols(0), _rows(0), _data(new T[0]), auto_delete(true) {};
        Matrix(quint32 rows, quint32 cols, bool auto_del = true);

        bool exists(quint32 row, quint32 col) const;
        T & operator()(quint32 row, quint32 col);
        T operator()(quint32 row, quint32 col) const;
        virtual ~Matrix();

        int size() const { return _rows * _cols; }
        int rows() const { return _rows; }
        int cols() const { return _cols; }
    private:
        Matrix(const Matrix &);
        quint32 _rows, _cols;
        mutable T * _data;
        const bool auto_delete;
};
template<typename T>
Matrix<T>::Matrix(quint32 rows, quint32 cols, bool auto_del) : _rows(rows), _cols(cols), auto_delete(auto_del) {
    _data = new T[rows * cols];
}
template<typename T>
inline T & Matrix<T>::operator()(quint32 row, quint32 col) {
    return _data[_cols * row + col];
}
template<typename T>
inline T Matrix<T>::operator()(quint32 row, quint32 col) const {
    return _data[_cols * row + col];
}

template<typename T>
bool Matrix<T>::exists(quint32 row, quint32 col) const {
    return (row < _rows && col < _cols);
}

template<typename T>
Matrix<T>::~Matrix() {
    if(auto_delete){
        for(int i = 0, c = size(); i < c; ++i){
            //will do nothing if T isn't a pointer
            deletep(_data[i]);
        }
    }
    delete [] _data;
}

int main() {
    Matrix< int > m(10,10);
    quint32 i = 0;
    for(int x = 0; x < 10; ++x) {
        for(int y = 0; y < 10; ++y, ++i) {
            m(x, y) = i;
        }
    }
    for(int x = 0; x < 10; ++x) {
        for(int y = 0; y < 10; ++y) {
            cerr << "@(" << x << ", " << y << ") : " << m(x,y) << endl;
        }
    }
}

*编辑,修复了拼写错误。

You could use a template like :

#include <iostream>
using std::cerr;
using std::endl;

//qt4type
typedef unsigned int quint32;

template <typename T>
void deletep(T &) {}
template <typename T>
void deletep(T* & ptr) {
    delete ptr;
    ptr = 0;
}
template<typename T>
class Matrix {
    public:
        typedef T value_type;
        Matrix() : _cols(0), _rows(0), _data(new T[0]), auto_delete(true) {};
        Matrix(quint32 rows, quint32 cols, bool auto_del = true);

        bool exists(quint32 row, quint32 col) const;
        T & operator()(quint32 row, quint32 col);
        T operator()(quint32 row, quint32 col) const;
        virtual ~Matrix();

        int size() const { return _rows * _cols; }
        int rows() const { return _rows; }
        int cols() const { return _cols; }
    private:
        Matrix(const Matrix &);
        quint32 _rows, _cols;
        mutable T * _data;
        const bool auto_delete;
};
template<typename T>
Matrix<T>::Matrix(quint32 rows, quint32 cols, bool auto_del) : _rows(rows), _cols(cols), auto_delete(auto_del) {
    _data = new T[rows * cols];
}
template<typename T>
inline T & Matrix<T>::operator()(quint32 row, quint32 col) {
    return _data[_cols * row + col];
}
template<typename T>
inline T Matrix<T>::operator()(quint32 row, quint32 col) const {
    return _data[_cols * row + col];
}

template<typename T>
bool Matrix<T>::exists(quint32 row, quint32 col) const {
    return (row < _rows && col < _cols);
}

template<typename T>
Matrix<T>::~Matrix() {
    if(auto_delete){
        for(int i = 0, c = size(); i < c; ++i){
            //will do nothing if T isn't a pointer
            deletep(_data[i]);
        }
    }
    delete [] _data;
}

int main() {
    Matrix< int > m(10,10);
    quint32 i = 0;
    for(int x = 0; x < 10; ++x) {
        for(int y = 0; y < 10; ++y, ++i) {
            m(x, y) = i;
        }
    }
    for(int x = 0; x < 10; ++x) {
        for(int y = 0; y < 10; ++y) {
            cerr << "@(" << x << ", " << y << ") : " << m(x,y) << endl;
        }
    }
}

*edit, fixed a typo.

千秋岁 2024-08-25 05:53:47

如果在编译时已知矩阵大小,您可以使用模板来完成此操作:

template <int width, int height>
class Matrix{
    double data[height][width];
    //...member functions
};

you could do it with a template, if the matrix size is known at compile-time :

template <int width, int height>
class Matrix{
    double data[height][width];
    //...member functions
};
海拔太高太耀眼 2024-08-25 05:53:47

对于矩阵类,您希望避免重载 [] 运算符。
请参阅 C++ 常见问题解答 13.10

另外,搜索web 上有一些免费软件 Matrix 类。最坏的情况下,他们可以为您提供指导。最好的情况是,您需要编写和调试的软件更少。

For a matrix class, you want to stay away from overloading the [] operator.
See C++ FAQ 13.10

Also, search the web for some freeware Matrix classes. Worst case, they can give you guidance. Best case, less software that you have to write and debug.

因为看清所以看轻 2024-08-25 05:53:47

在 C++ 中没有“规范”的方法来处理矩阵,STL 不提供像“矩阵”这样的类。然而,有一些第三方库可以这样做。我们鼓励您使用它们或编写自己的实现。您可以尝试我的实现,该实现源自互联网上的一些公共实现。

There is no "canonical" way to do the matrix in C++, STL does not provide classes like "matrix". However there are some 3rd party libraries that do. You are encouraged to use them or write your own implementation. You can try my implementation derived from some public implementation found on the internet.

断桥再见 2024-08-25 05:53:47

名为 Matrix 的库支持许多功能,包括数学运算、转储和日志记录功能、关联容器、多个维度等。

用法

其用法与c++数组类似。

Matrix<int> A(1, 2);
Matrix<int> B(2, 3);
Matrix<int> result(1, 3);

A[0][0] = 7;
A[0][1] = 10;

B[0][0] = 1;
B[0][1] = 4;
B[0][2] = 2;
B[1][0] = 1;
B[1][1] = 2;
B[1][2] = 100;

result = A * B;

result.dump.matrix();

结果:

Matrix view:
-            -
| 17 48 1014 |
-            -

这是文档Github 页面

The library called, Matrix supports so many features including mathematics operations, dumping and logging features, associative containers, multiple dimensions and etc.

Usage

its usage is similar to c++ arrays.

Matrix<int> A(1, 2);
Matrix<int> B(2, 3);
Matrix<int> result(1, 3);

A[0][0] = 7;
A[0][1] = 10;

B[0][0] = 1;
B[0][1] = 4;
B[0][2] = 2;
B[1][0] = 1;
B[1][1] = 2;
B[1][2] = 100;

result = A * B;

result.dump.matrix();

Result:

Matrix view:
-            -
| 17 48 1014 |
-            -

Here is the documentation and Github page.

○闲身 2024-08-25 05:53:47

在 C++ 中你可以这样使用:

matrix *p = new matrix;

之后,

delete p; 

In C++ you can use like this:

matrix *p = new matrix;

After that,

delete p; 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文