По умолчанию в корпусе коммутатора

Ниже приведен код, который мне нужно оптимизировать и спланировать, что было бы хорошо перейти к переключению. Но я могу сравнить на случай. Поэтому я планировал сделать comaparision (len> 3) стандартным случаем.

Если я сделаю сравнительную часть (len> 3) по умолчанию и добавлю по умолчанию, как первый в swith, будет быстрее?

Или как я могу сделать код ниже в качестве оператора switch?

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; } 

Возможно нет. И if...else и switch...case – это конструкции высокого уровня. То, что замедляет вас, – это предсказание ветвей. Чем лучше ваш outlook, тем быстрее будет работать ваш код. Сначала вы должны поставить свой наиболее распространенный случай, if , во-вторых, в else if и так, как и вы писали. Для switch результат зависит от внутренней реализации компилятора, которая может изменить порядок дел, несмотря на ваш собственный заказ. Значение по default должно быть фактически зарезервировано для менее встречающихся ситуаций, потому что остальная часть условий должна быть проверена, прежде чем вернуться к default .

Чтобы все это сделать, использование производительности if...else оптимально, если вы зададите свои условия в правильном порядке. Что касается switch...case то это компилятор специфический и зависит от применяемых оптимизаций.

Также обратите внимание, что switch...case более ограничен, чем if...else поскольку он поддерживает только простое сравнение значений.

Хотя вы согласились с тем, что, вероятно, лучший ответ, я хотел бы предоставить альтернативу.

Обратите внимание, что стандартная оговорка применяется – оптимизация – это не оптимизация, если вы не профилировали свой код.

Однако, если вы сталкиваетесь с низкой производительностью, связанной с филиалами, вы можете уменьшить или устранить их. То, что ваш код имеет одно или несколько сравнений неравенства, не является препятствием – вы можете сократить свои случаи до набора прямых равенств и, если необходимо, использовать это для индексации таблицы, а не для ветвления вообще.

 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); } 

Обратите внимание, что эти коды делают несколько предположений, которые могут не выполняться на практике, но поскольку мы делаем дикое предположение, что это даже требует оптимизации в первую очередь …

Кроме того, обратите внимание, что лучше оптимизация может быть возможной благодаря большему знанию фактического диапазона и типа входного параметра, и действительно, какие фактические действия должны быть выполнены.

вы не можете перемещать сравнения в оператор switch. Он использует одиночные проверки для своих выборов .. то есть:

 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; } 

используйте разрывы, чтобы предотвратить, чтобы заявления о делах работали друг с другом.

ваш код будет «оптимизирован», поскольку он будет в текущем состоянии.

Единственный способ, которым вы собираетесь знать, – сравнить его с вашим компилятором. Если производительность является проблемой, вы должны использовать опцию, чтобы предоставить компилятору выход профилировщика и позволить ему решить; он, как правило, найдет наилучшее решение. (Обратите внимание, что даже в конкретной архитектуре, например Intel, наилучшее решение с точки зрения машинных инструкций может варьироваться от одного процессора к другому.)

В вашем случае переключатель, вероятно, будет выглядеть так:

 switch ( len ) { case 2: // ... break; case 3: // ... break; default: if ( len > 3 ) { // ... } else { // ... } } 

Имея только два эффективных случая, компилятор не имеет большого труда работать. Типичная реализация (без экстремальной оптимизации) проведет проверку границ, а затем ищет таблицу для двух явных случаев. Любой достойный компилятор затем подберет, что сравнение в вашем случае по default соответствует одной из проверок границ, которые оно уже выполнило, а не дублирует. Но только с двумя случаями таблица перехода, вероятно, не будет иметь существенного значения по сравнению с двумя сравнениями, тем более, что вы будете вне пределов в наиболее частом случае.

Пока у вас нет фактических данных профилировщика, что это узкое место в вашем коде, я бы не стал беспокоиться об этом. После того, как у вас есть эта информация, вы можете просмотреть различные варианты, чтобы увидеть, что быстрее, но я подозреваю, что если вы будете использовать максимальную оптимизацию и информацию профилирования корда обратно в компилятор, разница не будет.

Если вас беспокоит скорость, правда в том, что ваши утверждения if...else или switch...case не будут иметь реального влияния на скорость вашего приложения, если у вас их не будет сотни. Места, где вы теряете скорость, находятся в ваших итерациях или петлях. Чтобы ответить на ваш вопрос конкретно, вы не можете преобразовать свой оператор if...else оператор switch...case с указанием по default ; но с учетом сказанного, если вы сделали конвертировать в switch...case то вы будете, чтобы они работали с одинаковой скоростью (разница слишком мала, чтобы быть подхваченной обычными инструментами бенчмаркинга).

Вы можете использовать диапазон в случае:

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

Изменить: но это расширение, предоставляемое GCC …