Matlab에서 'for'루프를 작성하는 가장 효율적인 방법은 무엇입니까?


12

예를 들어 for행렬의 인덱스를 실행 하는 이중 루프가있는 경우 외부 루프에 열 실행 인덱스를 배치하는 것이 더 효율적 이라는 것을 읽었습니다 . 예를 들면 다음과 같습니다.

a=zeros(1000);
for j=1:1000
 for i=1:1000
  a(i,j)=1;
 end
end

for루프 가 세 개 이상인 경우 가장 효율적인 코딩 방법은 무엇입니까 ?

예를 들면 다음과 같습니다.

a=zeros(100,100,100);
for j=1:100
 for i=1:100
  for k=1:100
   a(i,j,k)=1;
  end
 end
end

4
ForMATLAB에서는 루프가 매우 느립니다. 가능하면 MATLAB에서 명시적인 루프를 피해야합니다. 대신, 보통 문제는 행렬 / 벡터 연산으로 표현 될 수 있습니다. 이것이 MATLABic 방식입니다. 행렬 등을 초기화하는 내장 함수도 많이 있습니다. 예를 들어, 행렬의 모든 요소를 ​​1 (확장, 곱셈 (스칼라)로 설정하는 ones () 함수가 있습니다. all-ones 행렬을 곱한 값)). 3D 배열에서도 작동합니다 (여기서는 예제를 다루는 것으로 생각됩니다).
Peter Mortensen

3
@PeterMortensen Matlab의 루프 효율은 C와 Python에 비해 어떤 요소 (약)로 작습니까? 왜 그런데? 또한 지난 몇 년 동안 Matlab의 루프 효율성이 향상되지 않았습니까?
TensoR

3
@PeterMortensen“대개 문제는 매트릭스 / 벡터 연산으로 표현 될 수 있습니다”–“보통”의 특정 값에 대해 가능합니다. IMO Matlab 등에서 일하는 사람들은 수십 년 동안 매트릭스 / 벡터 작업으로 할 수없는 모든 것을 무시하는 문화를 가지고 있기 때문에 모든 것이 그 망치의 손톱처럼 보입니다. . 그리고 "Matlab의 for 루프가 느리다"라고 말하지 말고 "Matlab이 느립니다"(C와 Fortran으로 작성된 LA 기본 체의 빠른 라이브러리에만 연결됩니다).
leftaroundabout

5
for 루프의 성능은 논란의 여지가 있습니다 : matlabtips.com/matlab-is-longer-slow-at-for-loops
ohreally

@leftaroundabout True입니다. 해석 된 (또는 반 해석 된) 언어의 속도에 대해 걱정한다는 것은 실제 솔루션이 "이 언어를 사용하지 않는"XY 문제가 있음을 나타내는 명백한 증거입니다. 물론 Simulink에서 코드 생성을 사용하는 경우 코드 생성기가 구축하는 C와 그 효율성에 대한 의문이 있습니다.
Graham

답변:


18

짧은 대답은 가장 안쪽 루프에서 가장 왼쪽의 색인을 원합니다. 귀하의 예에서 루프 인덱스는 k, j, i가되고 배열 인덱스는 i, j, k가됩니다. 이것은 MATLAB이 다른 차원을 메모리에 저장하는 방법과 관련이 있습니다. 자세한 내용은 이 레딧 게시물 의 # 13을 참조하십시오 .



5
@Peter OP의 예제는 실제 유스 케이스가 아닌 무언가를하는 for 루프의 장난감 예제 일뿐입니다.
Matt

@Matt 당신은 맞습니다.
TensoR

11

가장 왼쪽에있는 인덱스가 가장 빠르게 변하는 것이 더 효율적인 이유를 설명하는 다소 긴 답변. 이해해야 할 두 가지 중요한 사항이 있습니다.

먼저, MATLAB (및 C 및 대부분의 다른 프로그래밍 언어가 아닌 포트란)은 배열을 "열 주요 순서"로 메모리에 저장합니다. 예를 들어 A가 2 x 3 x 10 행렬이면 항목은 순서대로 메모리에 저장됩니다.

A (1,1,1)

A (2,1,1)

A (1,2,1)

A (2,2,1)

A (1,3,1)

A (2,3,1)

A (1,1,2)

A (2,1,2)

...

A (2,3,10)

이 컬럼 메이저 순서의 선택은 임의적입니다. 우리는 "행 메이저 순서"규칙을 쉽게 채택 할 수있었습니다. 실제로 C와 다른 프로그래밍 언어에서 수행됩니다.

두 번째로 알아야 할 중요한 점은 최신 프로세서는 한 번에 한 위치에 메모리에 액세스하지 않고 64 또는 128 연속 바이트 (8 또는 16 배정 밀도 부동 소수점 숫자)의 "캐시 라인"을로드하고 저장한다는 것입니다. 메모리에서 한 번에. 이러한 데이터 청크는 빠른 메모리 캐시에 임시 저장되고 필요에 따라 다시 쓰여집니다. (실제로 캐시 아키텍처는 3 ~ 4 레벨의 캐시 메모리로 상당히 복잡하지만 기본 아이디어는 컴퓨터가 어린 시절에 있었던 일종의 1 레벨 캐시로 설명 할 수 있습니다.)

A

가장 안쪽의 루프가 행 첨자를 업데이트하도록 루프가 중첩 된 경우 배열 항목은 순서대로 A (1,1), A (2,1), A (3,1), ... 첫 번째 항목 A (1,1)에 액세스하면 시스템은 A (1,1), A (2,1), ..., A (8,1)을 포함하는 캐시 라인을 주 메모리에서 캐시로 가져옵니다. . 가장 안쪽 루프의 다음 8 번 반복은 추가 주 메모리 전송없이이 데이터에서 작동합니다.

대안으로, 열 인덱스가 가장 안쪽 루프에서 변하도록 루프를 구성하면 A의 항목은 A (1,1), A (1,2), A (1,3 순서로 액세스됩니다. ), ...이 경우 첫 번째 액세스는 A (1,1), A (2,1), ..., A (8,1)을 주 메모리에서 캐시로 가져 오지만 이러한 항목은 사용되지 않습니다. 두 번째 반복에서 A (1,2)에 대한 액세스는 주 메모리에서 다른 8 개의 항목을 가져옵니다. 코드가 행렬의 행 2에서 작동 할 때까지 A (2,1) 항목이 캐시에서 플러시되어 다른 필요한 데이터를 처리 할 수 ​​있습니다. 결과적으로 코드는 필요한 트래픽의 8 배를 생성합니다.

일부 최적화 컴파일러는이 문제를 피하기 위해 루프를 자동으로 재구성 할 수 있습니다.

행렬 곱셈 및 인수 분해를위한 많은 수치 선형 대수 알고리즘은 프로그래밍 언어에 따라 행 주요 또는 열 주요 순서 체계와 효율적으로 작동하도록 최적화 될 수 있습니다. 이를 잘못된 방식으로 수행하면 성능에 상당한 부정적인 영향을 줄 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.