2013-05-22 7 views
4

은 이것이다 :삼항 연산자 컴파일러 최적화

int val; 
// ... 
val = (val != 0) ? otherVal : 0; 

이보다 효율적인

int val; 
//... 
if (val != 0) 
    val = otherVal; 

?

컴파일러는 3 진 연산자를 최적화 할 수 있습니까? 의도는 분명합니다. 실제로 메모리에 0을 쓰고 싶을 수있는 방법이 있습니까? 어쩌면 메모리가 파일에 매핑되었을 때?

우리는 상관 없다고 생각할 수 있습니까?

편집 : 요점은 하나의 조건이 충족되면 변수를 일부 값으로 설정하는 것입니다. 다른 분기가 필요하지 않습니다. 그래서 왜 삼진 (사본을 만들 의무가있는 지사가있는)이 덜 효과적이거나 최적화 될 것인지 물어 본다.

+3

Duplicit 질문 : http://stackoverflow.com/questions/3565368/ternary-operator-vs-if-else –

+1

내가 컴파일러 프로그래머, 그래서 돈 아니에요 ' 정말로 알지만, 삼항 연산자의 양쪽을 평가할 수 있으므로 분기를 건너 뛸 수 있습니다 (속도가 빨라집니다). – Hassedev

+1

무엇보다도 val은 이미 0 일 때 0으로 설정되며 첫 번째 경우에는 필요하지 않습니다. 컴파일러가 다른 것을 할 수는 없습니다. 가장 읽을 수있는 변형을 작성하십시오. –

답변

3

Mats Petersson 제안은 일반적으로 가장 "가장 읽을 수있는 변형 쓰기"입니다. 최적의 속도 성능 코드를 작성하려는 경우 컴퓨터 및 프로세서에 대한 자세한 정보가 필요합니다. 일부 시스템에서는 첫 번째가 더 빠르게 실행됩니다 (높은 파이프 라인 프로세서 : 분기가없고 최적화 된 삼항 연산자).다른 기계는 두 번째 형식 (더 간단)으로 더 빨리 실행됩니다.

+0

'if' 문은 0을 초기화하지 않기 때문에 평범한 최적화 컴파일러조차도 적어도 빠르다는 보장이 있습니다. 똑같은 일을했다면 성능 차이가 없을 것입니다. – strcat

+0

@strcat "적어도 빠르다는 보장"은 확실히 C 스펙에 없습니다. 오늘날의 하드웨어 아키텍처 및 소프트웨어 기술은 미래에 쉽게 진보하고 다른 패러다임을 제공 할 수 있습니다. 스칼라 프로세서와 단순히 임베디드 프로세서는 광범위한 가능성을 제공합니다. – chux

+0

현대 컴파일러는 두 프리미티브를 같은 것으로보고 있으며 두 프리미티브를 구별하는 유스 케이스는 없습니다. 답은 하드웨어 문제로 제시되지만 생성 된 코드는 항상 실제로 동일합니다. 이것은 아키텍처가 진화함에 따라 변하지 않을 것입니다. 컴파일러는 * 코드 스타일 *에 관계없이 분기를 수행하는 방법을 결정하기 위해 동일한 추론을 수행합니다.이 모든 것이 있습니다. 물론 컴파일러는 들여 쓰기에 공백이나 탭을 사용하는지 여부에 따라 최적화를 결정할 수 있지만 실용적인 대답으로는 유용하지 않습니다. – strcat

3

컴파일러가 최적화합니다. 결국 성능에는 차이가 거의 없습니다.

그러나 가독성에는 큰 차이가 있습니다. 때로는 삼항 연산자가 선명도를 크게 높이 지 않는 여러 줄의 코드를 제거하는 데 도움을 줄 수 있습니다.

다른 경우에는 if 성명이 명확하고 쉽게 이해할 수 있습니다.

코드를 3 진으로 축소했지만 명확성을 유지하기 위해 많은 주석을 추가해야하는 것은 비생산적입니다.

코딩의 모든 신들은 삼원 진술을 중첩하지 마십시오.

+0

C++에서는 복사 작업이 일어나는 것을 상상할 수 있습니다. 예 : "Object a = Object (기본값); a = (조건)? Object (var) : Object (기본값)" 컴파일러가 과제를 제거 할 정도로 충분히 똑똑하고 공격적일까요? 물건이 생성자에서 발생할 수 있으므로 위험합니다. 평범한 오래된 데이터의 경우 다를 수 있습니까? – Aki

+0

"선택의 여지가 없다면 ("constexpr'이 마음에 온다.) "삼항 문장을 중첩하지 말라." – rubenvb

+0

"copy elision"이라는 최적화 기능이있어 컴파일러가 불필요한 복사를 막을 수 있습니다. Object (...)는 이름없는 temp이고 변수에 할당되어 있기 때문에 빌드 될 것입니다. http://en.cppreference.com/w/cpp/language/copy_elision http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ – user666412

1

이 대부분 효율이 동일한 컴파일러는이 경우/else 문을 최적화처럼 삼항 연산자를 최적화 될 것입니다 대부분의 컴파일러를 들어 Ternary operator ?: vs if...else

의 중복입니다. 말하자면, 나는 그들이 문장을 훨씬 더 쉽게 읽을 수있게 만들었을 때 문장을 선호한다.

다른 질문에 답변하십시오. 나는 당신이 무엇을 의미하는지 모르겠다. 만약 하나의 정수 나 변수를 0으로 설정했다면, 위에서와 같이 0으로 설정하는 것 이외의 다른 방법은 없다.

변수 배열이있는 경우 memset(ptr, 0, size*sizeof(TYPE))을 사용할 수 있습니다. 변수 배열을 0으로 설정하면 가장 빠를 수 있습니다. 아니면 std :: fill_n

나는 당신이 위의 논리로 달성하려고하는 것이 확실하지 않지만 약간 이상하게 보입니다. 거기에 조건부를 전혀 필요로하지 않는다는 것을 의미하는 코드를 배열하는 방법이 있지만 좀 더 많은 코드를 보지 않고는 자신의 상황에 대해 말하기는 어렵습니다.

이 작업을 수십억 번하지 않는 한 정직하게 말하자면 이것은 매우 성숙한 최적화 일 것입니다. 가독성에 중점을 두어야합니다.

+0

그냥 이해하려고합니다. 가독성이 성능에 영향을 미치는 곳. 3 진을 사용하면 약간의 경우 가독성이 향상되지만 성능 비용이 발생할 수도 있습니다. 즉, if-assign이 논리적으로 더 빠르다는 것을 의미하지만 가독성을 높이기 위해 삼항 항을 사용하려면 단순한 논리에 반하는 것입니다. 그렇게하면 컴파일러가 최적화 할 수 있습니까? 3 자 외 다른 지점이 PoD에 쓸모 없다는 것은 꽤 명백합니다. 그러나 파일이 메모리에 매핑되거나 드라이버를 프로그래밍 할 때 메모리의 각 쓰기가 영향을 미칠 수 있습니다 ...이 점에서 대부분의 컴파일러가 어떻게 작동하는지 이해해야합니다. – Aki

+0

대부분의 컴파일러는 3 진 및 if/else 블록을 정확하게 동일한 기계 코드로 최적화합니다. 또한 제 삼자는 제 겸손한 견해로 거의 읽을 수없는 것을 만듭니다. – Salgar

+0

당신은 가독성을 위해 당신이 옳다고 생각합니다. 그러나 주관적이며 그러한 칭의에 사용되는 것을 보았습니다. 내가 삼항을 다른 경우와 비교하고 싶지 않다는 것을 이해하십시오. else 조건은 if와 함께 사용되지 않는다는 것을 의미하는 반면, 그것은 ternary와 함께 취해진 다 ... 또는 그것입니까? (그것은 내 질문이다). 컴파일러가 논리적이고 유창하고 공격적이며 최적화되어지기를 원하는지 알아내는 것은 어렵습니다. 나는 단지 궁금하다. – Aki

1

때때로 bitselect라고하는 분기없는 삼항 연산자를 사용할 수 있습니다 (조건 : true : false).

여분의 작업에 대해 걱정하지 마십시오. if 문 분기와 비교하면 아무 것도 아닙니다.

bitselect 구현 :

inline static int bitselect(int condition, int truereturnvalue, int falsereturnvalue) 
{ 
    return (truereturnvalue & -condition) | (falsereturnvalue & ~(-condition)); //a when TRUE and b when FALSE 
} 

inline static float bitselect(int condition, float truereturnvalue, float falsereturnvalue) 
{ 
    //Reinterpret floats. Would work because it's just a bit select, no matter the actual value 
    int& at = reinterpret_cast<int&>(truereturnvalue); 
    int& af = reinterpret_cast<int&>(falsereturnvalue); 
    int res = (at & -condition) | (af & ~(-condition)); //a when TRUE and b when FALSE 
    return reinterpret_cast<float&>(res); 
}