【问题标题】:Is a vector<vector<double>> a good way to make a matrix class?vector<vector<double>> 是制作矩阵类的好方法吗?
【发布时间】:2012-08-10 00:00:42
【问题描述】:

我是一名数学学生,对 C++ 很陌生,为了帮助我的学习,我想创建一个矩阵类(我不想使用库类)。我正在考虑做类似的事情

int iRows = 5;
int iColumns = 6;
double** pMatrix = new double*[iRows];
for (int i = 0; i < iRows; ++i) {
    pMatrix[i] = new double[iColumns];
}

(我不确定这是否是正确的语法 - 我想在尝试之前在这里获得建议)但我在 Stackoverflow 看到不推荐使用不像 shared_ptr 的指针。使用vector&lt;vector&lt;double&gt;&gt; 是不是更好,这样我就不用担心删除内存了?我担心向量不是一个好的选择,因为长度可以用 push_back 改变,我希望矩阵的大小是固定的。我无法使用

double dMatrix[iRows][iColumns];

因为尺寸不是恒定的。什么是我使用的最佳选择?

【问题讨论】:

  • “我不想使用库类”——Eeeeet,错了。您确实想使用一个,除非是出于学习目的自己编写一个。另外,不,它不是一个很好的矩阵近似值,因为doubles 将遍布整个内存。最好使用一维向量并自己调整索引。
  • 那里有很多矩阵 API,为什么不看看他们是如何做到的。如果您只需要某些尺寸(如 3x3、4x4 等),那么您可以使用 2d 数组为每个尺寸创建一个类。
  • @Xeo 是的,这正是我想要做的——学习目的是为了更好地使用 C++ 做一些实际的事情。感谢所有建议。

标签: c++ vector matrix


【解决方案1】:

不,绝对不是。都没有

vector<vector<double>> matrix;

也没有

double** matrix;

是矩阵类的好布局。尽管您的课程可能会很好地熟悉编程,但此类矩阵课程的性能会较差。问题是您丢失了数据局部性。只需考虑您的代码

for (int i = 0; i < iRows; ++i) {
    pMatrix[i] = new double[iColumns];
}

对于高效的矩阵向量乘法,您应该在缓存中拥有尽可能多的矩阵值,否则内存传输将花费太多时间。 当您每行获取一个内存块时,无法保证这些数据垃圾在内存中紧密相连。对于简单的矩阵向量乘法,这可能并不算太糟糕,因为行元素仍然是连续存储的,并且“只有”从一行到下一行的跳转会导致缓存未命中。

但是,对转置矩阵进行操作确实是一个问题,因为沿列的值可能存储在内存中的任何位置,并且没有合理的方法来确定可用于缓存预取的那些元素之间的步幅。

因此,正如其他作者所建议的,为您的矩阵使用一大块内存。这需要您付出更多的努力,但它会为您的矩阵类的用户带来回报。

【讨论】:

    【解决方案2】:

    我会先问自己:你想达到什么目标?您是想创建一些东西作为学习练习,还是想要一个体面的矩阵实现?

    如果您想将此作为学习练习,那么我建议您仅在内部使用带有 MxN 元素的一维双精度向量。创建一个在内部存储它但对调用者隐藏实现的类——他们不应该知道或关心它是如何存储的。作为界面的一部分,您通常希望通过运算符 (m,n) 访问它,例如

    double& MyMatrix::operator()(int m, int n) {
      return m_Array[m*numColumns + n];
    } 
    

    一旦你尝试用它做更多有趣的事情,比如加法和乘法,你就会意识到你必须重载算术运算符。不仅是operator+operator-,还有运算符 *、/、*=、+=、-= /=、++、--。当您实现乘法时,您可能会发现您的实现可能太慢而无法使用,因为您可能会发现您正在制作大量冗余副本。 YMMV

    因此,如果您想要一个快速矩阵库,那么您将需要一个在内部使用 BLAS 的库,例如 Boost 的 Basic Linear Algebra library

    也许然后自己先尝试一下,以了解获得良好设计的问题,然后看看 boost,因为通过研究你会学到很多东西。

    【讨论】:

    • 感谢您的回答。是的,正如我在问题中所说的那样,我想将其作为学习练习。我会按照你的建议去做。
    • 在这种情况下,还请查看编译器提供的 &lt;valarray&gt; 标头,因为它具有 operator+/- 的示例实现。我以前用它作为算术向量的基础。需要注意的一件事是,由于分配,A=B+C; 对矩阵的操作有多昂贵。阅读move semantics,了解如果您有最新的编译器,如何降低成本。
    【解决方案3】:

    大概

    std::vector<double> matrix(rows * columns); // ditch the prefixes
    // indexing: matrix[row * columns + column];
    

    因为无论如何每一行都会有相同数量的列。

    【讨论】:

      猜你喜欢
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-16
      • 2011-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多