添加OpenMP以编程以计算n×n矩阵n x n的行列式

时间:2015-01-09 13:42:22

标签: c++ multithreading matrix openmp

这是找到矩阵n x n的行列式的代码。

#include <iostream>

using namespace std;

int determinant(int *matrix[], int size);
void ijMinor(int *matrix[], int *minorMatrix[], int size, int row, int column);

int main()
{
    int size;
    cout << "What is the size of the matrix for which you want to find the determinant?:\t";
    cin >> size;

    int **matrix;
    matrix = new int*[size];
    for (int i = 0 ; i < size ; i++)
        matrix[i] = new int[size];

    cout << "\nEnter the values of the matrix seperated by spaces:\n\n";
    for(int i = 0; i < size; i++)
        for(int j = 0; j < size; j++)
            cin >> matrix[i][j];

    cout << "\nThe determinant of the matrix is:\t" << determinant(matrix, size) << endl;

    return 0;
}

int determinant(int *matrix[], int size){
    if(size==1)return matrix[0][0];
    else{
        int result=0, sign=-1;
        for(int j = 0; j < size; j++){

            int **minorMatrix;
            minorMatrix = new int*[size-1];
            for (int k = 0 ; k < size-1 ; k++)
                minorMatrix[k] = new int[size-1];

            ijMinor(matrix, minorMatrix, size, 0, j);

            sign*=-1;
            result+=sign*matrix[0][j]*determinant(minorMatrix, size-1);
            for(int i = 0; i < size-1; i++){
                delete minorMatrix[i];
            }
        }

        return result;
    }
}

void ijMinor(int *matrix[], int *minorMatrix[], int size, int row, int column){
    for(int i = 0; i < size; i++){
        for(int j = 0; j < size; j++){
            if(i < row){
                if(j < column)minorMatrix[i][j] = matrix[i][j];
                else if(j == column)continue;
                else minorMatrix[i][j-1] = matrix[i][j];
            }
            else if(i == row)continue;
            else{
                if(j < column)minorMatrix[i-1][j] = matrix[i][j];
                else if(j == column)continue;
                else minorMatrix[i-1][j-1] = matrix[i][j];
            }
        }
    }
}

添加OpenMP pragma后,我已经更改了行列式功能,现在它看起来像这样:

int determinant(int *matrix[], int size){
    if(size==1)return matrix[0][0];
    else{
        int result=0, sign=-1;
        #pragma omp parallel for default(none) shared(size,matrix,sign) private(j,k)  reduction(+ : result)

        for(int j = 0; j < size; j++){

            int **minorMatrix;

            minorMatrix = new int*[size-1];

            for (int k = 0 ; k < size-1 ; k++)
                minorMatrix[k] = new int[size-1];

            ijMinor(matrix, minorMatrix, size, 0, j);

            sign*=-1;
            result+=sign*matrix[0][j]*determinant(minorMatrix, size-1);
            for(int i = 0; i < size-1; i++){
                delete minorMatrix[i];
            }
        }

        return result;    
        delete [] matrix;
    }
}

我的问题是结果每次都不同。有时它会给出正确的价值,但大多数情况下都是错误的。我认为这是因为sign变量。我遵循这个公式:

Formula

正如您所看到的,在for循环的每次迭代中都应该有不同的sign,但是当我使用OpenMP时,出现了问题。如何使该程序与OpenMP一起运行?

最后,我的第二个问题是使用OpenMP不会使程序比没有OpenMP更快地运行。我还尝试制作100,000 x 100,000矩阵,但我的程序报告了有关分配内存的错误。如何用非常大的矩阵运行这个程序?

1 个答案:

答案 0 :(得分:1)

我认为你的问题如下:

1)正如Hristo所指出的,你的线程正在踩着彼此关于sign变量的数据。它应该是每个线程的私有,以便它们具有完全的读/写访问权限,而不必担心竞争条件。然后,您只需要一个算法来计算sign是加1还是减1,具体取决于迭代j 独立来自其他迭代。通过一点思考,你会发现Hristo的建议是正确的:sign = (j % 2) ? -1 : 1;应该这样做。

2)您的determinant()函数是递归的。就像这样,这意味着循环的每次迭代,在形成你的未成年人之后,你再次在那个未成年人上调用你的函数。因此,单个线程将执行其迭代,输入递归函数,然后尝试将自己拆分为nthreads个更多线程。您现在可以看到如何超额订阅系统通过启动比实际拥有核心更多的线程。两个简单的解决方案:

  • omp parallel代码中调用原始的串行函数。这是最快的方法,因为这样可以避免任何OpenMP启动开销。
  • 在第一次调用omp_set_nested(0);之前致电determinant(),关闭嵌套并行性。
  • 将if子句添加到parallel for指令:if(omp_in_parallel())

3)你的内存问题是因为你的递归的每次迭代,你分配更多的内存。如果您修复问题#2,那么您应该在串行情况下使用与并行情况相当的内存量。话虽这么说,在输入算法之前分配所需的所有内存会好得多。分配大块内存(然后释放它!),特别是并行分配,是代码中一个可怕的瓶颈。

在进入第一个循环之前计算您需要的内存量(在纸面上)并一次性分配所有内存。我还强烈建议你考虑连续分配你的内存(也就是一维),以便更好地利用缓存。请记住,每个线程都应该有自己独立的区域。然后,将您的功能更改为:

int determinant(int *matrix, int *startOfMyWorkspace, int size)

不是在循环内部分配新的(size-1)x(size-1)矩阵,而是简单地利用工作区的下一个(size-1)*(size-1)整数,更新startOfMyWorkspace下一次递归调用的内容,并继续。

相关问题