web-dev-qa-db-fra.com

Java: décalage à droite sur un nombre négatif

Je suis très confus sur l'opération de décalage à droite sur un nombre négatif, voici le code.

int n = -15;
System.out.println(Integer.toBinaryString(n));
int mask = n >> 31;
System.out.println(Integer.toBinaryString(mask));

Et le résultat est:

11111111111111111111111111110001
11111111111111111111111111111111

Pourquoi décaler à droite un nombre négatif de 31 et non 1 (le bit de signe)?

26
Cacheing

Parce que dans Java il n'y a pas de types de données non signés, il existe deux types de décalages à droite: décalage arithmétique>> et décalage logique>>>. http://docs.Oracle.com/javase/tutorial/Java/nutsandbolts/op3.html

Décalage arithmétique >> conservera le bit de signe.
Arithmetic shift

Maj non signé >>> ne conservera pas le bit de signe (remplissant ainsi 0s).
Logical shift

(images de Wikipedia)


Soit dit en passant, le décalage gauche arithmétique et le décalage gauche logique ont le même résultat, il n'y a donc qu'un seul décalage gauche <<.

36
Alvin Wong

Opérateur >> appelé Décalage à droite signé , décale tous les bits vers la droite un nombre spécifié de fois. L'important est >> remplit le bit de signe le plus à gauche (Bit le plus significatif MSB) jusqu'au bit le plus à gauche après le décalage. Cela s'appelle extension de signe et sert à conserver le signe de nombres négatifs lorsque vous les déplacez vers la droite.

Ci-dessous est ma représentation schématique avec un exemple pour montrer comment cela fonctionne (pour un octet):

Exemple:

i = -5 >> 3;  shift bits right three time 

La forme du complément de cinq sur deux est 1111 1011

Représentation de la mémoire:

 MSB
+----+----+----+---+---+---+---+---+
|  1 |  1 | 1  | 1 | 1 | 0 | 1 | 1 |   
+----+----+----+---+---+---+---+---+
   7    6   5    4   3   2   1   0  
  ^  This seventh, the left most bit is SIGN bit  

Et ci-dessous, comment >> travaux? Lorsque vous faites -5 >> 3

                        this 3 bits are shifted 
                         out and loss
 MSB                   (___________)      
+----+----+----+---+---+---+---+---+
|  1 |  1 | 1  | 1 | 1 | 0 | 1 | 1 |   
+----+----+----+---+---+---+---+---+
  | \                 \  
  |  ------------|     ----------|
  |              |               |
  ▼              ▼               ▼
+----+----+----+---+---+---+---+---+
|  1 |  1 | 1  | 1 | 1 | 1 | 1 | 1 |
+----+----+----+---+---+---+---+---+
(______________)
 The sign is        
 propagated

Remarque: les trois bits les plus à gauche sont un car chaque bit de signe de décalage est conservé et chaque bit est également à droite. J'ai écrit Le signe se propage parce que tous ces trois bits sont à cause du signe (mais pas des données).

De plus, en raison de trois décalages à droite, la plupart des trois bits sont des pertes.

Les bits entre les deux flèches droites sont exposés à partir des bits précédents dans -5.

Je pense que ce serait bien si j'écrivais un exemple pour un nombre positif aussi. L'exemple suivant est 5 >> 3 et cinq est un octet est 0000 0101

                        this 3 bits are shifted 
                         out and loss
 MSB                   (___________)      
+----+----+----+---+---+---+---+---+
|  0 |  0 | 0  | 0 | 0 | 1 | 0 | 1 |   
+----+----+----+---+---+---+---+---+
  | \                 \  
  |  ------------|     ----------|
  |              |               |
  ▼              ▼               ▼
+----+----+----+---+---+---+---+---+
|  0 |  0 | 0  | 0 | 0 | 0 | 0 | 0 |
+----+----+----+---+---+---+---+---+
(______________)
 The sign is        
 propagated

Voir à nouveau j'écris Le signe se propage, donc les trois zéros les plus à gauche sont dus au bit de signe.

Voilà donc ce que l'opérateur >> Décalage à droite signé do, préserve le signe de l'opérande gauche.

[votre réponse]
Dans votre code, vous déplacez -15 à droite pour 31 fois en utilisant >> opérateur donc votre droite 31 les bits sont desserrés et les résultats sont tous les bits 1 c'est en fait -1 en magnitude.

Remarquez-vous que de cette manière -1 >> n est équivalent à pas une déclaration.
Je crois que si l'on fait i = -1 >> n il doit être optimisé pour i = -1 par Java, mais c'est différent

Ensuite, il serait intéressant de savoir dans Java un autre opérateur de décalage à droite est disponible >>> appelé Décalage à droite non signé . Et cela fonctionne logiquement et remplit zéro à partir de la gauche pour chaque opération de décalage. Ainsi, à chaque décalage à droite, vous obtenez toujours un bit zéro sur la position la plus à gauche si vous utilisez un décalage à droite non signé >>> opérateur pour les nombres négatifs et positifs.

Exemple:

i = -5 >>> 3;  Unsigned shift bits right three time 

Et ci-dessous est mon diagramme qui montre comment l'expression -5 >>> 3 travaux?

                        this 3 bits are shifted 
                         out and loss
 MSB                   (___________)      
+----+----+----+---+---+---+---+---+
|  1 |  1 | 1  | 1 | 1 | 0 | 1 | 1 |   
+----+----+----+---+---+---+---+---+
  | \                 \  
  |  ------------|     ----------|
  |              |               |
  ▼              ▼               ▼
+----+----+----+---+---+---+---+---+
|  0 |  0 | 0  | 1 | 1 | 1 | 1 | 1 |
+----+----+----+---+---+---+---+---+
(______________)
  These zeros
  are inserted  

Et vous pouvez remarquer: cette fois, je n'écris pas ce bit de signe propagé mais en fait >>> l'opérateur insère des zéros. Par conséquent >>> ne préserve pas le signe.

À ma connaissance, le décalage à droite non signé est utile dans VDU (programmation graphique), bien que je ne l'ait pas utilisé mais que je l'ai lu quelque part dans le passé.

Je vous suggère de lire ceci: Différence entre >>> et >> : >> est un décalage arithmétique vers la droite, >>> est un décalage logique vers la droite.

Modifier :

Quelques informations intéressantes sur l'opérateur de décalage à droite non signé >>> opérateur.

  • L'opérateur de décalage vers la droite non signé >>> produit une valeur pure qui est son opérande gauche décalé vers la droite avec zéro 0 extension par le nombre de bits spécifié par son opérande droit.

  • Comme >> et <<, opérateur >>> aussi l'opérateur ne lève jamais d'exception.

  • Le type de chaque opérande de l'opérateur de décalage vers la droite non signé doit être un type de données entier, sinon une erreur de compilation se produit.

  • Le >>> L'opérateur peut effectuer des conversions de type sur ses opérandes; contrairement aux opérateurs binaires arithmétiques, chaque opérande est converti indépendamment. Si le type d'un opérande est octet, court ou caractère, cet opérande est converti en entier avant que la valeur de l'opérateur ne soit calculée.

  • Le type de la valeur produite par l'opérateur de décalage à droite non signé est le type de son opérande gauche. LEFT_OPERAND >>> RHIGT_OPERAND

  • Si le type converti de l'opérande gauche est entier, seuls les cinq bits de poids faible de la valeur de l'opérande droit = sont utilisés comme distance de décalage. ( soit 25 = 32 bits = nombre de bits en entier)
    Ainsi, la distance de décalage est comprise entre 0 et 31.

    Ici, la valeur produite par r >>> s est le même que:

    s==0 ? r : (r >> s) & ~(-1<<(32-s))
    
  • Si le type de l'opérande gauche est long, seuls les six bits de poids faible de la valeur de l'opérande droit sont utilisés comme distance de décalage. ( soit 25 = 64 bits = nombre de bits en long)

    Ici, la valeur produite par r >>> s est identique à ce qui suit:

    s==0 ? r : (r >> s) & ~(-1<<(64-s))
    

Une référence intéressante: [Chapter 4] 4.7 Shift Operators

14
Grijesh Chauhan

Parce que >> est défini comme un décalage arithmétique vers la droite, qui préserve le signe. Pour obtenir l'effet attendu, utilisez un décalage logique à droite, l'opérateur >>>.

3
user207421