Défaut dans le cas du commutateur

Le code ci-dessous est le code que je dois optimiser et qui prévoit que ce serait bien de passer à un changement. Mais je peux comparer au cas où. J’ai donc prévu de faire la comparaison (len> 3) comme cas par défaut.

Si je fais de la comparaison (len> 3) la casse par défaut et que j’ajoute la valeur par défaut en tant que premier, cela sera-t-il plus rapide?

Ou comment puis-je créer le code ci-dessous en tant qu’instruction 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; } 

Probablement pas. Les deux if...else et switch...case sont des constructions de haut niveau. Ce qui vous ralentit, c’est la prédiction de twig. Plus votre prédiction est bonne, plus votre code sera exécuté rapidement. Vous devriez mettre votre cas le plus souvent en premier if , en second lieu dans le else if et ainsi de suite, comme vous l’avez écrit. Pour switch le résultat dépend de l’implémentation interne du compilateur, qui peut réorganiser les cas malgré votre propre ordre. La default doit en fait être réservée aux situations les moins fréquentes, car le rest des conditions doit être vérifié avant de revenir à la default .

Pour conclure, l’utilisation de if...else termes de performances est optimale tant que vous définissez vos conditions dans le bon ordre. En ce qui concerne switch...case il est spécifique au compilateur et dépend des optimisations appliquées.

Notez également que switch...case est plus limité que if...else car il ne prend en charge que la simple comparaison de valeurs.

Bien que vous ayez accepté ce qui est probablement la meilleure réponse, je souhaitais proposer une alternative.

Notez que la mise en garde standard s’applique: l’optimisation n’est pas une optimisation à moins que vous n’ayez profilé votre code.

Toutefois, si vous rencontrez des problèmes de performances liés aux twigs, vous pouvez les réduire ou les éliminer. Le fait que votre code comporte une ou plusieurs comparaisons d’inégalité n’est pas un obstacle: vous pouvez réduire vos cas à un ensemble d’égalités directes et, si nécessaire, vous en servir pour indexer une table plutôt que de créer une twig.

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

Notez que ces codes émettent plusieurs hypothèses qui peuvent ne pas être vérifiées dans la pratique, mais comme nous émettons l’hypothèse sauvage que cela doit même être optimisé en premier lieu …

Notez également que de meilleures optimisations peuvent être possibles avec davantage de connaissances sur la plage et le type réels du paramètre d’entrée, ainsi que sur les actions réellement entresockets.

vous ne pouvez pas déplacer les comparaisons dans une instruction switch .. il utilise des contrôles uniques pour ses sélections .. c’est-à-dire:

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

utilisez des pauses pour empêcher les déclarations de cas de se rencontrer, lisez plus ici

votre code est aussi “optimisé” que dans l’état actuel.

Le seul moyen de le savoir est de le comparer à votre compilateur. Si les performances sont un problème, vous devez utiliser l’option pour fournir au compilateur une sortie du profileur et le laisser décider. il trouvera généralement la meilleure solution. (Notez que même sur une architecture spécifique, telle qu’Intel, la meilleure solution en termes d’instructions machine peut varier d’un processeur à l’autre.)

Dans votre cas, le commutateur ressemblerait probablement à ceci:

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

Avec seulement deux cas efficaces, le compilateur n’a pas grand-chose à travailler. Une implémentation typique (sans optimisation extrême) ferait une vérification des limites, puis une table pour les deux cas explicites. Tout compilateur décent saura alors que la comparaison dans votre cas default correspond à l’une des vérifications des limites qu’elle a déjà faite, et non la dupliquer. Mais avec seulement deux cas, la table de saut ne fera probablement pas une différence significative par rapport aux deux comparaisons, d’autant plus que vous serez hors limites dans le cas le plus fréquent.

Tant que vous ne disposerez pas d’informations sur le profileur indiquant qu’il s’agit d’un goulot d’étranglement dans votre code, je ne m’en inquiéterais pas. Une fois que vous avez cette information, vous pouvez profiler différentes variantes pour voir laquelle est la plus rapide, mais je soupçonne que si vous utilisez l’optimisation maximale et les informations de profilage dans le compilateur, il n’y aura aucune différence.

Si la rapidité vous inquiète, la vérité est que vos déclarations de switch...case if...else ou de switch...case n’auront pas d’incidence réelle sur la vitesse de votre application, sauf si vous en avez des centaines. Les endroits où vous perdez de la vitesse se trouvent dans vos itérations ou vos boucles. Pour répondre spécifiquement à votre question, vous ne pouvez pas convertir votre instruction if...else instruction switch...case avec la default apparaissant en premier; mais avec cela dit, si vous convertissez en un switch...case alors vous voulez qu’ils fonctionnent à la même vitesse (la différence est trop minime pour être relevée par les outils d’parsing comparative classiques).

Vous pouvez utiliser une plage dans un cas:

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

Edit: mais c’est une extension fournie par GCC …