-1

我正在尝试编写一个程序来计算两个大而密集的矩阵的乘积。当我对矩阵使用 200 x 200 尺寸时,程序运行良好,但是当我转到 300 x 300 时,我得到一个弹出窗口,上面写着“Assignment2.exe 已停止工作......”我运行了调试器,我得到了这个错误消息:“程序收到信号 SIGSEGV,分段错误。”

我知道明显的罪魁祸首是矩阵的大小太大,但我想知道是否有任何方法可以优化我的程序,以便它可以处理更大的矩阵(不更改函数原型,因为这些是一成不变的那作业)。在 MATLAB 中,我能够处理比这更大的矩阵大小。我感谢您的帮助。谢谢!

这是我的代码:

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <random>

using namespace std;

int matrix_multiply(int n1, int n2, int n3, double *a, double *b, double *c);
int matrix_fill_random(int n1, int n2, double *a);
int matrix_print(int n1, int n2, double *a);


int matrix_multiply(int n1, int n2, int n3, double *a, double *b, double *c)
{
    int i;
    int j;
    int k;

    for (i=0;i<n1;i++) {
        for (j=0;j<n3;j++) {
            *(c+(i*n3)+j) = 0;
            for (k=0;k<n2;k++) {

                *(c+(i*n3)+j) += (*(a+(i*n2)+k) * (*(b+(k*n3)+j)));
            }
        }
    }
    return 0;
}

int matrix_fill_random(int n1, int n2, double *a)
{
    int i;
    for (i=0;i<(n1*n2);i++) {
        *(a+i) = rand() % 20001 - 10000;
        *(a+i) /= 10000;
    }
    return 0;
}

int matrix_print(int n1, int n2, double *a)
{
    int i;
    int j;

    cout << "\n" << endl;

    for (i=0;i<n1;i++) {
        for (j=0;j<n2;j++) {
            if (*(a+(i*n2)+j) >= 0) {
                cout << " ";
            }
            cout << *(a+(i*n2)+j) << "\t";
        }
        cout << " " << endl;
    }
    return 0;
}

int main() {

    int numRowsA;
    int numColsA;
    int numColsB;
    int numIterations;
    int i;
    srand((unsigned int)time(0));

    cout << "Please enter in the number of rows for Matrix A: ";
    cin >> numRowsA;
    cout << "Please enter in the number of columns for Matrix A: ";
    cin >> numColsA;
    cout << "Please enter in the number of columns for Matrix B: ";
    cin >> numColsB;
    cout << "Please enter in the number of iterations for repeating the multiplication: ";
    cin >> numIterations;

    double A[numRowsA][numColsA];
    double B[numColsA][numColsB];
    double C[numRowsA][numColsB];

    matrix_fill_random(numRowsA,numColsA,(&A[0][0]));
    matrix_fill_random(numColsA,numColsB,(&B[0][0]));

    clock_t beforeMult;
    clock_t afterMult;
    clock_t ticks;
    float seconds;
    float secondsPerIteration;

    beforeMult = clock();

    for (i=0;i<numIterations;i++){
        matrix_multiply(numRowsA,numColsA,numColsB,(&A[0][0]),(&B[0][0]),(&C[0][0]));
        delete C;
    }

    afterMult = clock();

    ticks = afterMult - beforeMult;
    seconds = (float(ticks))/numIterations;
    secondsPerIteration = seconds/CLOCKS_PER_SEC;

    cout << "The number of total clock ticks is: " << ticks << endl;
    cout << "The number of ticks per multiplication is: " << seconds << endl;
    cout << "The number of seconds per multiplication is: "  << secondsPerIteration << endl;

    delete A;
    delete B;
    delete C;
}
4

2 回答 2

2

这样做显然是错误的:

delete A;
delete B;
delete C;

因为A,B并且C在这里创建:

double A[numRowsA][numColsA];
double B[numColsA][numColsB];
double C[numRowsA][numColsB];

这些行中没有new。如果您没有调用new创建某些东西,那么您不应该使用delete. 如果使用new创建二维数组,您很可能需要使用循环来为每一行分配列,然后反向使用相同的方法来删除它 - 使用delete [], 因为您正在删除数组。

上面的代码也不符合 C++ 标准,因为标准 C++ 中任何数组的大小都必须是编译时常量。您正在从用户那里读取大小,因此大小显然不是编译时常量。并且使用较大的列和行值可能会导致在堆栈上分配空间时出现问题,即使编译器允许这样做。大多数系统的默认堆栈大小约为 1-4MB(因此最多最多约 500k 双倍)。一旦你用完了它,它就“游戏结束”了,此时你无法恢复。所以最好避免用完堆栈。这又带回了循环分配适量内存的想法。但是,我建议您使用std::vector而不是原始指针或数组,如下所示:

std::vector<std::vector <double> > A;

A.resize(numrowsa);
for(int i = 0; i < numrowsa; i++)
{
    A[i].resize(numcolsa); 
}

对于 B 和 C 也是如此。

于 2013-09-28T17:20:44.677 回答
0

使用new运算符对我有用,如以下代码所示:

double *A = new double[numRowsA*numColsA];
double *B = new double[numColsA*numColsB];
double *C = new double[numRowsA*numColsB];
于 2013-09-29T02:30:54.753 回答