首页 > 解决方案 > 使用 C 将随机生成的大尺寸矩阵相乘时出错

问题描述

我的主要目的是通过在各种环境中对 C 和 Java 中的矩阵乘法算法进行基准测试来展示虚拟化与容器化的不同之处,并得出一个合适的结论。

我选择这个算法的原因是因为矩阵乘法是各种计算机科学领域中非常常用的算法,因为它们中的大多数都处理大尺寸,我希望优化我的代码以能够执行至少 2000x2000 矩阵的操作大小,这样两者之间的区别就很明显了。

我在 Linux 上使用 GCC,在 Windows 上的 Code::Blocks 中使用 C 的默认编译器(我不知道使用的是哪个版本的 GCC)。

问题是当我在 Windows 上运行代码时,编译器只接受最大为 490x490 的大小,如果我超出大小,则转储内核。Linux 设法克服了这一点,但不能超过 590x590。

我最初认为是我的设备内存是原因,并请我的几个朋友使用更好的机器运行相同的代码,但结果仍然相同。

仅供参考:我正在运行 Pentium N3540 和 4GB DDR3 RAM。我的朋友们正在运行带有 16GB DDR4 的 i7-8750H,而另一个使用带有 8GB DDR4 的 i5-9300H。

这是我写的代码:

#include <stdio.h>
#include <stdlib.h>
#define MAX 10

int main()
{
    long i, j, k, m, n;
    printf("Enter the row dimension of the matrix: "); scanf("%ld", &m);
    printf("Enter the column dimension of the matrix: "); scanf("%ld", &n);
    long mat1[m][n], mat2[m][n], mat3[m][n];

    for(i=0; i<m; i++)
        for(j=0; j<n; j++)
        {
            mat1[i][j] = (long)rand()%MAX;
            mat2[i][j] = (long)rand()%MAX;
            mat3[i][j] = 0;
        }

    printf("\n\nThe matrix 1 is: \n");
    for(i=0; i<m; i++)
    {
        for(j=0; j<n; j++)
        {
            printf("%d\t", (int)mat1[i][j]);
        }
        printf("\n");
    }

    printf("\n\nThe matrix 2 is: \n");
    for(i=0; i<m; i++)
    {
        for(j=0; j<n; j++)
        {
            printf("%d\t", (int)mat2[i][j]);
        }
        printf("\n");
    }

    for (i = 0; i < m; i++)
        for (j = 0; j < n; j++)
            for (k = 0; k < n; k++)
                mat3[i][j] += mat1[i][k] * mat2[k][j];

    printf("\n\nThe resultant matrix is: \n");
    for(i=0; i<m; i++)
    {
        for(j=0; j<n; j++)
        {
            printf("%d\t", (int)mat3[i][j]);
        }
        printf("\n");
    }
    return 0;
}

标签: cmatrixoptimizationmatrix-multiplication

解决方案


当你这样做

long mat1[m][n], mat2[m][n], mat3[m][n];

您创建一个具有自动存储持续时间的对象(又名变量)。这意味着对象在函数执行后自动创建,并在函数退出时自动销毁。

C 标准没有描述如何做到这一点。这留给实施标准的系统。最常见的方法是使用所谓的堆栈。这是为您的程序预先分配的内存区域。每当您的程序调用函数时,函数内定义的任何变量都可以放在该堆栈上。这允许为这些变量非常简单和快速地分配内存。

然而,它有一个缺点——堆栈的大小有限(而且相当小)。所以如果一个函数使用了巨大的变量,你可能会用完堆栈内存。不幸的是,大多数系统直到为时已晚才检测到这一点。

避免这种情况的简单规则是:不要定义具有自动存储持续时间的巨大变量(又名巨大的函数局部变量)。

因此,对于您的具体示例,您应该替换:

long mat1[m][n]

long (*mat1)[n] = malloc(m * sizeof *mat1); // This defines mat1 as a pointer
if (mat1 == NULL)                           // to an array of n longs and
{                                           // allocate memory of m such arrays.
    // Out of memory                        // In other words:
    exit(1);                                // A m by n matrix of long
}

// From here on you can use mat1 as a 2D matrix
// example:
mat1[4][9] = 42;

...

// Once you are done using mat1, you need to free the memory. Like:
free(mat1);

推荐阅读