c++动态内存分配-矩阵乘法

Posted

技术标签:

【中文标题】c++动态内存分配-矩阵乘法【英文标题】:c++ dynamic memory allocation - matrix multiplication 【发布时间】:2021-10-25 18:41:09 【问题描述】:

我正在尝试进行大型矩阵乘法,例如1000x1000。不幸的是,它只适用于非常小的矩阵。对于大的,程序只是打开,仅此而已 - 没有结果。代码如下:

#include <iostream>

using namespace std;

int main() 
    int matrix_1_row;
    int matrix_1_column;
    matrix_1_row = 10;
    matrix_1_column = 10;

    int** array_1 = new int* [matrix_1_row];
    // dynamically allocate memory of size matrix_1_column for each row
    for (int i = 0; i < matrix_1_row; i++)
    
        array_1[i] = new int[matrix_1_column];
    
    // assign values to allocated memory
    for (int i = 0; i < matrix_1_row; i++)
    
        for (int j = 0; j < matrix_1_column; j++)
        
            array_1[i][j] = 3;
        
    

    int matrix_2_row;
    int matrix_2_column;
    matrix_2_row = 10;
    matrix_2_column = 10;
    // dynamically create array of pointers of size matrix_2_row
    int** array_2 = new int* [matrix_2_row];
    // dynamically allocate memory of size matrix_2_column for each row
    for (int i = 0; i < matrix_2_row; i++)
    
        array_2[i] = new int[matrix_2_column];
    
    // assign values to allocated memory
    for (int i = 0; i < matrix_2_row; i++)
    
        for (int j = 0; j < matrix_2_column; j++)
        
            array_2[i][j] = 2;
        
    

    // Result
    int result_row = matrix_1_row;
    int result_column = matrix_2_column;
    // dynamically create array of pointers of size result_row
    int** array_3 = new int* [result_row];
    // dynamically allocate memory of size result_column for each row
    for (int i = 0; i < result_row; i++)
    
        array_3[i] = new int[result_column];
    


    // Matrix multiplication
    for (int i = 0; i < matrix_1_row; i++)
    
        for (int j = 0; j < matrix_2_column; j++)
        
            array_3[i][j] = 0;
            for (int k = 0; k < matrix_1_column; k++)
            
                array_3[i][j] += array_1[i][k] * array_2[k][j];
            
        
    


    //RESULTS
    for (int i = 0; i < result_row; i++)
    
        for (int j = 0; j < result_column; j++)
        
            std::cout << array_3[i][j] << "\t";
        
    


    // deallocate memory using delete[] operator 1st matrix
    for (int i = 0; i < matrix_1_row; i++)
    
        delete[] array_1[i];
    
    delete[] array_1;
    // deallocate memory using delete[] operator 2nd matrix
    for (int i = 0; i < matrix_2_row; i++)
    
        delete[] array_2[i];
    
    delete[] array_2;
    // deallocate memory using delete[] operator result
    for (int i = 0; i < result_row; i++)
    
        delete[] array_3[i];
    
    delete[] array_3;

    return 0;

有人知道如何解决吗?我在什么时候出错了?我使用了指针,动态内存分配。

【问题讨论】:

您可以将数据存储在std::vector&lt;std::vector&lt;double&gt;&gt;中,而不是手动分配/删除内存。 首先:将所有这些包装在一个类中,这样您就不必手动调用delete[]。其次,矩阵应该只对整个数据使用单个分配,然后进行数学计算来计算索引(同样,隐藏在类中)。第三,对于具体的矩阵乘法,注意你访问内存的顺序,因为CPU缓存很重要。 关于我的第三点,请参见例如***.com/a/7395643/1405588 @Eugene Nah,单个std::vector&lt;double&gt; 要好得多,可能包装在 Matrix 类中 请发布一个无效的变体,而不是一个有效的变体。 (据我所知,这应该在几秒钟内完成。) 【参考方案1】:

不要使用直接命名为矩阵的数组,而是尝试一些简单且可扩展的方法,然后进行优化。像这样的:

class matrix 
 
    private: 
    // sub-matrices 
    std::shared_ptr<matrix> c11;     
    std::shared_ptr<matrix> c12;     
    std::shared_ptr<matrix> c21;     
    std::shared_ptr<matrix> c22; 
 
    // properties 
    const int n; 
    const int depth; 
    const int maxDepth; 
 
    // this should be shared-ptr too. Too lazy. 
    int data[16]; // lowest level matrix = 4x4 without sub matrix 
 
 
    // multiplication memory 
    std::shared_ptr<std::vector<matrix>> m; 
     
    public: 
    matrix(const int nP=4,const int depthP=0,const int maxDepthP=1): 
        n(nP),depth(depthP),maxDepth(maxDepthP) 
     
        if(depth<maxDepth) 
         
            // allocate c11,c22,c21,c22 
            // allocate m1,m2,m3,...m7 
         
     
 
    // matrix-matrix multiplication 
    matrix operator * (const matrix & mat) 
     
        // allocate result 
 
        // multiply 
        if(depth!=maxDepth) 
         
            // Strassen's multiplication algorithm 
            *m[0] = (*c11 + *c22) * (*mat.c11 + *mat.c22); 
            ... 
            *m[6] = (*c12 - *c22) * (*mat.c21 + *mat.c22); 
 
            *c11 = *m[0] + *m[3] - *m[4] + *m[6]; 
            .. 
            *c22 = .. 
         
        else 
         
            // innermost submatrices (4x4) multiplied normally 
            result.data[0] = data[0]*mat.data[0] + .... 
            ... 
            result.data[15]= ... 
         
        return result; 
     
 
    // matrix-matrix adder 
    matrix operator + (const matrix & mat) 
     
        // allocate result 
 
        // add 
        if(depth!=maxDepth) 
         
            *result.c11 = *c11 + *mat.c11; 
            *result.c12 = *c12 + *mat.c12; 
            *result.c21 = *c21 + *mat.c21; 
            *result.c22 = *c22 + *mat.c22; 
         
        else 
         
            // innermost matrix 
            result.data[0] = ... 
         
        return result; 
     
; 

通过这种方式,它的时间复杂度更低,而且看起来仍然易于阅读。在它工作之后,你可以在类内使用单块矩阵数组来优化速度,最好只在根矩阵分配一次并使用

std::span 

用于从较新 C++ 版本的子矩阵访问。它甚至可以轻松并行化,因为每个矩阵可以将其工作分配给至少 4 个线程,它们可以分配给 16 个线程、64 个线程等。但是当然,线程过多与分配过多一样糟糕,应该以更好的方式进行优化方式。

【讨论】:

shared_ptrs 在这里似乎有点浪费。真的有分享吗? 以防多线程(大尺寸)。此外,具有新 C++ 功能的数组视图 (std::span) 的单个内存块会更好。否则 unique_ptr 是好的。

以上是关于c++动态内存分配-矩阵乘法的主要内容,如果未能解决你的问题,请参考以下文章

动态内存分配(c++)

C++内存分配及变长数组的动态分配

C++ 动态分配内存

避免使用 Eigen 分解稀疏矩阵时的动态内存分配

C++程序的内存分区,为什么要使用动态内存,动态内存的分配使用释放

优化动态分配内存的变量