2013-04-06 1 views
4

손으로 쓴 for 루프, 컴퓨팅 성능면에서 거의 동일하다.표현식 템플릿 : 표현식 평가의 성능이 향상 되었습니까? 식 템플릿 기법</p> <pre><code>D = A*B+sin(C)+3.; </code></pre> <p>같은 매트릭스 식으로

지금, 나는 다음과 같은 두 식 표현 템플릿에 의한 "고전"구현에서

D = A*B+sin(C)+3.; 
F = D*E; 
cout << F << "\n"; 

을 가지고 가정, 컴퓨팅 성능은 거의 순서대로 두 for 루프의 경우와 동일합니다. 이는 표현식이 = 연산자를 만나면 즉시 평가되기 때문입니다.

내 질문은 : 어떤 기술 (?, 예를 들어 자리 표시자를 사용)가 D의 값이 실제로 사용되지 않는 것을 인식하고 관심의 값은 F의 유일한 요소임을 있도록 표현식 만

F = E*(A*B+sin(C)+3.); 

이 평가되며 전체 성능은 단일 for 루프의 것과 동일합니까?

물론, 이러한 가상 기술은 나중에 코드에서 D의 값이 필요한 경우 식을

D = A*B+sin(C)+3.; 

을 평가하기 위해 다시 반환 할 수 있어야한다.

도움을 주셔서 감사합니다.

편집 : 솔루션을 실험 결과 예브게니에 의해 제안

원래 명령 :

Result D=A*B-sin(C)+3.; 

계산 시간 : 32 ms보다 짧은

두 단계 명령어 :

Result Intermediate=A*B; 
Result D=Intermediate-sin(C)+3.; 

계산 시간 : 43ms auto

솔루션 :

auto&& Intermediate=A*B; 
Result D=Intermediate-sin(C)+3.; 

계산 시간 : 32 ms보다 짧은 시간.

결과적으로 auto&&은 단일 명령의 원래 계산 시간을 복원 할 수있었습니다.

편집 :

Copy Elision

What does auto tell us

Universal References in C++11

C++ Rvalue References Explained

예브게니에 의해 제안 다음, 관련 링크를 요약 (210)

+0

산술 표현식이 'for' 루프와 같은 이유는 무엇입니까? –

+0

@JoachimPileborg, [표현 템플릿] (http://eigen.tuxfamily.org/dox-devel/TopicInsideEigenExample.html)이 ** 전체 ** 표현을 수집하고, 구조를 최적화하고 (optionaly), 그렇게 실행할 수 있기 때문에 ** for ** 루프가되어야합니다. http://en.wikipedia.org/wiki/Expression_templates –

답변

4

평가는 일반적으로 발생 그 결과로 전환. 그런 전환 과정에서 평가가 이루어집니다.


내 질문은 : 어떤 기술 (? 자리 표시자를 사용하여, 예를 들어) D의 값이

이러한 종류의 "transfromation"실제로 사용되지 않는 것을 인식 할 수있다 :

Result F = (A*B+sin(C)+3.)*E; 
Result D = A*B+sin(C)+3.; 
Result F = D*E; 

D를 평가하지 않을 때 가능합니다.이렇게하려면 일반적으로 D가 실제 인 것처럼 표현 유형을 캡처해야합니다. 예를 들어, auto의 도움으로 그러나

auto &&D = A*B+sin(C)+3.; 
Result F = D*E; 

, 당신은 자르해야한다 - 때때로 표현 템플릿은 피연산자의에 대한 참조를 캡처하고 당신이 그것을 표현이다 후에 만료 것이다 일부 를 rvalue이있는 경우 :

auto &&D = A*get_large_rvalue(); 
// At this point, result of **get_large_rvalue** is destructed 
// And D has expiried reference 
Result F = D*E; 

get_large_rvalue은 여기서

LargeMatrix get_large_rvalue(); 

그것은 결과이다는 get_large_rvalue가 호출되었을 때 전체 식의 말에 만기, 를 rvalue입니다. 표현식 내의 어떤 부분에 포인터/참조를 저장하면 (나중에 평가하기 위해) 평가를 "연기"합니다. 포인터/참조는 가리키고 참조 된 객체보다 오래 지속됩니다. 내가 이해, 자동 유형을 결정하도록 컴파일러에 요청,

auto &&intermediate = get_large_rvalue(); // it would live till the end of scope 
auto &&D = A*intermediate ; 
Result F = D*E; 

나는 C++ (11)에 익숙하지 합니다만 :

이를 방지하려면 어떻게해야 그것의 초기화에서 변수의

그래, 정확히. 이를 Type Inference/Deduction이라고합니다.

C++ 98/03에는 템플릿 함수에만 유형 공제가 있었으며, C++ 11에는 자동이 있습니다.

CUDA와 C++ 11은 어떻게 상호 작용하는지 알고 있습니까?

(나는 OpenCL을를 사용하지만) 나는 CUDA을 사용하지 않은,하지만 난 C++ 11 호스트 코드에는 문제가 없을 것 같아요. 어쩌면 일부 C++ 11 개 기능 장치 코드 내에서 지원되지 않습니다,하지만 당신의 목적을 위해 - 당신은 단지 마지막

호스트 코드 자동 필요 만 C++와 가능성이있다?

pre-C++ 11을 의미합니까? 나는. C++ 98/C++ 03? 네, 가능하지만, 더 구문 노이즈가, 아마도 그 이유는 그것을 거부하는 것입니다 : 지금 Windows에서 CUDA/비주얼 스튜디오 2010을 사용하고 있습니다

// somehwhere 
{ 
    use_D(A*B+sin(C)+3.); 
} 
// ... 
template<typename Expression> 
void use_D(Expression D) // depending on your expression template library 
         // it may be better to use (const Expression &e) 
{ 
    Result F = D*E; 
} 

.당신이 두 OS '(당신이 어떤을 알고에, GPGPU와 CUDA) 내 관심의 틀에서 C++ 11을 사용하는 2010

MSVC에 대한 컴파일러/도구 모음/환경 추천 시겠어요 않는 C의 일부를 지원 ++ 11. 특히 자동을 지원합니다. 따라서 (C++ 11) 만 필요한 경우 - MSVC2010은 정상입니다.

그러나 MSVC2012를 사용할 수 있다면 좋습니다. C++ 11 지원이 훨씬 뛰어납니다. 또한

트릭 자동 & & 중간 = get_large_rvalue을(); 그러한 문제를 알지 못하는 제 3 자 사용자에게 "투명"하지 않은 것 같습니다. 내가 맞습니까? 어떤 대안?

표현식 템플리트가 일부 값에 대한 참조를 저장하고 평가를 지연하는 경우. 당신은 평가의 장소에서 참조가 모두 살아 있는지 확인해야합니다. 원하는 방법을 사용하십시오. 자동이 없으면 다음과 같이 자동으로 수행 할 수 있습니다.

LargeMatrix temp = get_large_rvalue(); 

또는 전역/정적 변수 (덜 선호되는 방법)조차도 가능합니다.

최후의 의견/질문 : 자동을 사용하기 & & D = A * B + 죄 (C) +3; 두 개의 표현식 사이의 할당에 대해 연산자를 오버로드해야합니다. 맞습니까?

아니요, 이러한 양식은 할당 연산자를 복사하거나 이동하거나 생성자를 복사/이동하지 않아도됩니다.

기본적으로 임시 값의 이름을 지정하고 유효 기간이 끝날 때까지 수명이 연장됩니다. Check this SO.

하지만, 다른 형태로 사용한다면 : 어쩌면 컴파일하기 위해 필요한 이러한 경우의 복사/이동/변환 생성자에서

auto D = A*B+sin(C)+3.; 

을 (실제 사본이 Copy Ellision를 사용하여 컴파일러에 의해 멀리 최적화 할 수 있지만)

또한 계산을 강제 (중간 표현식) 자동차를 사용하여 결과를 전환함으로써, 타사 사용자에게 투명하지 않은 것으로 보인다. 어떤 대안?

대체 방법이 있는지 확실하지 않습니다. 이것은 표현 템플릿의 본성에 의한 것입니다. 표현식에서 사용하는 동안 - 내부 중간 유형을 반환하지만 일부 "특수"유형으로 저장하면 평가가 트리거됩니다.

+0

답변 해 주셔서 대단히 감사합니다. 저는 이미 C++로 작성된 표현 템플릿과 GPGPU를위한 CUDA를 사용하여 매트릭스 라이브러리를 사용합니다. 저는 C++ 11에 익숙하지 않지만,'auto'는 컴파일러에게 초기화로부터 변수의 타입을 결정하도록 요구합니다 : 표현 템플릿에 매우 유용합니다. CUDA와 C++ 11이 어떻게 상호 작용하는지 알고 있습니까? 또한 마지막 포인트 ('rvalue' 만료)를 더 확장 할 수 있습니까? 나중에 필요하다면 나는 "게시"할 수 없다는 것을 의미합니까 - D를 평가합니까? 마지막으로 C++ (C++ 11을 피함)만으로도 어떤 가능성이 있습니까? 아주 좋은 지적이야! 고맙습니다! – JackOLantern

+0

답변이 업데이트되었습니다. 그건 그렇고, 어떤 컴파일러/툴셋/환경을 사용합니까? –

+0

다시 한 번 감사드립니다. +1하고 대답을 수락했습니다. 예전에는'Linux '에서'nvcc/gcc'를 사용했지만 몇 가지 이유 때문에'Windows'에서'CUDA/Visual Studio 2010 '을 사용하고 있습니다. 두 운영체 모두에게 'C++ 11'을 내 관심사 (GPGPU와 CUDA, 당신이 알고있는 것)의 틀에서 사용할 수있는 컴파일러/툴셋/환경을 추천 해 주시겠습니까? 또한 트릭'auto && intermediate = get_large_rvalue();'는 제 3 자 사용자에게 "투명하지"않은 것 같습니다 (이 문제는 알지 못합니다). 내가 맞습니까? 어떤 대안? – JackOLantern

1

C++ 11에서 당신이 표현 템플릿을 사용하는 가정 auto

auto D = A*B+sin(C)+3.; 

을 사용할 수 있습니다, D의 유형은 <some template type which represents an expression> 될 것이다. 이제 약간의 메모리를 절약하기 때문에 (행렬에 대한 공간을 할당 할 필요가 없기 때문에) 신중하게 사용해야하지만 사용 방법에 따라 이것이 최상일 수는 없습니다. 위해 D * E (실제로 n 회, n은 크기가 계산 될 때

생각 약

F = D * E의 요소 D가 [I] [J] 있어야

여러번 "방문"). D가 일반 매트릭스 타입이라면 이것은 문제가되지 않습니다. D가 표현식이라면, 여러 번 평가할 수 있습니다. 하고있는 contray에

,

F = D + E 

괜찮습니다.

생각해 보면 : 두 개의 중첩 루프를 사용하여 F = E*(A*B+sin(C)+3.);을 작성할 수 없습니다. 표현의

Result D = A*B+sin(C)+3.; 

결과 유형 :

A*B+sin(C)+3. 

하지 결과이지만, 뭔가 당신이 어떤 특별한 유형 등으로 결과를 저장할 때 expression template

+1

Expression Template 라이브러리는 결과의 일부를 임시로 평가하는 것이 더 나은지 아닌지를 자동으로 인식 할 수 있습니다. 예를 들어, [Eigen does this] (http://eigen.tuxfamily.org/dox/TopicLazyEvaluation.html) : ** "Eigen은 각 하위 식에 대해 임시 변수로 평가할지 여부를 자동으로 결정합니다. 실제로 경우에 따라 하위 식을 즉시 임시 변수로 평가하는 것이 좋지만 다른 경우에는 그것을 피하는 것이 낫습니다. "** –

+0

@sbabbi 답변 해 주셔서 대단히 감사합니다. 제발, 내 의견을 참조하십시오 Evgeny Panasyuk. 사실, 왜'F = D * E'가'F = D + E'와 다른지 이해하지 못합니다. 둘 다 elementwise 작업을 포함합니다. 설명해 주시겠습니까? 감사. – JackOLantern

관련 문제