Duda con desplazamiento de bits a la derecha de un número entero

¡Qué tal! hace tiempo que no participo en la página, pero pues espero puedan ayudarme. Sucede que estudiando el comportamiento del desplazamiento de bits, me causo confusión el siguiente código:

/****************** Exercise 11 *****************
 * Start with a number that has a binary one in  
 * the most significant position. (Hint: Use a  
 * hexadecimal constant.) Use the signed  
 * right-shift operator to right shift your
 * number through all its binary positions.  
 * Display each result using Integer.toBinaryString().
 ************************************************/

package operators;
import static net.mindview.util.Print.*;
public class E11_SignedRightShift {
  public static void main(String[] args) {
    int i = 0x80000000;
    print(Integer.toBinaryString(i));
    print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
    i >>= 1;  print(Integer.toBinaryString(i));
  }
} /* salida:
10000000000000000000000000000000
11000000000000000000000000000000
11100000000000000000000000000000
11110000000000000000000000000000
11111000000000000000000000000000
11111100000000000000000000000000
11111110000000000000000000000000
11111111000000000000000000000000
11111111100000000000000000000000
11111111110000000000000000000000
11111111111000000000000000000000
11111111111100000000000000000000
11111111111110000000000000000000
11111111111111000000000000000000
11111111111111100000000000000000
11111111111111110000000000000000
11111111111111111000000000000000
11111111111111111100000000000000
11111111111111111110000000000000
11111111111111111111000000000000
11111111111111111111100000000000
11111111111111111111110000000000
11111111111111111111111000000000
11111111111111111111111100000000
11111111111111111111111110000000
11111111111111111111111111000000
11111111111111111111111111100000
11111111111111111111111111110000
11111111111111111111111111111000
11111111111111111111111111111100
11111111111111111111111111111110
11111111111111111111111111111111
*/

 

En la teoría según voy entendiendo, el desplazamiento a la derecha con signo con número enteros, si éste es positivo va insertando 0's o 1's, si el número es negativo. En este ejercicio resuelto el número es: 2147483648 pero veo que va insertando 1's por cada desplazamiento, cuando debería insertar 0's, esta es mi confusión, ¿por qué pasa esto?
Ahora probe cambiando el número entero, solo le quite un cero a la constante hexadecimal y que equivale a 134217728 un número más pequeño:

class DesplazamientoDerechaConSigno {
        public static void main(String[] args) {
                int valor = 0x8000000;
                System.out.println(Integer.toBinaryString(valor));                     
                for(int i = 1; i <= 32; i++)                   
                        System.out.println(Integer.toBinaryString(valor >>= 1));               
        }
}
/* salida:
1000000000000000000000000000
100000000000000000000000000
10000000000000000000000000
1000000000000000000000000
100000000000000000000000
10000000000000000000000
1000000000000000000000
100000000000000000000
10000000000000000000
1000000000000000000
100000000000000000
10000000000000000
1000000000000000
100000000000000
10000000000000
1000000000000
100000000000
10000000000
1000000000
100000000
10000000
1000000
100000
10000
1000
100
10
1
0
0
0
0
0
*/

<blockcode>
Aqui si puedo comprobar que se cumple lo que dice la teoría, ojala me pueda explicar alguien, como funciona esto, por favor.

Nota: Según leí por ahí en internet que el desplazamiento es ciclico, osea que los bits que van saliendo vuelven a entrar por el otro lado, en este caso por el lado izquierdo, pero pues se puede comprobar que no es cierto, ¿verdad? si no que se pierden.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

no es cíclico

No es cíclico pero la bronca es que estás manejando enteros con signo y el 0x80000000 es un número especial, por así decirlo. Los enteros en Java son de 32 bits y van de -2147483648 a 2147483647 (porque el bit 32 es el signo, y los otros 31 son para el valor). Pero por la cosa de que se manejan con complemento a 2, existe un número especial, que puede ser representado como -0 o como 2147483648 y es justamente el que estás usando, que es todo ceros pero con el bit más significativo encendido, para indicar que es un número negativo. En este único caso, el shift a la derecha va metiendo unos en vez de ceros, cuando haces el shift un bit a la vez. Si haces por ejemplo 0x80000000>>31 obtienes 1.

ADD: Si ves los enteros que se imprimen, en vez de solamente los bits, verás que lo que está pasando es que se pasan puros unos para que el comportamiento sea similar a cuando haces el shift con números positivos. Por ejemplo los últimos números si lo haces a partir del positivo más grande, van a ser 8, 4, 2, 1... con tu ejemplo los últimos números son -8, -4, -2, -1.

Imagen de martinillo

ya más claro

Gracias por responder @ezamudio. Estuve haciendo mis pruebas de acuerdo según lo que entendí y aqui esta el programita:

class E11_DesplazamientoDerechaConSigno {
        public static void main(String[] args) {
                // Haciedo desplazamiento a partir del entero positivo más grande: 2147483647 (1)
                int enteroMaximo = 0x7FFFFFFF;         
                System.out.println(Integer.toBinaryString(enteroMaximo) + " = " + enteroMaximo);
                for(int i = 1; i <= 31; i++)                   
                        System.out.println(Integer.toBinaryString(enteroMaximo >>= 1) + " = " + enteroMaximo);         
               
                // Haciedo desplazamiento a partir de -0 o 2147483648 (2)
                int ceroNegativo = 0x80000000;
                System.out.println(Integer.toBinaryString(ceroNegativo) + " = " + ceroNegativo);               
                for(int i = 1; i <= 31; i++)
                        System.out.println(Integer.toBinaryString(ceroNegativo >>= 1) + " = " + ceroNegativo);         
               
                // desplazamiento de un solo golpe (3)
                enteroMaximo = 0x80000000;
                System.out.println("Desplazamiento en una sola instruccion:");         
                System.out.println(Integer.toBinaryString(enteroMaximo >>=31) + " = " + enteroMaximo);         
        }
}/* salida:
1111111111111111111111111111111 = 2147483647
111111111111111111111111111111 = 1073741823
11111111111111111111111111111 = 536870911
1111111111111111111111111111 = 268435455
111111111111111111111111111 = 134217727
11111111111111111111111111 = 67108863
1111111111111111111111111 = 33554431
111111111111111111111111 = 16777215
11111111111111111111111 = 8388607
1111111111111111111111 = 4194303
111111111111111111111 = 2097151
11111111111111111111 = 1048575
1111111111111111111 = 524287
111111111111111111 = 262143
11111111111111111 = 131071
1111111111111111 = 65535
111111111111111 = 32767
11111111111111 = 16383
1111111111111 = 8191
111111111111 = 4095
11111111111 = 2047
1111111111 = 1023
111111111 = 511
11111111 = 255
1111111 = 127
111111 = 63
11111 = 31
1111 = 15
111 = 7
11 = 3
1 = 1
0 = 0
10000000000000000000000000000000 = -2147483648
11000000000000000000000000000000 = -1073741824
11100000000000000000000000000000 = -536870912
11110000000000000000000000000000 = -268435456
11111000000000000000000000000000 = -134217728
11111100000000000000000000000000 = -67108864
11111110000000000000000000000000 = -33554432
11111111000000000000000000000000 = -16777216
11111111100000000000000000000000 = -8388608
11111111110000000000000000000000 = -4194304
11111111111000000000000000000000 = -2097152
11111111111100000000000000000000 = -1048576
11111111111110000000000000000000 = -524288
11111111111111000000000000000000 = -262144
11111111111111100000000000000000 = -131072
11111111111111110000000000000000 = -65536
11111111111111111000000000000000 = -32768
11111111111111111100000000000000 = -16384
11111111111111111110000000000000 = -8192
11111111111111111111000000000000 = -4096
11111111111111111111100000000000 = -2048
11111111111111111111110000000000 = -1024
11111111111111111111111000000000 = -512
11111111111111111111111100000000 = -256
11111111111111111111111110000000 = -128
11111111111111111111111111000000 = -64
11111111111111111111111111100000 = -32
11111111111111111111111111110000 = -16
11111111111111111111111111111000 = -8
11111111111111111111111111111100 = -4
11111111111111111111111111111110 = -2
11111111111111111111111111111111 = -1
Desplazamiento en una sola instruccion:
11111111111111111111111111111111 = -1

A partir del entero positivo (1) más grande se va decrementanto el número hasta llegar 7, 3, 1... debo entender que mencionastes (8, 4, 2) a modo de ejemplo para ver la relación con los numeros negativos.

Y pues en (2) no imprime -0 (bueno supuse que debia imprimir eso) sale el numero más grande negativo, y pues si efectivamente va terminando en -8, -4, -2. No sé si entedí bien con respecto a -0.

en (3) probe lo que comentaste pero pues no salio 1 sino -1.

Gracias por la ayuda.

Imagen de ezamudio

numeros negativos en bits

Suponte que tienes un tipo de dato que es un entero sin signo, de 4 bits. Va del 0 al 15, correcto? Pero si lo quieres manejar con signo, entonces un bit es el signo, y te quedan 3 bits, con lo que puedes contar del 0 al 7 solamente, y en negativo va hasta el -7... ah pero resulta que 0000 es 0, 0111 es 7, y por otra parte tienes 1111 que es -1, y hay otra opcion que es 1000 que es... -0, pero -0 no tiene ningun sentido, de modo que se lo asignas a -8.

Ya pensando mejor en lo que te esta pasando, me parece que tu numero 0x80000000 debe ser -0 o lo que es lo mismo, el numero mas negativo que puede haber. Pero en las pruebas que yo hice no le puse cast y seguramente el compilador lo consideraba como un long o algo asi.

Imagen de martinillo

entonces es algo asi como por definición

Gracias por la ejemplificación, sinceramente no había entendido eso de la representación binaria en este caso de numeros enteros positivos y negativos pero con tu ayuda y otros tutos ya comprendo mejor. Sería entonces por definición que -0 se representaría tomando en cuenta como dices -0 --> -8 (1000) en el int seria -0 --> -2147483648 (10000000000000000000000000000000). Esto por qué sobra un número binario al utilizar un bit para el signo del número, ¿es correcto esto?.

Gracias!!

Imagen de martinillo

investigando más

no había entendido del todo lo que me dijistes, pero pues ahora mejor. Cuando dices que -0 no tiene sentido, tienes razón de hecho ese es el problema que se presenta con signo magnitud y complemento a 1 (despues de investigar más), y es que simplemente con la representación en complemento a 2 no existe la representación de -0, de acuerdo a tu ejemplo con 4 bits 1000 seria -8 (al fin de cuentas veo que lo intentastes explicar de otra manera). Asi que el programa del ejercicio que me causo confusión en un principio era en realidad el número negativo más grande cuando yo estaba equivocado al pensar que era un positivo o el 0 no recuerdo y debia insertar 0´s e lugar de 1's.

10000000000000000000000000000000 = -2147483648

Te agradezo haberme ayudado!!