2012-07-01 2 views
7

행렬 AA = magic(100);이됩니다. 행렬 A의 모든 원소의 합을 계산하는 2 가지 방법을 보았습니다.matlab에서 행렬 요소를 효율적으로 (가장 빠른) 방법으로

sumOfA = sum(sum(A)); 

또는

sumOfA = sum(A(:)); 

는 다른 그들 중 하나가 빠르게 (또는 더 나은 연습)인가? 그렇다면 어느 것입니까? 아니면 둘 다 똑같이 빠릅니까?

+0

모든 메서드는 행렬의 모든 요소를 ​​처리해야합니다. 복잡성과 관련해서는 똑같습니다. 다른 방법, 거대한 행렬로 두 개의 스크립트를 작성하고 실행 시간을 계산하는 것이 좋습니다. 여기에 긴 샷을 찍으면, 메모리 할당 작업을 포함하지 않기 때문에 두 번째 방법이 더 좋다고 말할 수 있습니다. 그러나 제가 말했듯이 그 긴 샷과 나는 여기서 뭔가를 놓칠 수 있습니다. –

+1

Matlab의'tic' 및'toc' 함수를 사용하여 실험을 수행 할 수 있습니다. – Turix

+3

나는 빠른 테스트를했으며 속도면에서 차이가 없었다. 'sum (A (:)) '의 장점은'A '가 얼마나 많은 지 알 필요가 없다는 것입니다. 그것은 모든 희미한 숫자에 대해 작동합니다. – tmpearce

답변

15

당신이 성능이나 부동 소수점 정밀도가 더 중요 여부에 대한 생각을 할 수없는 것 같다.

부동 소수점 정확도가 최고 정확도 인 경우 각 세그먼트를 정렬하여 양수 및 음수 요소를 분리합니다. 그런 다음 절대 값이 증가하는 순서로 합계합니다. 그래, 나도 알아, 그 누구보다 많은 일을하고 아마 시간 낭비 일 것이다.

대신 오류가 발생하지 않도록 적절한 정밀도를 사용하십시오. 테스트 등에 관한 좋은 수치 사례를 사용하여 문제가 발생하지 않도록하십시오.

는까지 시간이가는 등의 N × M 개의 어레이에 대해,

합계 (A는 (:)) N * M-1 가산을 필요로한다.

합계 (A)는 (N-1) * M + M-1 = N * M-1 가산을 요구할 것이다.

두 가지 방법 모두 동일한 수의 추가가 필요하므로 큰 배열의 경우 인터프리터가 똑같이 똑같은 지 인식 할만큼 똑똑하지 않더라도 누가 신경 쓰니?

이것은 문제가되지 않습니다. 이것에 대해 걱정할 두더지 언덕에서 산을 만들지 마십시오.

편집 : 한 방법의 오류에 대한 Amro의 의견에 대한 응답으로 제어 할 수있는 항목이 거의 없습니다. 추가는 다른 순서로 수행되지만 어떤 순서가 더 좋을지에 대한 보증은 없습니다.

A = randn(1000); 
format long g 

두 가지 해결책은 아주 비슷합니다. 사실 eps와 비교할 때 차이는 거의 없습니다.

sum(A(:)) 
ans = 
      945.760668102446 

sum(sum(A)) 
ans = 
      945.760668102449 

sum(sum(A)) - sum(A(:)) 
ans = 
     2.72848410531878e-12 

eps(sum(A(:))) 
ans = 
     1.13686837721616e-13 

앞서 언급 한 분리 및 정렬 트릭을 선택한다고 가정합니다. 음수 부분과 양수 부분이 충분히 커야 정밀도가 떨어질 수 있습니다.

sum(sort(A(A<0),'descend')) 
ans = 
      -398276.24754782 

sum(sort(A(A<0),'descend')) + sum(sort(A(A>=0),'ascend')) 
ans = 
      945.7606681037 

그럼 어쨌든 더 정밀도가 높은 배열에 조각을 축적해야합니다. 시도해 볼 수도 있습니다 :

[~,tags] = sort(abs(A(:))); 
sum(A(tags)) 
ans = 
      945.760668102446 

이러한 테스트에서도 흥미로운 문제가 발생합니다. 테스트가 랜덤 (정상) 배열로 수행되기 때문에 문제가 발생합니까? 본질적으로, 우리는 합계 (A (:))를 술꾼의 산책 인 무작위 걸음으로 볼 수 있습니다. 그러나 sum (sum (A))을 고려하십시오. 합계 (A)의 각 요소 (즉, 내부 합)는 그 자체로 1000 개의 정규 편차의 합이다. 그들 중 일부를보십시오 :

sum(A) 
ans = 
    Columns 1 through 6 
     -32.6319600960983   36.8984589766173   38.2749084367497   27.3297721091922   30.5600109446534   -59.039228262402 
    Columns 7 through 12 
      3.82231962760523   4.11017616179294   -68.1497901792032   35.4196443983385   7.05786623564426   -27.1215387236418 
    Columns 13 through 18 

우리가 그들을 추가하면 정밀도가 손실됩니다. 따라서 잠재적으로 합계 (A (:))와 같은 연산이 약간 더 정확할 수 있습니다. 그렇지? 누적에 더 높은 정밀도를 사용하면 어떨까요? 먼저 double을 사용하여 열을 뺀 다음 십진수 25 자리로 변환하고 행을 합계합니다. 대신, 결과를 합산, 정밀도의 25 자리로 즉시 변환

sum(hpf(sum(A))) 
ans = 
945.76066810244807408 

을 (나는. 가드 자리로 숨겨진 5 개 자리를 떠나, 여기에 20 자리 숫자를 표시했습니다) 또는.

두 배의 정밀도 형식은 여기서 반대 방향으로 똑같이 잘못되었습니다. 결론적으로, 내가 제시 한 대안은 단순한 유사 합계 (A (:)) 또는 합계 (A())와 비교할 때 훨씬 더 많은 시간이 소요되기 때문에 이는 모두 논란의 여지가 있습니다. 그 중 하나를 골라서 걱정하지 마십시오.

+0

감사합니다. 훌륭한 답변입니다. 이것이 내가이 질문을 한 이유입니다. 두 가지 코드가 모두 같다고 생각합니다 (항상 동일한 결과를 산출합니다). 그러나 다른 하나보다 두 배 길다. 그것들과 매트릭스 사이의 차이는 거의 없습니다. 그것은 내 생각에 그것이 성능 차이를 만드는 부분이 될 수 있습니다. 나는 다른 곳을 봐야 해. 성능은 대용량 데이터의 최적화 문제이기 때문에 여기에서 매우 중요합니다 ... 그리고 차라리 2 일 동안 결과를 얻으려면 1 일을 기다려야합니다. – drasto

+2

@drasto 코드를 프로파일 링 해 보셨습니까? 당신은 당신이 "그들 사이에 거의 차이가 없다"고 말하면서, 이것은 오직 하나뿐입니다. 다른 사람들을 봤어? "대용량 데이터의 최적화 문제"에서 "병목 현상"이 매트릭스 요소의 합계 인 경우 매우 놀랍습니다. – abcd

+0

인터프리터가 내부 행렬의 결과를 보유하기 위해 임시 행렬을 할당하기로 결정하면 'sum (sum (A))'에 대한 한 가지 우려가 있습니다. 루프 중간에이 작업을 수행하고 있고 매우 많은 수의 열이있는 경우 임시 매트릭스를 할당하고 해제하면 실제 성능이 저하 될 수 있습니다. Matlab JIT가이를 최적화 할 수는 있지만 가능하지 않은 비슷한 상황을 봤습니다. – sfstewman

3

성능면에서는 두 가지 모두 매우 유사하다고 말하고 싶습니다 (최근 MATLAB 버전 가정). 여기에 TIMEIT 기능을 사용하여 빠른 테스트는 다음과 같습니다

function sumTest() 
    M = randn(5000); 
    timeit(@() func1(M)) 
    timeit(@() func2(M)) 
end 
function v = func1(A) 
    v = sum(A(:)); 
end 
function v = func2(A) 
    v = sum(sum(A)); 
end 

결과가 있었다 :

>> sumTest 
ans = 
    0.0020917 
ans = 
    0.0017159 

내가되는 부동 소수점 문제에 대해 걱정한다. 예 : 큰 행렬에 대한

>> M = randn(1000); 
>> abs(sum(M(:)) - sum(sum(M))) 
ans = 
    3.9108e-11 

오류 크기 증가

+0

따라서 부동 소수점 문제에 관해서는 어떤 방법이 더 바람직한가요? – drasto

+1

어느 것이 더 나은 답을 줄지 알 수있는 방법이 없습니다. 두 개의 결과는 하위 비트에서 완전히 무작위입니다. 그것은 모두 어떤 순서로 숫자가 추가되었는지에 달려 있으며, 이는 matlab이나 걱정할 것이 없습니다. –

관련 문제