C 전치행렬 만들기 질문입니다

질문

(Eugene Binary) #1
#include <stdio.h>
int main() {
	int matrix[5][5] = {
		{1,2,3,4,5},
		{6,7,8,9,10},
		{11,12,13,14,15},
		{16,17,18,19,20},
		{21,22,23,24,25}
	};
	int copy;
	for (int i = 0; i < sizeof(matrix) / sizeof(matrix[0]); ++i) {
		int k = 0;
		for (int j = k; j < sizeof(matrix[5]) / sizeof(int); ++j) {
			copy = matrix[i][j];
			matrix[i][j] = matrix[j][i];
			matrix[j][i] = copy;
		}
		k++;
	}
	for (int i = 0; i < sizeof(matrix) / sizeof(matrix[0]); ++i) {
		for (int j = 0; j < sizeof(matrix[0]) / sizeof(int); ++j)
			printf("%d ", matrix[i][j]);
		puts("");
	}

	return 0;
}

보시는 것처럼 5x5 정방행렬의 전치행렬을 구하는 프로그램을 짜려고 했는데요,
‘전치행렬은 정방행렬의 대각성분을 기준으로 각 성분을 대칭시킨 거니까 matrix[m][n] 을 matrix[n][m] 으로 바꿔주기만 하면 되겠구나. 어렵지 않겠다.’ 라고 생각해서 코드를 짰습니다. 그리고 실행을 해봤는데… 왜인지 전치행렬이 아니라 원래 정방행렬이 나오더라구요.
한 번 뒤바뀐 성분이 중복되어 바뀌는 것을 막기 위해 k라는 변수를 만들었고, copy를 써서 matrix[i][j]와 matrix[j][i]를 뒤바꿨습니다.
제 예상대로라면 전치행렬이 나와야 할 터인데. 어째서 원래 행렬이 나오는 것인지 답을 찾을 수가 없어 여러분들의 고견을 듣고자 합니다.


(프로책팔이) #2

이걸 for loop 바깥으로 내보내 보세요.
지금 상태에서는 k 를 계속 0 으로 재생성(?) 하고 있기 때문에 님이 원하는 식으로 안 되고 계속 바깥 쪽으로 겉돌겁니다.

int copy;
int k = 0;
for (int i = 0; i < sizeof(matrix) / sizeof(matrix[0]); ++i) {
	for (int j = k; j < sizeof(matrix[5]) / sizeof(int); ++j) {
		copy = matrix[i][j];
		matrix[i][j] = matrix[j][i];
		matrix[j][i] = copy;
	}
	k++;
}

그리고 변수명 그렇게 알수 없는 식으로 적지 마십쇼. 나중에 보기 힘들어 집니다.


(codesafer) #3

가장 간단한 표현은

tt< tn D, tn S >    auto        transpose_xy( D* dst, S* src, int w, int h )
{
    parallel_for( 0, w, [ & ]( int x )
    {
        auto    s = src + x;
        auto    d = dst + x * h;
        fo( y, 0; h )
            d[ y ] = s[ y * w ];
    } );
}

이런식이려나요~
이 코드는 제자리 변환 ( inplace transform ) 아닙니당.
원본 배열과 목표 배열이 달라야하는.


(codesafer) #4

코드는 안봤지만 swap 을 시행한다면 중심을 제외한 직각 이등변 삼각형 만큼만 swap 하셔야겠죠 : )
정사각형을 다 돌면 원래대로 가야 정상.


(Eugene Binary) #5

@withdraw 아항… 감사합니다. 왜 이상하게 돌아가는지 알겠어요. 변수명은 주의하겠습니다.
@codesafer 코세님도 감사합니다. 다만 제 식견이 일천하여 아직은 써 주신 코드를 알아볼 수 없네요… :frowning: 알려주신 간단한 표현은 꼭 나중에 다시 보도록 하겠습니다.


(바보털) #6

해석:

template< typename D, typename S >  //템플릿은 몰라도 됨, D와 S는 자료형 이름임
auto transpose_xy(D* dst, S* src, int w, int h)  //auto는 리턴타입 자동 추론이니까 눈치껏 알아맞춰보고
{
      parallel_for(0, w, [ & ](int x)  //for(int x = 0; int x < w; ++x)랑 비슷한데, 한바퀴씩 찔끔찔끔이 아니라 병렬로 한방에 실행할꺼임
      {
            auto s = src + x;  //얘네도 타입 자동으로 해줌(S*)
            auto d = dst + x * h;  //D*

            for(int y = 0; y < h; ++y)
            {
                  d[ y ] = s[ y * w ];
            }
      });
}

코드독해영역.


근데 이러면 std::array< std::array >같은데 못쓰지 않나요?


(codesafer) #7

배열에서 포인터를 향하게 할지 포인터에서 배열을 향하게 할지 wrapper 함수를 하나 만들어주고
캐스팅을 걸어주면 되는 문제죠.

전치행렬이 또꼬맣고 고정크기를 가질 일이 많다면 template 인자에서 array 의 크기를 받아오면 되는데,
흔히 이미지를 가로 세로 뒤집는 용도로 쓰고, 버퍼의 일부를 따서 쓰다보니
크기를 배열로 정의하는게 불편해서 말이죠.

그리고 물론 전치행렬 구하는걸 SSE 명령으로 확장한 버전이 있지만 엿먹이기 좋은코드라 참았습니다~


(바보털) #8

보여주세용~