Est-il possible de limiter une valeur entière à une certaine plage sans créer de twig?

Juste par curiosité. Si j’ai quelque chose comme:

if(x  some_maximum) x = some_maximum; return x; 

Y a-t-il un moyen de ne pas créer de twig? C’est c ++.

Addendum: Je veux dire pas d’instructions de twig dans l’assemblage. C’est une architecture MIPS.

Il existe des astuces pour trouver le minimum ou le maximum de deux nombres, vous pouvez donc utiliser ceux-ci pour trouver min(max(x, 0), some_maximum) . À partir d’ ici :

 y ^ ((x ^ y) & -(x < y)); // min(x, y) x ^ ((x ^ y) & -(x < y)); // max(x, y) 

Comme le dit la source, il est probablement plus rapide de le faire de manière normale, malgré la twig

Cela dépendra du compilateur et du processeur, mais si vous utilisez ?: Il peut être traduit en un déplacement conditionnel (au moins sur les processeurs Intel) qui n’utilise pas de twig.

x = x < 0 ? 0 : x; x = x > max ? max : x;

Cela peut utiliser l’instruction CMOV (voir http://www.intel.com/software/products/documentation/vlin/mergedprojects/analyzer_ec/mergedprojects/reference_olh/mergedProjects/instructions/instruct32_hh/vc35.htm ), dont le but est d’éviter ramification (et donc pénalités de prédiction de twig).

Edit : ce fil peut vous intéresser. Les points de référence montrent que les déplacements conditionnels ne vous apporteront des gains de vitesse que sur les twigs peu prévisibles, alors que les twigs hautement prévisibles (telles que celles d’une boucle longue) préfèrent l’approche standard.

Utilisation de l’opérateur ternaire 🙂

 return x < 0 ? 0 : x > some_maximum ? : some_maximum : x; 

Cela dépend de votre architecture. Pour ARM, au moins, le compilateur émettrait probablement des instructions exécutées de manière conditionnelle et le code machine résultant ne contiendrait pas de twig. Je ne peux pas penser à un bon moyen de rendre cela explicite dans le programme C.

S’il est possible de limiter à des puissances de 2 (non inclus), il suffit d’aller avec

int newx = x & ((highest power of 2) - 1)

pas tout à fait sûr de gérer le cas (si x <0 cas) ou le générique (x

Pour les futurs problèmes comme celui-ci, la page de piratage pourrait être utile: http://graphics.stanford.edu/~seander/bithacks.html .

Puisque le bithack pour min et max était déjà affiché, en voici un autre:

 // CHAR_BIT is number of bits per byte. // sign = 1 if x < 0, sign = 0 otherwise (according to the page above) int sign = (int)((unsigned int)((int)x) >> (sizeof(int) * CHAR_BIT - 1)); int y = (1-sign)*x; // if x < 0, then y = 0, else y = x. // Depending on arch, the below _might_ cause a branch. // (on x64 it does not cause a branch, not sure about MIPS) int z = !(y/some_maximum); // if 0 <= y < some_maximum, z = 1, else z = 0 int ret = z*y + (1-z)*some_maximum; // if z =1, then ret = y; else ret = some_maximum. return ret; 

Je viens de l'essayer, et cela a fonctionné pour les quelques cas de test que j'ai eu.

Voici le code d'assemblage de mon ordinateur (Intel Arch) qui ne montre aucune twig.

 int cap(int x) { 00F013A0 push ebp 00F013A1 mov ebp,esp 00F013A3 sub esp,0FCh 00F013A9 push ebx 00F013AA push esi 00F013AB push edi 00F013AC lea edi,[ebp-0FCh] 00F013B2 mov ecx,3Fh 00F013B7 mov eax,0CCCCCCCCh 00F013BC rep stos dword ptr es:[edi] int some_maximum = 100; 00F013BE mov dword ptr [some_maximum],64h // CHAR_BIT is number of bits per byte. // sign = 1 if x < 0, sign = 0 otherwise (according to the page above) int sign = (int)((unsigned int)((int)x) >> (sizeof(int) * CHAR_BIT - 1)); 00F013C5 mov eax,dword ptr [x] 00F013C8 shr eax,1Fh 00F013CB mov dword ptr [sign],eax int y = (1-sign)*x; // if x < 0, then y = 0, else y = x. 00F013CE mov eax,1 00F013D3 sub eax,dword ptr [sign] 00F013D6 imul eax,dword ptr [x] 00F013DA mov dword ptr [y],eax // Depending on arch, the below _might_ cause a branch. // (on x64 it does not cause a branch, not sure about MIPS) int z = !(y/some_maximum); // if 0 <= y < some_maximum, z = 1, else z = 0 00F013DD mov eax,dword ptr [y] 00F013E0 cdq 00F013E1 idiv eax,dword ptr [some_maximum] 00F013E4 neg eax 00F013E6 sbb eax,eax 00F013E8 add eax,1 00F013EB mov dword ptr [z],eax int ret = z*y + (1-z)*some_maximum; // if z =1, then ret = y; else ret = some_maximum. 00F013EE mov eax,dword ptr [z] 00F013F1 imul eax,dword ptr [y] 00F013F5 mov ecx,1 00F013FA sub ecx,dword ptr [z] 00F013FD imul ecx,dword ptr [some_maximum] 00F01401 add eax,ecx 00F01403 mov dword ptr [ret],eax return ret; 00F01406 mov eax,dword ptr [ret] } 00F01409 pop edi 00F0140A pop esi 00F0140B pop ebx 00F0140C mov esp,ebp 00F0140E pop ebp 00F0140F ret 
 x = min(max(x,0),100); 

La ramification est bien cachée dans les fonctions avec des noms normaux.

Suggérant de créer un modèle clip_by.

 x = ((int)(x > some_maximum)) * some_maximum + ((int)(x > 0 && x <= some_maximum)) * x;