Commutation de bits dans chaque quartet d’un int

Comment puis-je basculer les 0ème et 3ème bits de chaque quartet dans un entier en utilisant uniquement des opérations sur les bits (pas de structures de contrôle)? Quel type de masques dois-je créer pour résoudre ce problème? Toute aide serait appréciée. Par exemple, 8 (1000) devient 1 (0001).

/* * SwitchBits(0) = 0 * SwitchBits(8) = 1 * SwitchBits(0x812) = 0x182 * SwitchBits(0x12345678) = 0x82a4c6e1 * Legal Operations: ! ~ & ^ | + <> */ int SwitchBits(int n) { } 

Code:

 #include  #include  static uint32_t SwitchBits(uint32_t n) { uint32_t bit0_mask = 0x11111111; uint32_t bit3_mask = 0x88888888; uint32_t v_bit0 = n & bit0_mask; uint32_t v_bit3 = n & bit3_mask; n &= ~(bit0_mask | bit3_mask); n |= (v_bit0 << 3) | (v_bit3 >> 3); return n; } int main(void) { uint32_t i_values[] = { 0, 8, 0x812, 0x12345678, 0x9ABCDEF0 }; uint32_t o_values[] = { 0, 1, 0x182, 0x82A4C6E1, 0x93B5D7F0 }; enum { N_VALUES = sizeof(o_values) / sizeof(o_values[0]) }; for (int i = 0; i < N_VALUES; i++) { printf("0x%.8" PRIX32 " => 0x%.8" PRIX32 " (vs 0x%.8" PRIX32 ")\n", i_values[i], SwitchBits(i_values[i]), o_values[i]); } return 0; } 

Sortie:

 0x00000000 => 0x00000000 (vs 0x00000000) 0x00000008 => 0x00000001 (vs 0x00000001) 0x00000812 => 0x00000182 (vs 0x00000182) 0x12345678 => 0x82A4C6E1 (vs 0x82A4C6E1) 0x9ABCDEF0 => 0x93B5D7F0 (vs 0x93B5D7F0) 

Notez l’utilisation de uint32_t pour éviter un comportement non défini avec des bits de signature dans des entiers signés.

Pour obtenir un peu, vous pouvez le masquer en utilisant AND. Pour obtenir le bit le plus bas, par exemple:

 x & 0x01 

Pensez à la manière dont AND fonctionne: les deux bits doivent être définis. Puisque nous sums AND avec 1, tous les bits sauf le premier doivent être 0, car ils sont 0 dans 0x01. Le bit le plus bas sera 0 ou 1, selon le contenu de x ; Dit différemment, le bit le plus bas sera le bit le plus bas de x , ce que nous voulons. Visuellement:

  x = abcd AND 1 = 0001 -------- 000d 

(où abcd représente les bits dans ces slots; nous ne soaps pas ce qu’ils sont)

Pour le déplacer à la position du bit 3, il suffit de le déplacer:

 (x & 0x01) << 3 

Visuellement, encore:

 x & 0x01 = 000d << 3 ----------- d000 

Pour l'append, nous devons d'abord effacer cet endroit dans x pour notre bit. Nous utilisons ET encore:

 x & ~0x08 

Ici, nous 0x08 (ce qui correspond à 1000 en binary): cela signifie que tous les bits sauf le bit 3 sont mis à 1, et lorsque nous ET que, avec x , nous obtenons x sauf ce bit.

Visuellement,

  0x08 = 1000 (invert) ----------- 0111 AND x = abcd ------------ 0bcd 

Combinez avec OU:

 (x & ~0x08) | ((x & 0x01) << 3) 

Visuellement,

  x & ~0x08 = 0bcd | ((x & 0x01) << 3) = d000 -------------------------- dbcd 

Maintenant, cela ne déplace que les bits 0 à 3, et remplace simplement le bit 3. Nous devons toujours faire le bit 3 → 0. C'est simplement un autre:

 x & 0x08 >> 3 

Et nous devons effacer sa place:

 x & ~0x01 

Nous pouvons combiner les deux pièces de compensation:

 x & ~0x09 

Et alors:

 (x & ~0x09) | ((x & 0x01) << 3) | ((x & 0x08) >> 3) 

Cela ne traite bien sûr que le plus petit grignotage. Je laisserai les autres comme un exercice.

Essayez ci-dessous le code. Ici, vous devez savoir que l’opérateur au niveau du bit doit implémenter et corriger la position à placer. Il doit également connaître la maintenance, le déplacement et le basculement des propriétés de base.

  #include #define BITS_SWAP(x) x=(((x & 0x88888888)>>3) | ((x & 0x11111111)<<3)) | ((x & ~ (0x88888888 | 0x11111111))) int main() { int data=0; printf("enter the data in hex=0x"); scanf("%x",&data); printf("bits=%x",BITS_SWAP(data)); return 0; } 

OP

vinay @ vinay-VirtualBox: ~ / c_skill $ ./a.out

entrer les données en hex=0x1

bits=8

vinay @ vinay-VirtualBox: ~ / c_skill $ ./a.out

entrer les données en hex=0x812 bits=182

vinay @ vinay-VirtualBox: ~ / c_skill $ ./a.out

entrez les données en hex=0x12345678 bits=82a4c6e1

vinay @ vinay-VirtualBox: ~ / c_skill $

Essayez cette variante du swap xor:

 uint32_t switch_bits(uint32_t a){ static const mask = 0x11111111; a ^= (a & mask) << 3; a ^= (a >> 3) & mask; a ^= (a & mask) << 3; return a; } 
  1. Déplacez les bits bas aux bits hauts et masquez les bits résultants.
  2. Déplacez les bits hauts vers les bits bas et masquez les bits résultants.
  3. Masque tous les bits qui n’ont pas été déplacés.
  4. Combinez les résultats avec les OR.

Code:

 unsigned SwitchBits(unsigned n) { return ((n << 3) & 0x88888888) | ((n >> 3) & 0x11111111) | (n & 0x66666666); } 

Alternativement, si vous souhaitez être très intelligent. Cela peut être fait avec deux opérations en moins, bien que cela ne soit pas vraiment plus rapide en raison de certaines dépendances entre les instructions.

  1. Déplacez les bits hauts pour les aligner avec les bits bas
  2. XOR enregistre un 0 dans le bit bas si les bits haut et bas sont identiques, et un 1 s’ils sont différents.
  3. A partir de là, masquez uniquement le bit le plus bas de chaque quartet.
  4. A partir de là, multipliez par 9 , le bit bas restra tel quel et sera copié dans le bit haut.
  5. De là, XOR avec la valeur d’origine. dans le cas où les bits haut et bas sont identiques, aucun changement ne se produira correctement. S’ils sont différents, ils seront échangés efficacement.

Code:

 unsigned SwitchBits(unsigned n) { return ((((n >> 3) ^ n) & 0x11111111) * 0x9) ^ n; }