2012-11-09 3 views

답변

4

찾으시는 단어는 입니다.입니다. Google에서 쓰레싱 행렬 곱셈을 찾으십시오.

C에 대한 표준 승산 알고리즘 = A * B는 큰 단계 fastly 메모리 탐색 기본적

void multiply(double[,] a, double[,] b, double[,] c) 
{ 
    for (int i = 0; i < n; i++) 
     for (int j = 0; j < n; j++) 
      for (int k = 0; k < n; k++) 
       C[i, j] += a[i, k] * b[k, j]; 
} 

같을 것이다 것은 성능에 불리하다. k에 대한 액세스 패턴은 [k, j]입니다. 그래서 그 대신 메모리에 주위 점프, 우리는 가장 내부 루프는 행렬의 제 2 액세스 인덱스에서 작동하도록 작업을 재 배열 할 수 있습니다

void multiply(double[,] a, double[,] B, double[,] c) 
{ 
    for (i = 0; i < n; i++) 
    { 
     double t = a[i, 0]; 
     for (int j = 0; j < n; j++) 
     c[i, j] = t * b[0, j]; 

     for (int k = 1; k < n; k++) 
     { 
     double s = 0; 
     for (int j = 0; j < n; j++) 
      s += a[i, k] * b[k, j]; 
     c[i, j] = s; 
     } 
    } 
} 

이 해당 페이지에 주어진 예였다. 그러나 다른 옵션은 B [k, *]의 내용을 미리 배열에 복사하고이 배열을 내부 루프 계산에 사용하는 것입니다. 이 방법은 대개 데이터를 복사하는 경우에도 대체 방법보다 훨씬 더 빠르게 입니다.보다 빠릅니다. 이것이 직관에 반하는 것처럼 보일지라도 스스로 자유롭게 시도하십시오.

void multiply(double[,] a, double[,] b, double[,] c) 
{ 
    double[] Bcolj = new double[n]; 
    for (int j = 0; j < n; j++) 
    { 
     for (int k = 0; k < n; k++) 
      Bcolj[k] = b[k, j]; 

     for (int i = 0; i < n; i++) 
     { 
      double s = 0; 
      for (int k = 0; k < n; k++) 
       s += a[i,k] * Bcolj[k]; 
      c[j, i] = s; 
     } 
    } 
} 
+0

두 번째 코드 블록에서'c [i, j] = s;'이지만 'j'가 해당 범위에서 선언되지 않은 것으로 보입니다. –

+0

이것이 왜 받아 들여지는 대답인가, k의 안쪽 루프가 성능 열적 관점에서 완전히 잘못된 열에 액세스하고 있는지 궁금합니다. – greywolf82

+0

코드는 행렬이 행 주요 인 C와 유사한 언어를 사용합니다. '''a [i, j]'''를 사용하여 행 우선 순위에 저장된 행렬에 접근 할 때, 항상'''''가 항상''''''보다 빨리 변경되도록해야합니다 성능을 최대화합니다. – Cesar

1

@ Cesar의 대답이 정확하지 않습니다. 예를 들어, 내부 루프

for (int k = 0; k < n; k++) 
    s += a[i,k] * Bcolj[k]; 

은 a의 i 열을 통과합니다.

다음 코드는 항상 데이터를 행 단위로 방문해야합니다.

void multiply(const double (&a)[I][K], 
       const double (&b)[K][J], 
       const double (&c)[I][J]) 
{ 
    for (int j=0; j<J; ++j) { 
     // iterates the j-th row of c 
     for (int i=0; i<I; ++i) { 
     c[i][j] = 0; 
     } 

     // iterates the j-th row of b 
     for (int k=0; k<K; ++k) { 
      double t = b[k][j]; 
      // iterates the j-th row of c 
      // iterates the k-th row of a 
      for (int i=0; i<I; ++i) { 
      c[i][j] += a[i][k] * t; 
      } 
     } 
    } 
} 
+0

코드가 잘못되었습니다. c [i] [j]의 재설정은 전적으로 선택 사항 일 수 있습니다 (호출자가 행렬을 0으로 재설정하면 달라집니다). 또한 k의 루프는 1부터 시작하지만 0부터 시작해야합니다. – greywolf82

+0

@ greywolf82 c [i] [j] + = a [i] [k] * t; 초기 값이 필요합니다. "0부터 시작하는 k"는 정확합니다. 결정된. –

+0

예, 알아요.하지만 호출자가 memset을 0으로 만든 경우 루프가 필요하지 않습니다. 명확하게하기 위해 코드에 주석을 추가하십시오. – greywolf82