2vision2
2vision2

Reputation: 5023

Default in switch case

The below is the code which I need to optimize and planned that it would be good to move to the switch construct. But I can compare in case. So I planned to make the comparison (len > 3) as the default case.

If I make the comparison part (len > 3) as the default case and add the default as the first in the switch, will it be faster?

Or how can I make the below code as a switch statement?

if ( len > 3 ) {
    // Which will happen more often;
}
else if ( len == 3 ) {
    // Next case which may occur often;

} else if ( len == 2 ) {
    // The next priority case;

} else {
    // And this case occurs rarely;

}

Upvotes: 4

Views: 6706

Answers (6)

piwi
piwi

Reputation: 5336

You can use a range in a case:

switch (len) {
  case 3 ... INT_MAX:
    // ...
    break;
  case 2:
    // ...
    break;
  default:
    // ...
    break;
 }

But that is an extension provided by GCC...

Upvotes: 0

iKlsR
iKlsR

Reputation: 2672

You can't move comparisons into a switch statement... it uses single checks for its selections.. i.e.,

switch (len) {

    case 1:
        // Do case 1 stuff here
    break;

    case 2:
        // Do case 2 stuff here
    break;

    case 3:
        // Do case 3 stuff here
    break;
}

Use breaks to prevent the case statements from running into each other. Read more here.

Your code is as 'optimized' as it will get in its current state...

Upvotes: 2

justkash
justkash

Reputation: 709

If you are worried about speed, the truth is that your if...else or switch...case statements won't have a real impact of your application speed unless you have hundreds of them. The places where you lose speed is in your iterations or loops. To answer your question specifically, you cannot convert your if...else statement to a switch...case statement with the default appearing first; but with that said, if you did convert to a switch...case then you will that they run at the same speed (difference is too minute to be picked up by conventional benchmarking tools).

Upvotes: 1

James Kanze
James Kanze

Reputation: 153899

The only way you're going to know is to benchmark it with your compiler. If performance is an issue, you should use the option to provide the compiler with profiler output, and let it decide; it will generally find the best solution. (Note that even on a specific architecture, like Intel, the best solution in terms of machine instructions may vary from one processor to the next.)

In your case, the switch would probably look like:

switch ( len ) {
case 2:
    //  ...
    break;

case 3:
    //  ...
    break;

default:
    if ( len > 3 ) {
        // ...
    } else {
        // ...
    }
}

With only two effective cases, the compiler doesn't have much to work with. A typical implementation (without extreme optimization) would do bounds checking, then a table lookup for the two explicit cases. Any decent compiler will then pick up that the comparison in your default case corresponds to one of the bounds checks it has already done, and not duplicate it. But with only two cases, the jump table will probably not make a significant difference compared to the two comparisons, especially as you'll be out of bounds in the most frequent case.

Until you have actual profiler information that this is a bottleneck in your code, I wouldn't worry about it. Once you have that information, you can profile different variants to see which is faster, but I suspect that if you use maximum optimization and feed profiling information back into the compiler, there will be no difference.

Upvotes: 1

SomeWittyUsername
SomeWittyUsername

Reputation: 18338

Probably not. Both if...else and switch...case are high-level constructs. What slows you down is the branch prediction. The better your prediction is the faster your code will run. You should put your most occurring case in first if, second in the else if and so on, just like you wrote. For switch the result depends on the internal compiler implementation which can reorder the cases despite your own order. The default should be actually reserved for the less occurring situations because rest of the conditions must be checked before falling back to default.

To conclude all this, performance-wise usage of if...else is optimal as long as you set your conditions in the correct order. Regarding switch...case it's compiler specific and depends on the applied optimizations.

Also note that switch...case is more limited than if...else since it supports only simple comparison of values.

Upvotes: 6

JasonD
JasonD

Reputation: 16582

Although you've accepted what is probably the best answer, I wanted to provide an alternative.

Note that the standard caveat applies - optimisation isn't optimisation unless you've profiled your code.

However if you are encountering poor performance relating to branches, you can reduce or eliminate them. That your code has one or more inequality comparisons is not an obstacle - you can reduce your cases down to a set of direct equalities, and if necessary use that to index a table, rather than branch at all.

void doSomething(int len)
{
    static const char* str[] =
    {   "%2d > 3\n",
        "%2d < 2\n",
        "%2d = 2\n",
        "%2d = 3\n"
    };

    int m1 = (len-2)>>31;
    int m2 = (len-4)>>31;

    int r = (len & m2 & ~m1) + !!m1;

    printf(str[r],len); 
}

Note that this codes makes several assumptions which may not hold in practice, but as we're making the wild assumption that this even needs optimising in the first place...

Also, note that better optimisations may be possible with more knowledge about the actual range and type of the input parameter, and indeed what the actual actions taken need to be.

Upvotes: 4

Related Questions