81 votes

Incrémentation de jeux de bits "masqués

Je suis actuellement en train d'écrire un énumérateur d'arbres et j'ai rencontré le problème suivant :

Je cherche des ensembles de bits masqués, c'est-à-dire des ensembles de bits où les bits de l'ensemble sont un sous-ensemble d'un masque. 0000101 avec masque 1010101 . Ce que je veux faire, c'est incrémenter le jeu de bits, mais uniquement en ce qui concerne les bits masqués. Dans cet exemple, le résultat serait 0010000 . Pour rendre les choses un peu plus claires, n'extrayez que les bits masqués, c.-à-d. 0011 et les incrémenter à 0100 et les distribuer à nouveau aux bits de masque, ce qui donne 0010000 .

Quelqu'un voit-il un moyen efficace de le faire, à moins d'implémenter l'opération à la main en utilisant une combinaison de balayages binaires et de masques de préfixe ?

123voto

zch Points 7275

Il suffit de remplir les bits non masqués avec des uns pour qu'ils propagent la retenue :

// increments x on bits belonging to mask
x = ((x | ~mask) + 1) & mask;

11 votes

C'est un joli tour... Presque la magie dont j'ai dit qu'elle n'existait pas :)

8 votes

@EugeneSh. Ne jamais croire que ce n'est pas le cas.

24 votes

Probablement pas important pour le PO puisqu'ils ont accepté, mais il faut peut-être noter que cela mettra à zéro les bits non-masqués. S'ils étaient nécessaire ailleurs, vous devrez être plus prudent en remplaçant x . Possiblement x = (x & ~mask) | (((x | ~mask) + 1) & mask); .

20voto

nglee Points 1560

Bien que cela ne soit pas intuitif par rapport à la réponse acceptée, cela fonctionne en seulement 3 étapes :

x = -(x ^ mask) & mask;

Ceci peut être vérifié comme suggéré par zch :

  -(x ^ mask)
= ~(x ^ mask) + 1  // assuming 2's complement
= (x ^ ~mask) + 1
= (x | ~mask) + 1  // since x and ~mask have disjoint set bits

Elle devient alors équivalente à la réponse acceptée.

2 votes

La réponse de zch est très intuitive, je vois immédiatement qu'elle est juste grâce à son explication claire. Quelle est la logique de cette réponse ? Comment cette formule fonctionne-t-elle pour donner l'effet désiré ? Je suis curieux de connaître le processus de découverte, la nature de l'intuition ici.

0 votes

Je pense que votre vérification serait beaucoup plus simple si vous prouviez simplement que -(x ^ mask) == (x | ~mask) + 1 chaque fois que x est un sous-ensemble de masque et a ensuite fait référence à ma réponse.

5 votes

-(x^mask) == ~((x ^ mask) - 1) == ~(x ^ mask) + 1 == (x ^ ~mask) + 1 == (x | ~mask) + 1 . La dernière équation est valable parce que les ensembles de bits sont disjoints, les autres sont toujours vraies (au moins en 2-complément).

7voto

DAle Points 7149

Si l'ordre d'itération n'est pas si important, et qu'une opération de décrémentation répond à vos besoins, il est possible de n'utiliser que deux opérations :

Commençons par

x = mask

et récupérer la valeur précédente avec

x = (x - 1) & mask

x - 1 change le dernier bit non nul en zéro, et met tous les bits moins significatifs à 1. Ensuite, & mask ne laisse que des bits de masque parmi eux.

0 votes

2 opérations, bien. Je dirais cependant que c'est la même approche, en propageant seulement les emprunts par les zéros, plutôt que les reports par les uns.

0 votes

@zch, c'est vrai, merci. Je vais reformuler la réponse

0 votes

Ne fonctionne que si x commence avec tous les bits non-masqués clairs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X