21

Sono molto confuso sull'operazione di spostamento a destra sul numero negativo, ecco il codice.Java: spostamento a destra sul numero negativo

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

e il risultato è:

11111111111111111111111111110001 
11111111111111111111111111111111 

Perché destra spostando un numero negativo per 31 non 1 (il bit di segno)?

+2

BTW, è possibile utilizzare '>>> -1' e funzionerà con i tipi' int' e 'long'. –

risposta

30

Perché in Java non ci sono tipi di dati non firmati, ci sono due tipi di turni di destra: arithmetic shift>> e logical shift>>>. http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

Spostamento aritmetico >> manterrà il bit di segno.
Arithmetic shift

spostamento senza segno >>> non impedirà il bit di segno (riempiendo 0 s).
Logical shift

(immagini di Wikipedia)


proposito, sia aritmetica spostamento a sinistra e logico spostamento a sinistra hanno lo stesso risultato, per cui v'è un solo spostamento a sinistra <<.

+0

Cosa succede se lo fai ** '10101010 << 1' **? ** '11010100' ** o **' 01010100' **? –

+0

@ AurélienOoms È uno spostamento a sinistra, che riempie '0's sulla destra. –

+1

Voglio dire, è * "A proposito, sia lo spostamento aritmetico che lo spostamento logico hanno lo stesso risultato, quindi c'è solo uno spostamento a sinistra <<' * veramente vero? –

12

Operatore >> chiamato Passaggio a destra firmato, spostare tutti i bit a destra un numero specificato di volte. Importante è >> riempie il bit di segno più a sinistra (Most Significant Bit MSB) al bit più a sinistra il dopo spostamento. Questa è chiamata estensione di segno e serve a conservare il segno di numeri negativi quando li si sposta a destra.

Qui di seguito è la mia rappresentazione schematica, con un esempio per mostrare come funziona (per un byte):

Esempio:

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

Cinque in forma complemento a due è la rappresentazione 1111 1011

Memoria:

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 

E di seguito è, come funziona >>? Quando si esegue -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 

Avviso: la sinistra la maggior parte dei tre bit sono uno perché su è conservato ogni turno di bit di segno e ogni bit è giusto anche. Ho scritto Il segno è propagato perché tutti questi tre bit sono dovuti al segno (ma non ai dati).

Anche a causa di tre spostamento a destra a destra, la maggior parte dei tre bit sono perdite.

I bit tra due frecce a destra sono esposti dai bit precedenti in -5.

Penso che sarebbe bello scrivere un esempio anche per un numero positivo. esempio successivo è 5 >> 3 e cinque è un byte è 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 

vedere di nuovo mi scrive Il segno viene propagato, quindi più a sinistra tre zeri sono dovuti a firmare bit.

Quindi, questo è l'operatore >>fare il passaggio a destra do, conserva il segno dell'operando di sinistra.

[la risposta]
Nel codice, si sposta a destra per -1531 volte utilizzando >> operatore in modo che il diritto più 31 bit sono sciolto e risultati è tutti i bit 1 che è in realtà -1 in grandezza.

Si nota che in questo modo -1 >> n equivale a non una dichiarazione.
Credo che se uno fare i = -1 >> n dovrebbe essere ottimizzato per i = -1 da compilatori Java, ma questo è altro discorso

Avanti, sarebbe interessante sapere in Java un altro operatore di spostamento a destra è disponibile >>> chiamato Unsigned Right Shift. E funziona logicamente e riempie zero da sinistra per ogni operazione di cambio. Quindi, ad ogni spostamento a destra, si ottiene sempre un bit zero nella posizione più a sinistra se si utilizza l'operatore di spostamento a destra senza segno >>> per i numeri negativi e positivi.

Esempio:

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

E sotto è il mio schema che dimostra come l'espressione -5 >>> 3 funziona?

     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 

E si può notare: questa volta non scrivo che i bit del segno propagate, ma in realtà >>> zeri inserimento dell'operatore. Quindi >>> non conserva il segno, invece esegue il giusto spostamento logico.

A mia conoscenza, lo spostamento a destra senza segno è utile in VDU (programmazione grafica), sebbene non l'abbia usato ma lo legga in qualche posto dove in passato.

Vorrei suggerire di leggere questo: Difference between >>> and >>: >> è spostamento aritmetico a destra, >>> è spostamento logico a destra.

Edit:

Alcuni interessante di spostamento a destra senza segno Operatore >>> operatore.

  • L'operatore spostamento a destra senza segno >>> produce un valore puro che è l'operando fianco destro spostata dallo zero 0 estensione per il numero di bit specificato dal suo operando destro.

  • Come >> e <<, operatore >>> anche operatore non genera un'eccezione.

  • Il tipo di ciascun operando dell'operatore di spostamento a destra senza segno deve essere un tipo di dati intero oppure si verifica un errore di compilazione.

  • L'operatore >>> può eseguire conversioni di tipi sui suoi operandi; a differenza degli operatori binari aritmetici, ogni operando viene convertito in modo indipendente. Se il tipo di un operando è byte, short o char, quell'operando viene convertito in un int prima che il valore dell'operatore sia calcolato.

  • Il tipo del valore prodotto dall'operatore di spostamento a destra senza segno è il tipo del suo operando di sinistra.LEFT_OPERAND >>> RHIGT_OPERAND

  • Se il tipo convertito dell'operando di sinistra è int, solo i cinque bit meno significativi del valore della operando destro servono come shift. (che è 2 = 32 bit = numero di bit in int)
    Quindi, la distanza di spostamento è compreso tra 0 e 31.

    Qui, il valore prodotto dal r >>> s è lo stesso:

    s==0 ? r : (r >> s) & ~(-1<<(32-s)) 
    
  • Se il tipo dell'operando di sinistra è lungo, allora solo i sei bit meno significativi del valore dell'operando destra sono usati per lo shift. (che è 2 = 64 bit = numero di bit nel lungo)

    Qui, il valore prodotto dal r >>> s è la stessa come la seguente:

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

A Riferimento Interessante: [Chapter 4] 4.7 Shift Operators

+0

In realtà non "mette 1", ma conserva solo il bit del segno, qualunque esso sia. – EJP

+1

Una risposta più semplice è più corretta e più utile. L'operatore non guarda se l'operando è negativo o positivo e quindi fa due cose diverse. – EJP

+0

Si prega di attenersi al punto e tenere fuori le personalità. La tua spiegazione è due volte più complessa di quanto sia necessario e, a giudicare dal tuo commento alla risposta di @AlvinWong, non riesci ancora a capire perché. – EJP

3

Poiché >> è definito come spostamento aritmetico destra, che conserva il segno. Per ottenere l'effetto che ci si aspetta, utilizzare uno spostamento logico a destra, l'operatore >>>.

+0

Ok quello che stavo cercando di dire che hai scritto in una parola * ' conserva il segno' * che è buono. –