1

I have a simple doubt about the flow of the below code snippet. I compare this code block both on the high level and assembly instruction level. And I found that ?: is far better than branching.

const int THUMB_IMAGE = 0;
const int ICON_IMAGE = 1;
const int UNKNOWN_IMAGE = 2;

void foo( int nFlag ){
    int CopyFlag = nFlag;
    if( CopyFlag == THUMB_IMAGE )
        CopyFLag = ICON_IMAGE; // Setting THUMB and ICON images to same level
    // Executing rest of the code
}

void foo1( int nFlag ){
    int CopyFlag = ( nFlag == THUMB_IMAGE ) ?
                     ICON_IMAGE : nFlag; // Setting THUMB and ICON images to same level
    // Executing rest of the code
}

int main(void){
   foo( THUMB_IMAGE );
   foo1( THUMB_IMAGE );
   return 0;
}

In the above code snippet, there are two functions, foo() and foo1(). These two functions are setting two image types to ICON_IMAGE.

The question is how the assignment and if() are implemented?

Which conditional statements are highly optimized, if() or ternary operator ?:?

On the assembly code level, to translate the if(), CMP (branch) and MOV instructions are necessary. And for the ?: operator, I think there are some special instructions but the branch instruction is completely avoided.

Can anyone tell which is the best method?

In foo(), the very first an assignment operation is done regardless of the if condition. It may not be needed all the time.

But in foo1(), this is done in the ?: operator section and avoids the unwanted assignment operation. I want to know if the code in foo() or foo1() respectively, is optimized?

Mysticial
  • 464,885
  • 45
  • 335
  • 332
  • Why you want saves on matches? It's strange idea. How about look at assembly code? – ForEveR Feb 28 '13 at 08:33
  • It is just to do some business with code, just get around some situation. like patch work..... – RyanAdamVeet Feb 28 '13 at 08:36
  • 13
    folks, English is probably not this person's main language. down-voting for poor grammar is in poor taste: So Knock it off! – C.J. Feb 28 '13 at 08:38
  • 1
    @CJohnson Agreed, instead please suggest an edit. I have tried to fix the English now, hopefully the question will be a bit clearer. – Lundin Feb 28 '13 at 09:00
  • there is nothing big difference but it actually depends on size of variable if variable is holding big string then you should use if() – Shushant Feb 28 '13 at 09:30

9 Answers9

2

Without optimization, you're setting copyFlag twice the way you write the if, only once when you use ?. The equivalent to your ?: using if would be:

int copyFlag;
if ( nFlag == thumbImage ) 
    copyFlag = iconImage;
else
    copyFlag = nFlag;

With optimization, I would expect all three variants to generate more or less the same code.

In general, you shouldn't worry about this sort of thing. Above all, I wouldn't worry about the assembler; the same optimizations are available in both cases. (It's possible to write this without any branch instructions; whether that is the best solution or not is for the compiler to decide, not you.) The optimizer will take care of it. You should write the code in the clearest way possible—in this case, that means the ternary operator.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
1

On a decent compiler, there is absolutely no difference in efficiency between if and ?:.

The only difference between these two ways of doing the same thing, is that ?: contains subtle promotion rules. The 2nd and 3rd expression are balanced against each other, as if they were operands of the same operation. If you are unlucky, this can cause bugs, but it will probably not make ?: less efficient than if.

For example, if you write int x = 1; then x ? 1 : 1.0f; then the resulting type is float, which might perhaps be unexpected.

Lundin
  • 195,001
  • 40
  • 254
  • 396
1

For x86 series, a compiler with optimization off would translate if... else... to a branch with jump instructions in x86, and ...?...:... to conditional move instructions in x86.

If you write the condition as straight forward as in your code, good compiler would optimized the branch into conditional move.

For performance, the branch would be better if it's easy to predict, and the conditional move would be better if it's hard to predict. The reason is branch instruction would incur significant branch prediction penalty in modern processor if the prediction is not correct, while conditional move instruction has a slightly slower latency regardless of whether the condition holds or not.

See my answer for detailed explanation here:

Community
  • 1
  • 1
WiSaGaN
  • 46,887
  • 10
  • 54
  • 88
1

I'm 100% sure that any modern compiler will optimise both of these to the same thing. Of course, in this particular example, the compiler will probably remove all of the code for foo and foo1, as these do nothing in this example, unless you turn off optimisation - which is not a fair comparison. You need a more complex example where the compiler can't determine the input and needs the result of the code.

Now, if I'm right in what this code does - namely, copying some sort of image - then I'd expect that the if-statement at the beginning of the function is extremely little of the overall time spent in this function.

As always with performance, first profile your code and identify "hotspots", then concentrate on making the hotspots run faster. I'm pretty convinced this one isn't a hotspot. So you are trying to optimize something that isn't going to make a big difference in your code.

And further, don't trust someone on the internet to tell you which version of your code is faster - run it in the different configurations and then make a decision. Preferably on a several machines with different hardware (different manufacturers processors, in this particular case) - unless it's a hobby project that only needs to run fast on your current computer.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
0

It depends on the compiler. Some compilers will optimize both statements and produce the same assembly code from that.

Just as a side note, the advantage of using the fastest solution for this is very very small and it is not worth the trouble. If you call this code for setting an image's type, it's most likely that you are going to use that image somewhere (even if just changing image types and not displaying them), which takes a lot more CPU cycles than an extra assembler instruction in an if or ?: statement. Writing your code using mostly the ternary operator ?: might make development and maintenance harder and it's just not worth the effort.

EDIT: The difference in performance comes from the fact that you are performing two assignments in foo when nFlag is THUMB_IMAGE. The following foo2 should be closer in performance to foo1.

void foo2( int nFlag ){
   int CopyFlag;
   if( nFlag == THUMB_IMAGE )
       CopyFlag = ICON_IMAGE; // Setting THUMB and ICON images to same level
   else
       CopyFlag = nFlag;
   // Executing rest of the code
}

The difference in performance might have come that either the compiler was not build to optimize the assignment and if statement with assignment on the same variable into an if-else statement (as an example the Sun/Oracle Java compiler does that) or from the fact that the compiler might have been instructed not to optimize code (via a compilation flag/parameter).

lucian.pantelimon
  • 3,673
  • 4
  • 29
  • 46
  • 2
    In this particular case, using the ternary operator results in more readable and easier to maintain code. – James Kanze Feb 28 '13 at 08:47
  • @JamesKanze Yes, I do agree with that. What I meant was not to bother choosing `?:` over `if` when not necessarily needed - i.e. the condition is of greater complexity or has function calls in it. I have worked on a project that used `?:` a lot and, even though it makes code more readable, it is hellish to debug the software when there are a lot of ternary operators with function calls. +1 on the comment for stating this out better than the answer. – lucian.pantelimon Feb 28 '13 at 08:59
  • @JamesKanze I agree completely. Bizarrely, we have some coding convention at work that claims one should *not* use the ternary operator in these cases (or ever) because it is too *confusing*. So people are encouraged to write code like in this example. Sadly, the effects of this are seen all over the code base. – juanchopanza Feb 28 '13 at 09:14
  • @juanchopanza Maybe the author of the coding convention was paid by the line. (Or maybe he just didn't know C++.) Our coding conventions encourage the use of `?:` where appropriate: if the important thing to understand when reading the code is that the variable is initialized, then that is what we write, and if there's a condition in the initialization, we use `?:`. – James Kanze Feb 28 '13 at 09:39
  • @JamesKanze I suspect it is a lack of knowledge of C++, given the code examples used to motivate the convention (I actually considered posting an entry on the thedailywtf.com), although I must admit that if there wasn't so much bad code out there, they wouldn't need so many developers to look after it... – juanchopanza Feb 28 '13 at 09:43
  • @juanchopanza Aha. Another possible motivation: job security. – James Kanze Feb 28 '13 at 09:52
0

In theory there shouldn't be any difference and in theory an omniscient optimizer will optimize this to the same generated code.

In practice I know for a fact that at least certain versions of gcc on amd64 will generate a branch with if and use the cmov instruction with :? regardless of optimization level and flags. Sounds like a small thing, but in the code base where I tested this on a construct similar to this that was used in a sort of a lock changing the if to :? gave a 10% reduced cpu usage on a macro benchmark.

Of course, your mileage may vary depending on the compiler, compiler version, flags and other things outside of your control. So test on your compiler and see if it's worth optimizing.

Art
  • 19,807
  • 1
  • 34
  • 60
0

With an optimizing compiler, you should not see any difference. Just use whatever is more readable.

Axel
  • 13,939
  • 5
  • 50
  • 79
0

All the other answers, indicating that a decent compiler won't care, and that you probably shouldn't worry unless you see this function popping up in a profiler as a performance bottleneck, are completely correct.

However... if you are on some architecture where branches are expensive, and conditional moves don't exist, or your compiler is really awful... you could compare the naive version, with the following:

void foo( int nFlag ){
    int CopyFlag = ((nFlag & 2) << 1) + 1;
    // Rest of code...

Obviously that needs to come with a lot of caveats (it's ugly, hacky, unmaintainable, etc.)... It would parallelise though!

Really what I'm getting at however, is that rather than worrying about the exact code-gen of two similar language constructs, you should (after establishing that you even have a performance problem) look at the algorithm itself, and whether or not it can be changed or replaced in such a way as to avoid the issue you are having entirely.

JasonD
  • 16,464
  • 2
  • 29
  • 44
0

The performance difference may exist only if you switch optimization off. Modern compilers should optimize both versions equally.

The reasons to choose one of the solutions may be:

  1. Readability. However, personal preferenes may vary.
  2. Debug version performance. However, difference should be small.
  3. Ease of debugging. It is not possible to set a breakpoint at a certain branch of a ternary operator (unless you go to assembly language level, then sometimes it's possible).
  4. Coverage analysis. If you write tests and gather coverage analysis info, if statement allows you to understand if both branches were tested. Ternary operator does not. One of the expressions can be not evaluated at all during a program run, but code coverage tools will show you everything is covered.
Ellioh
  • 5,162
  • 2
  • 20
  • 33