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; }
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.
0
dans le bit bas si les bits haut et bas sont identiques, et un 1
s’ils sont différents. 9
, le bit bas restra tel quel et sera copié dans le bit haut. Code:
unsigned SwitchBits(unsigned n) { return ((((n >> 3) ^ n) & 0x11111111) * 0x9) ^ n; }