2010-11-29 5 views
16

J'ai le code suivant:Pourquoi -1 >> 1 est -1? Et 1 >> 1 est 0!

std::cout << (-10 >> 1) << std::endl; 
std::cout << (-9 >> 1) << std::endl; 
std::cout << (-8 >> 1) << std::endl; 
std::cout << (-7 >> 1) << std::endl; 
std::cout << (-6 >> 1) << std::endl; 
std::cout << (-5 >> 1) << std::endl; 
std::cout << (-4 >> 1) << std::endl; 
std::cout << (-3 >> 1) << std::endl; 
std::cout << (-2 >> 1) << std::endl; 
std::cout << (-1 >> 1) << std::endl; 

Le résultat est:

-5 
-5 
-4 
-4 
-3 
-3 
-2 
-2 
-1 
-1 

Mais pourquoi?

-1 est 1111 1111 (pour 1 octet), -1 >> 1 doit être: 1011 1111 et ce n'est pas -1 ou 0! (signe-bit n'est pas décalé, je sais)

Quelqu'un peut-il m'expliquer comment cela fonctionne?

+0

chaque bit est décalé, et il n'y a pas de bit de signe explicite dans le complément à deux. – jalf

Répondre

24

standard 5,8/3 (opérateurs de décalage):

La valeur de E1 E2 est E1 >> les positions de bits E2 droite décalée. Si E1 a un type non signé ou si E1 a un type signé et une valeur non négative, la valeur du résultat est la partie intégrante du quotient de E1 divisée par la quantité 2 élevé à la puissance E2. Si E1 a un type signé et une valeur négative, la valeur résultante est définie par l'implémentation.

Donc à la question «pourquoi?», La réponse standard est: pourquoi pas.

+8

La réponse standard est: "RTFM pour votre compilateur" –

17

Le décalage vers la droite d'un nombre négatif est défini par l'implémentation.

Les implémentations qui se déplacent dans un bit étendu vers le bit le plus à gauche fonctionnent comme indiqué.

Quant à savoir pourquoi il est fait de cette façon, il est parce que bon décalage peut être utilisé pour diviser par une puissance de 2 avec aller-vers-négatif infini (par exemple comme floor()) le comportement d'arrondi:

(-8 >> 2) == -2 
(-9 >> 2) == -3 
(-10 >> 2) == -3 
(-11 >> 2) == -3 
(-12 >> 2) == -3 

See this SO question.

3

-1 >> 1 doit être: 1011 1111

Si cela était vrai, -10 >> 1 serait 10.111.011 == -69 en complément de deux. Pas un résultat très utile!

Bien que le comportement de langage soit indéfini (le résultat, utile ou non, ne peut être invoqué), le comportement commun (et présenté dans ce cas) consiste à effectuer une extension de signe.

Il est pas vrai que le « signe bits n'est pas déplacé », il est déplacé et est rempli le bit laissé vacant avec une valeur égale au bit de signe. Ce comportement préserve à la fois le signe et fournit l'opération de division par deux «attendue» que vous avez observée pour toutes les valeurs sauf -1. Pour les valeurs négatives, -1 est la «valeur terminale» d'un décalage vers la droite, puisque zéro est pour les nombres positifs. C'est-à-dire que le décalage vers la droite d'un nombre négatif tend vers -1 et qu'un nombre positif tend vers zéro.

3

En général, les décalages vers la droite sont définis comme étant soit «arithmétiques» soit «logiques». La différence est que, avec un décalage vers la droite logique, le bit le plus à gauche est toujours mis à zéro. Avec un décalage arithmétique à droite, le bit le plus à gauche est une copie de la valeur précédente. Par exemple, supposons que la valeur soit de 8 bits pour faciliter le suivi. Puis:

logique:

0111 1111 >> 1 = 0011 1111 
1111 1111 >> 1 = 0111 1111 
1111 1110 >> 1 = 0111 1111 

Arithmétique:

0111 1111 >> 1 = 0011 1111 
1111 1111 >> 1 = 1111 1111 
1111 1110 >> 1 = 1111 1111 

Un déplacement vers la droite de calcul est équivalent à une division par deux et arrondi vers l'infini négatif.

En C++, que l'opérateur de décalage vers la droite soit logique ou arithmétique est spécifique à l'implémentation. c'est-à-dire que chaque auteur de compilateur peut décider pour lui-même, probablement en fonction de ce qu'il est plus facile de faire en donnant l'architecture de l'ordinateur sur lequel il travaille.

Votre déclaration indiquant que le bit de signe n'est pas décalé est incorrecte. Le bit de signe est décalé comme tous les autres bits. La seule question est ce qui le remplace.

Java a deux opérateurs de décalage vers la droite différents: >> est l'arithmétique et >>> est logique.

+0

@laalto: Oh, merci pour l'édition. C'était lisible sur mon écran quand je l'ai tapé. :-( – Jay

Questions connexes