컴퓨터 개론 및 실습 강의 9
행렬의 column-major 및 1차원 처리 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ C 언어에서 행렬 int A[2][4] = { 1,2,3,4,5,6,7,8 }은 row-major 로 세팅되어 있으므로 i행 j열 원소는 A[i][j]로 처리된다. A = [ 1 2 3 4 ] [ 5 6 7 8 ] A[0] = [ 1 2 3 4 ] A[1] = [ 5 6 7 8 ]
행렬의 column-major 및 1차원 처리 ■ 1차원 배열과 행렬 아래에 주어진 1차원 배열 A, B 를 4 x 2 행렬에 column-major 로 초기화시키는 방법으로 대응시키고 싶다. 그러나, C 언어에서 행렬은 row-major 로 처리되므로 사용자가 이러한 직접 처리를 고안해야 한다. 따라서 m x n 행렬에 대한 일반적인 포인터를 고안해보자. 2차원 배열 포인터를 이용하면 i 행 j 열 원소를 사용자가 고안한 함수를 이용하여 *prow [ i ] [ j ] (행-우선) 및 *pcol [ j ] [ i ] (열-우선) 두 가지 방법 모두 가능하게 처리할 수 있다. double A[] = { 1,2,3,4, 5,6,7,8 }; double B[] = {2,3,4,5, 6,7,8,1 }; A = [ 1 5 ] [ 2 6 ] [ 3 7 ] [ 4 8 ] B = [ 2 6 ] [ 5 1 ]
행렬의 column-major 및 1차원 처리 (cont.) void mulAtrB(double*C, int m1,int n1, double*A, int m2,int n2, double*B) { // m1 x n1 matrix A // m2 x n2 matrix B // C = A' * B, n1 x n2 matrix int i,j,k; double *a,*b; if( m1 != m2 ) { printf(“mulAtrB : inner dimension mismatch\n"); exit(1); } b = B; for(j = 0; j < n2; j++) { a = A; for(i = 0; i < n1; i++) { *C = 0; for(k = 0; k < m1; k++) *C += a[k] * b[k] ; a += m1; ++C; } b += m1; double A[] = { 1,2,3,4, 5,6,7,8 }; double B[] = { 2,3,4,5, 6,7,8,1 }; double C[100]; mulAtrB(C, 4,2,A, 4,2,B); b a [ 1 2 3 4 ] [ 5 6 7 8 ] [ 2 6 ] [ 3 7 ] [ 4 8 ] [ 5 1 ] [ 40 48 ] [ 96 136 ]
행렬의 column-major 및 1차원 처리 (cont.) double ***rowmtrx(int m,int n) { int i,j,k; double ***A, *pnull = NULL; // pointers to rows A = (double ***) malloc((size_t) (m*sizeof(double **))); if(A == NULL) { printf("allocation failure in matrix"); exit(1); } A[0] = (double **) malloc((size_t)(m*n*sizeof(double*))); for(i = 1; i < m; i++) A[i] = A[i-1]+n; for(i = 0; i < m; i++) for(j = 0; j < n; j++) A[i][j] = pnull+i + m*j; // i,j return A; // pointer to array of pointers to rows } 위에서 A[0] = (double **) malloc( (size_t) (m * n * sizeof(double*)) ); 인 명령에서 double 형 데이터에 대한 m*n 개의 포인터를 정의하였다. 따라서, m*n 개의 원소에 대한 1차원 처리 가능하다. 한편, A[0] 다음의 포인터 A[1]은 n 개의 double 형 데이터를 가리킨다. double M[] = { 1,2,3,4, 5,6,7,8 }; prow[0] prow[1] prow[2] prow[3] [ 1 5 ] [ 2 6 ] [ 3 7 ] [ 4 8 ] row-major m = 4 n = 2
행렬의 column-major 및 1차원 처리 (cont.) double ***colmtrx(int m,int n) { int i,j,k; double ***A, *pnull = NULL; // pointers to rows A = (double ***) malloc((size_t) (m*sizeof(double **))); if(A == NULL) { printf("allocation failure in matrix"); exit(1); } A[0] = (double **) malloc((size_t)(m*n*sizeof(double*))); for(j = 1; j < n; j++) A[j] = A[j-1]+m; for(i = 0; i < m; i++) for(j = 0; j < n; j++) A[j][i] = pnull+i + m*j; // j,i return A; // pointer to array of pointers to rows } double M[] = { 1,2,3,4, 5,6,7,8 }; pcol[0] pcol[1] column-major m = 2 n = 4 prow[0] prow[1] prow[2] prow[3] [ 1 5 ] [ 2 6 ] [ 3 7 ] [ 4 8 ] [ 1 5 ] [ 2 6 ] [ 3 7 ] [ 4 8 ] row-major m = 4 n = 2 6
행렬의 column-major 및 1차원 처리 (cont.) int i,j, m,n; double A[] = { 1,2,3,4, 5,6,7,8 }; double ***pcol,***prow; m = 4; n = 2; prow = rowmtrx(m,n); // row-major pcol = colmtrx(m,n); // column-major for(i=0;i<m;i++) for(j=0;j<n;j++) printf(" %g", *( (A-NULL)+prow[i][j]) ); printf("\n"); // A[i][j] for(j=0;j<n;j++) for(i=0;i<m;i++) printf(" %g", *( (A-NULL)+pcol[j][i]) ); printf("\n"); // A[j][i] 위와 같이 행우선, 열우선 포인터를 각각 정의할 수 있다. 결과는 double A[100] = { 1,2,3,4, 5,6,7,8 }; A = [ 1 5 ] [ 2 6 ] [ 3 7 ] [ 4 8 ] 1 5 2 6 3 7 4 8 1 2 3 4 5 6 7 8 pcol[0] pcol[1] column-major m = 2 n = 4 prow[0] prow[1] prow[2] prow[3] [ 1 5 ] [ 2 6 ] [ 3 7 ] [ 4 8 ] [ 1 5 ] [ 2 6 ] [ 3 7 ] [ 4 8 ] row-major m = 4 n = 2
행렬의 column-major 및 1차원 처리 (cont.) void mulAB(double *C, double *A, double *B, double ***prow, double ***pcol, int n) { // C = A * B, n x n matrix int i,j,k; double **a,**b; b = pcol[0]; for(j = 0; j < n; j++) { a = prow[0]; for(i = 0; i < n; i++) { *C = 0; for(k = 0; k < n; k++) *C += *(a[k]+(A-NULL)) * *(b[k]+(B-NULL)); ++C; a += n; } b += n; a[k] + A 는 에러인 이유는 두 개의 포인터를 더할 수 없기 때문이다. 포인터 NULL 의 주소값은 0 이므로 (A-NULL)은 두 개의 포인터의 차이로 정수값이 되므로 포인터에 더할 수 있게 된다. double X[] = { 1,2,3,4 }; double Y[] = { 5,6,7,8 }; double C[100]; [ 1 3 ] [ 2 4 ] [ 5 7 ] [ 6 8 ] [ 23 31 ] [ 34 46 ] =