카테고리 없음

[C/행렬] 동적 메모리 이용해서 행렬곱 함수 구현하기

미친토끼 2021. 3. 3. 00:16
// 행렬곱 구하는 함수: matrixMul.c
// 동적 메모리를 이용해 행렬곱 함수를 모듈화했다.
// 함수에 x 매트릭스, y 매트릭스, 각 매트릭스의 행과 열 shape를 전달해야 한다.

#include <stdio.h>
#include <stdlib.h>

//2차원 배열(행렬)과 그 shape을 입력받아 출력하는 함수.
void printMatrix(int *array[], int row, int col) {
	int i, j;
	for (i = 0; i < row; i++) {
		for (j = 0; j < col; j++)
			printf("%d\t", array[i][j]);
		printf("\n");
	}
}

// 동적 할당 매트릭스 x와 그 쉐입,  동적 할당 매트릭스 y와 그 쉐입을 인자로 주면 
// 행렬곱 함수에서 행렬곱을 계산해서 동적 할당 매트릭스에 저장해 그 포인터를 돌려준다.
// main에서 2차원 정적 배열로 함수에 인자로 전달하면 함수 매개변수에 그것을 표시해야 해서 범용적이지 못하다.
// 그래서 번거롭지만 main에서 x와 y 매트릭스를 동적 할당해서 그 주소를 함수에 전달하고 
// 함수에서는 동적 매트릭스 z를 생성하여 행렬곱의 계산 결과를 저장해 그 포인터를 전달한다.  
// 이 행렬곱 함수는 필자가 짠 전치행렬 함수에서 일부를 가져왔다.

int ** matrixMul(int *x[], int x_row, int x_col, int *y[], int y_row, int y_col) {
    if (x_col != y_row) {
       printf("Wrong shapes: x의 컬럼수와 y의 행수는 같아야 합니다.\n");
       return 0;
    }
   
    int **z = (int **)calloc(x_row, sizeof(int *));
	for (int i = 0; i < x_row; i++) {
		z[i] = (int *)calloc(y_col, sizeof(int));
	}

    for (int i = 0; i < x_row; i++) { //z의 행
        for (int j = 0; j < y_col ; j++) { //z의 열
            for (int k = 0; k < x_col; k++) {
                z[i][j] += x[i][k] * y[k][j];
             }
        }
    }
            //x의 shape이 (2,3)이고 y의 shape은 (3,2)일 때 z의 shape은 (2,2)가 되므로 수동으로 계산하면 아래와 같다. 
            // 인덱스의 움직임을 잘 보면, i, j, k중 어떤 값을 따라가야할지 감이 잡힌다.
            /* z[0][0] = x[0][0]*y[0][0] + x[0][1]*y[1][0] + x[0][2]*y[2][0]; 
               z[0][1] = x[0][0]*y[0][1] + x[0][1]*y[1][1] + x[0][2]*y[2][1];
               z[1][0] = x[1][0]*y[0][0] + x[1][1]*y[1][0] + x[1][2]*y[2][0];
               z[1][1] = x[1][0]*y[0][1] + x[1][1]*y[1][1] + x[1][2]*y[2][1];*/
    return z;
}

int main() {
   // 메모리 동적 할당을 해서 x 매트릭스와 y매트릭스를 만들고 그 정보를 행렬곱 함수에 전달한다.
   // 원하는 데이터와 shape을, 아래의 한 블럭 6줄을 추가해서 구할 수 있다.
   
    /* 
    int arr1[2][3] = {{1, 2, 3}, { 4, 5, 6}};
    int arr2[3][2] = {{1,2}, {3, 4}, {5, 6}};
    int x_row = 2;
    int x_col = 3;
    int y_row = 3;
    int y_col = 2;
    */
    
    /*int arr1[1][4] = {{1,2,3,4}};
    int arr2[4][1] = {{1},{2},{3},{4}};
    int x_row = 1;
    int x_col = 4;
    int y_row = 4;
    int y_col = 1;*/
  
    // (4 ,1) * (1, 4) = (4 ,4)행렬임
    /*int arr1[4][1] = {{1},{2},{3},{4}};
    int arr2[1][4] = {{1,2,3,4}};
    int x_row = 4;
    int x_col = 1;
    int y_row = 1;
    int y_col = 4;*/


    int arr1[4][2] = {{0, 1}, {2, 3}, {4, 5}, {6, 7}};
    int arr2[2][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}};
    int x_row = 4;
    int x_col = 2;
    int y_row = 2;
    int y_col = 4;

    int **x = NULL; 
    int **y = NULL;

    x = (int **)calloc(x_row, sizeof(int *));
    for (int i = 0; i < x_row; i++) {
        x[i] = (int *) calloc(x_col, sizeof(int));
        for (int j = 0; j < x_col; j++) {
            x[i][j] = arr1[i][j];
        }
    }
   
    printMatrix(x, x_row, x_col);
    printf("\n");
  
    y = (int **)calloc(y_row, sizeof(int *));
    for (int i = 0; i < y_row; i++) {
        y[i] = (int *) calloc(y_col, sizeof(int));
        for (int j = 0; j < y_col; j++) {
            y[i][j] = arr2[i][j];
        }
    }
 
    printMatrix(y, y_row, y_col); 
    printf("\n");
    
    int **z = matrixMul(x, x_row, x_col, y, y_row, y_col);
    printMatrix(z, x_row, x_row);
   
    //main에서 할당 받은 x 메모리 해제
	for (int i = 0; i < x_row; i++)
		free(x[i]);
	free(x);

	//main에서  할당 받은 y 메모리 해제
	for (int i = 0; i < y_row; i++)
		free(y[i]);
	free(y);

    //함수에서 할당 받은 z 메모리 해제
    //
    for (int i = 0; i < x_row; i++)
        free(z[i]);
    free(z);

	return 0;
}


----- 실행 결과 -----
0	1	
2	3	
4	5	
6	7	

0	1	2	3	
4	5	6	7	

4	5	6	7	
12	17	22	27	
20	29	38	47	
28	41	54	67