web-dev-qa-db-fra.com

Arithmétique bit-shift sur un entier signé

J'essaie de comprendre comment les opérateurs de décalage de bits arithmétiques fonctionnent exactement en C et comment cela affectera les entiers 32 bits signés.

Pour simplifier les choses, supposons que nous travaillons dans un octet (8 bits):

x = 1101.0101
MSB[ 1101.0101 ]LSB

En lisant d’autres articles sur Stack Overflow et certains sites Web, j’ai trouvé que: << passera vers MSB (à gauche, dans mon cas) et remplira les bits "vides" de LSB avec des 0.

Et >> passera vers LSB (à droite, dans mon cas) et remplira les bits "vides" avec le bit MS

Ainsi, x = x << 7 entraînera le déplacement du LSB vers le MSB et le réglage de tous les éléments à 0.

1000.0000

Maintenant, supposons que je >> 7, dernier résultat. Cela donnerait [0000.0010]? Ai-je raison?

Ai-je raison à propos de mes hypothèses sur les opérateurs de postes?

Je viens de tester sur ma machine, **

int x = 1;   //000000000......01

x = x << 31; //100000000......00

x = x >> 31; //111111111......11 (Everything is filled with 1s !!!!!) 

Pourquoi?

48
newprint

Le décalage à droite d'un nombre signé négatif a un comportement défini par l'implémentation.

Si vos 8 bits sont censés représenter une valeur signée de 8 bits (comme vous parlez d'un "entier signé de 32 bits" avant de passer aux exemples 8 bits), vous avez un nombre négatif. Le déplacer vers la droite peut remplir les bits "vides" avec le MSB d'origine (c'est-à-dire effectuer une extension de signe) ou en zéros, en fonction de la plate-forme et/ou du compilateur.

(Le comportement défini par l'implémentation signifie que le compilateur fera quelque chose de sensé, mais d'une manière dépendant de la plate-forme; la documentation du compilateur est censée vous dire quoi.)


Un décalage à gauche, si le nombre au départ est négatif ou si l'opération de décalage décalait de 1 vers le bit de signe ou au-delà, a un comportement indéfini (comme le font la plupart des opérations sur les valeurs signées entraînant un dépassement de capacité).

(Un comportement non défini signifie que tout peut arriver.)


Les mêmes opérations sur les valeurs unsigned sont bien définies dans les deux cas: les bits "vides" seront remplis avec 0.

53
Matthew Slattery

Les opérations de décalage binaire ne sont pas définies pour les valeurs négatives

pour '<<'

6.5.7/4 [...] Si E1 a un type signé et une valeur non négative, et E1 × 2E2 est représentable dans le type de résultat, alors c'est la valeur résultante; sinon, le comportement n'est pas défini.

et pour '>>'

6.5.7/5 [...] Si E1 a un type signé et une valeur négative, la valeur résultante est définie par la mise en oeuvre.

C'est une perte de temps d'étudier le comportement de ces opérations sur les nombres signés sur une implémentation spécifique, car vous n'avez aucune garantie que cela fonctionnera de la même manière sur toute autre implémentation (une implémentation consiste, par exemple, à compiler sur votre ordinateur avec votre paramètres de ligne de commande spécifiques).

Cela pourrait même ne pas fonctionner pour une version plus ancienne ou plus récente du même compilateur. Le compilateur peut même définir ces bits comme aléatoires ou non définis. Cela signifierait que la même séquence de code pourrait produire des résultats totalement différents lorsqu’elle est utilisée dans vos sources ou même selon des éléments comme l’optimisation de l’Assemblée ou toute autre utilisation du registre. Si elle est encapsulée dans une fonction, elle risque même de ne pas produire le même résultat dans ces bits lors de deux appels consécutifs avec les mêmes arguments.

En considérant uniquement les valeurs non négatives , l'effet du décalage à gauche de 1 (expression << 1) est identique à celui de la multiplication de l'expression par 2 (l'expression fournie * 2 ne déborde pas) et l'effet du décalage à droite de 1 (expression >> 1) équivaut à diviser par 2.

34
pmg

Comme d'autres l'ont dit, le décalage de valeur négative est défini par la mise en œuvre.

La plupart des implémentations considèrent le changement de droite signé comme du plancher (x/2N) en remplissant les bits décalés en utilisant le bit de signe. C'est très pratique dans la pratique car cette opération est très courante. D'un autre côté, si vous décalez le nombre entier non signé de droite, les bits décalés seront mis à zéro.

En ce qui concerne la machine, la plupart des implémentations ont deux types d’instructions:

  1. Un décalage "arithmétique" à droite (souvent avec ASR ou SRA mnémonique) qui fonctionne comme je l'ai expliqué.

  2. Un décalage 'logique' à droite (souvent avec mnémonique LSR ou SRL ou SR) qui fonctionne comme prévu.

La plupart des compilateurs utilisent d'abord les types signés et les non signés. Juste pour plus de commodité.

5
Vovanium

Dans le compilateur 32 bits 

x = x >> 31; 

ici x est l'entier signé, donc le 32ème bit est le bit de signe.

la valeur finale x est 100000 ... 000 . et le 32ème bit indique une valeur -ive.

ici x valeur implémenter au compliment de 1.

alors x final est -32768

0
user3060837