Я не могу выделить память для больших матриц, тогда ~200x200 Lapack Visual Studio в C Вот мой код

Я измеряю время выполнения решения матриц, и я не могу получить больше чем ~200x200, я должен идти, вероятно, 1500x1500 или близко к этому. Я запускаю это на VS .

#include <stdlib.h>
#include <stdio.h>
#include "lapacke.h"
#include "lapacke_config.h"
#include <time.h>

/* Auxiliary routines prototypes */
extern void print_matrix(lapack_complex_double *a, int m, int n);
extern void generate_matrix(lapack_complex_double * matrix, int w, int h);

/* Parameters */
#define N 179

/* Main program */
int main() {
    clock_t t;
    /* Locals */
    lapack_int n = N,info;
    lapack_int ipiv[N];
    lapack_complex_double a[N*N];
    lapack_complex_double b[N*N];

    FILE* fp1 = fopen("complexNumsLog.txt", "w");

    int w = 1, h = 1, h2 = 1, i = 0, j = 0; 


    for(i = 1; i <= N; i++){
        for(j = 1; j <= N; j++){
            w = i;
            h = i;
            h2 = j;

            generate_matrix(a, w, h);
            generate_matrix(b, w, h2);

            // print_matrix(a, w, h);
            // print_matrix(b, w, h2);

            // getchar(); 


            t = clock();
            info = LAPACKE_zgesv(LAPACK_ROW_MAJOR, w, h2, a, h, ipiv, b, h2);
            t = clock() - t;

            fprintf(fp1, "Matrix A: %3dx%3d ", w, h);
            fprintf(fp1, "Matrix B: %3dx%3d ", w, h2);
            fprintf(fp1, "%3d milliseconds %2.3f seconds\n",t,((float)t)/CLOCKS_PER_SEC);

            /* Check for the exact singularity */
            if( info > 0 ) {
                printf( "The diagonal element of the triangular factor of A,\n" );
                printf( "U(%i,%i) is zero, so that A is singular;\n", info, info );
                printf( "the solution could not be computed.\n" );
                getchar();
                exit( 1 );
            }
        }
        printf("%d\n", i);
    }
    getchar();
    exit( 0 );
} 

void print_matrix(lapack_complex_double* a, int m, int n) {
    int i, j;
    for( i = 0; i < m; i++ ) {
        for( j = 0; j < n; j++ )
            printf( " (%6.2f,%6.2f)", a[i*m+j].real, a[i*m+j].imag );
        printf( "\n" );
    }
    printf( "********************************************\n" );
}



void generate_matrix(lapack_complex_double * matrix, int w, int h){
    int i,j;
    double r;
    for(i = 0; i < w; i++){
        for(j = 0; j < h; j++){
            r = (rand()%1000 - 500)/100.0;
            matrix[i*w+j].real = r;
            r = (rand()%1000 - 500)/100.0;
            matrix[i*w+j].imag = r;;
        }
    }
}

2 ответа

Решение

Вы дуете свой стек. Ваша программа обычно выделяет всего несколько МБ стекового пространства, и вы пытаетесь выделить все свои данные в стеке. Когда вы превышаете 200x200, вы очень быстро исчерпываете пространство стека.

Чтобы это исправить, вам нужно либо выделить память в глобальной области видимости или в куче, где размер ограничен только вашим виртуальным адресным пространством и / или общим объемом доступной физической памяти. Поскольку размер известен во время компиляции, его проще всего выделить в глобальной области видимости:

/* Parameters */
#define N 179
lapack_int ipiv[N];
lapack_complex_double a[N*N];
lapack_complex_double b[N*N];    

/* Main program */
int main() {
    ...
}

Это вполне нормально. У вас есть этот блок объявлений в вашем коде:

lapack_int ipiv[N];
lapack_complex_double a[N*N];
lapack_complex_double b[N*N];

что, я думаю, является доминирующим распределением памяти. Я полагаю, что двойной комплекс Лапака представлен парой double и Lapack Int как int, но даже если это не так, конечный результат не сильно изменится.

Давайте возьмем некоторые стандартные значения (в байтах) для sizeof (double), 8, и sizeof (int)4.

Хорошо, мы готовы рассчитать, сколько памяти вам нужно

Memory occupation = 2*(8*2)*N² + 4*N = 32N² + 4N Bytes

Что это значит?

|    N   | Memory occupation |
|--------|-------------------|
|    50  |       80kb        |
|   100  |      320kb        |
|   150  |      721kb        |
|   500  |        8MB        |
|  1000  |       32MB        |
|  1500  |       72MB        |

Поскольку это локальные переменные, они размещаются в стеке и... вау! 72 МБ стека! Это довольно много, учитывая, что стандартный размер стека составляет 1 МБ в Windows с MSVC.

Вы можете выделить их динамически с malloc:

lapack_int *ipiv = malloc(N * sizeof (lapack_int));
lapack_complex_double *a = malloc(N * N * sizeof (lapack_complex_double);
lapack_complex_double *b = malloc(N * N * sizeof (lapack_complex_double);

но не забудьте освободить ресурсы перед выходом из функции, иначе вы потеряете (много) памяти. Делать:

free(ipiv);
free(a);
free(b);

как раз перед return,

Другие вопросы по тегам