> 백엔드 개발 > C++ > C에서 행렬을 효율적으로 전치하는 방법은 무엇입니까?

C에서 행렬을 효율적으로 전치하는 방법은 무엇입니까?

Susan Sarandon
풀어 주다: 2024-12-11 07:13:10
원래의
328명이 탐색했습니다.

How to Efficiently Transpose a Matrix in C  ?

C에서 행렬을 신속하게 전치하는 방법?

문제:

요소가 배열된 행렬 as:

a b c d e f
g h i j k l
m n o p q r 
로그인 후 복사

목표는 이 행렬을 전치하는 것입니다. 결과는 다음과 같습니다.

a g m
b h n
c I o
d j p
e k q
f l r
로그인 후 복사

해결책:

행렬을 효율적으로 전치하려면 , 다음 접근 방식을 고려하세요.

1. 순진한 전치:

void transpose(float *src, float *dst, const int N, const int M) {
    #pragma omp parallel for
    for(int n = 0; n<N*M; n++) {
        int i = n/N;
        int j = n%N;
        dst[n] = src[M*j + i];
    }
}
로그인 후 복사

이 간단한 방법은 각 요소를 반복하여 전치된 위치에 복사합니다. 다만, 예측할 수 없는 메모리 접근 패턴으로 인해 캐시 미스가 발생할 수 있습니다.

2. 행렬 곱셈을 위한 전치:

행렬 곱셈 C = A*B를 수행할 때 B를 전치하는 것이 유리할 수 있습니다. 이 접근 방식은 캐시 누락을 제거하고 계산 속도를 크게 향상시킵니다.

transpose(B);
for(int i=0; i<N; i++) {
    for(int j=0; j<K; j++) {
        float tmp = 0;
        for(int l=0; l<M; l++) {
            tmp += A[M*i+l]*B[K*j+l];
        }
        C[K*i + j] = tmp;
    }
}
transpose(B);
로그인 후 복사

3. 루프 차단을 사용한 블록 전치:

대형 행렬의 경우 루프 차단은 탁월한 성능을 제공합니다. 행렬을 더 작은 블록으로 나누고 독립적으로 전치합니다.

void transpose_block(float *A, float *B, const int n, const int m, const int lda, const int ldb, const int block_size) {
    #pragma omp parallel for
    for(int i=0; i<n; i+=block_size) {
        for(int j=0; j<m; j+=block_size) {
            transpose_scalar_block(&amp;A[i*lda +j], &amp;B[j*ldb + i], lda, ldb, block_size);
        }
    }
}
로그인 후 복사

4. SSE 내장 함수를 사용한 전치:

이 고급 기술은 SSE 내장 함수를 활용하여 비교할 수 없는 속도를 달성합니다. 단일 명령을 사용하여 4x4 블록을 한 번에 효율적으로 전치합니다.

void transpose4x4_SSE(float *A, float *B, const int lda, const int ldb) {
    __m128 row1 = _mm_load_ps(&amp;A[0*lda]);
    __m128 row2 = _mm_load_ps(&amp;A[1*lda]);
    __m128 row3 = _mm_load_ps(&amp;A[2*lda]);
    __m128 row4 = _mm_load_ps(&amp;A[3*lda]);
     _MM_TRANSPOSE4_PS(row1, row2, row3, row4);
     _mm_store_ps(&amp;B[0*ldb], row1);
     _mm_store_ps(&amp;B[1*ldb], row2);
     _mm_store_ps(&amp;B[2*ldb], row3);
     _mm_store_ps(&amp;B[3*ldb], row4);
}
로그인 후 복사

5. SSE를 사용한 루프 차단:

루프 차단과 SSE 내장 기능을 결합하면 성능이 더욱 향상됩니다. 이 접근 방식은 행렬의 4x4 블록을 효율적으로 처리합니다.

void transpose_block_SSE4x4(float *A, float *B, const int n, const int m, const int lda, const int ldb ,const int block_size) {
    #pragma omp parallel for
    for(int i=0; i<n; i+=block_size) {
        for(int j=0; j<m; j+=block_size) {
            int max_i2 = i+block_size < n ? i + block_size : n;
            int max_j2 = j+block_size < m ? j + block_size : m;
            for(int i2=i; i2<max_i2; i2+=4) {
                for(int j2=j; j2<max_j2; j2+=4) {
                    transpose4x4_SSE(&amp;A[i2*lda +j2], &amp;B[j2*ldb + i2], lda, ldb);
                }
            }
        }
    }
}
로그인 후 복사

위 내용은 C에서 행렬을 효율적으로 전치하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿