2008-08-29 6 views
33

Je sais que ce qui suit est vraiExiste-t-il un moyen d'effectuer un décalage de bits circulaire en C#?

int i = 17; //binary 10001 
int j = i << 1; //decimal 34, binary 100010 

Mais, si vous passez trop loin, les bits tombent à la fin. Où cela se produit est une question de la taille de l'entier avec lequel vous travaillez.

Existe-t-il un moyen d'effectuer un décalage de sorte que les bits tournent de l'autre côté? Je cherche une seule opération, pas une boucle for.

+0

Où une opération de ce type serait-elle utilisée? Quel est le but derrière faire un peu de rotation? Je n'ai pas besoin de savoir, mais je suis juste intéressé par l'expansion des connaissances. Keith –

+0

une très bonne question. Je viens de vérifier le code généré et le compilateur C# ne génère pas de code qui utilise les instructions de rotation du CPU (pas que l'architecture x86 les ait depuis le 8086 ...). C'est une honte. C fait cette optimisation. Les rotations sont également très importantes pour les tâches cryptographiques et dsp. –

Répondre

45

Si vous connaissez la taille du type, vous pouvez faire quelque chose comme:

uint i = 17; 
uint j = i << 1 | i >> 31; 

... exerceraient un décalage circulaire d'une valeur 32 bits.

Comme une généralisation à décalage circulaire gauche n bits, sur une variable bit b:

/*some unsigned numeric type*/ input = 17; 
var result = input << n | input >> (b - n); 


@The commentaire, il semble que C# ne traite le bit de valeurs signées différemment. J'ai trouvé quelques infos sur ce here. J'ai également changé l'exemple pour utiliser un uint.

+1

Puisque je ne connais pas C#, les opérateurs de décalage font-ils des changements arithmétiques ou logiques? Si arithmétique, cet algorithme ne peut pas être utilisé pour les entiers signés 64 bits. – tzot

+0

Alors peut-être que les types 'int' et 'var' devraient être préfixés avec un modificateur 'unsigned', bien sûr si C# le permet. – tzot

+0

Merci d'avoir attrapé ça. –

9

Il y a un an, je l'ai à mettre en œuvre MD4 pour ma thèse de premier cycle. Ici, c'est ma mise en œuvre du décalage bit circulaire utilisant un UInt32.

private UInt32 RotateLeft(UInt32 x, Byte n) 
{ 
     return UInt32((x << n) | (x >> (32 - n))); 
} 
3

Tout comme référence sur la façon de le faire, ces deux fonctions fonctionnent parfaitement pour faire tourner les bits de 1/2word:

static public uint ShiftRight(uint z_value, int z_shift) 
{ 
    return ((z_value >> z_shift) | (z_value << (16 - z_shift))) & 0x0000FFFF; 
} 

static public uint ShiftLeft(uint z_value, int z_shift) 
{ 
    return ((z_value << z_shift) | (z_value >> (16 - z_shift))) & 0x0000FFFF; 
} 

Il serait facile de le prolonger pour une taille donnée.

0

L'application la plus célèbre est la solution au problème de Josephus (comme discuté dans Concrete Mathematics, voir http://oeis.org/A006257). C'est fondamentalement un puzzle sans applications évidentes. Dans this video, j'ai démontré des liens entre le problème de Josephus du second ordre et des arbres équilibrés complets. Ce n'est toujours pas une application, mais bouger légèrement dans la bonne direction.

Questions connexes