¿Cómo se representan los enteros internamente a nivel de bits en Java?

83

Estoy tratando de entender cómo Java almacena el entero internamente. Sé que todos los enteros primitivos de Java están firmados (¿excepto los cortos?). Eso significa un bit menos disponible en un byte para el número.

Mi pregunta es, ¿todos los números enteros (positivos y negativos) se almacenan como complemento a dos o solo son números negativos en complemento a dos?

Veo que las especificaciones dicen x bit two's complement number. Pero a menudo me confundo.

Por ejemplo:

  int x = 15; // Stored as binary as is?  00000000 00000000 00000000 00001111?
  int y = -22; // Stored as two complemented value? 11111111 11111111 11111111 11101010

Editar

Para ser claro, x = 15

   In binary as is: `00000000 00000000 00000000 00001111'
  Two's complement: `11111111 11111111 11111111 11110001`

Entonces, si su respuesta es que los allnúmeros se almacenan como complemento a dos, entonces:

  int x = 15; // 11111111 11111111 11111111 11110001
  int y = -22 // 11111111 11111111 11111111 11101010

La confusión aquí nuevamente es que el letrero dice, ambos son números negativos. ¿Es posible que lo esté leyendo o entendiendo mal?

Editar No estoy seguro de que mi pregunta sea confusa. Obligado a aislar la pregunta:

Mi pregunta precisamente: ¿se almacenan los números positivos binary as ismientras que los números negativos se almacenan como two's complement?

Algunos dijeron que todos se almacenan en complemento a dos y una respuesta dice que solo los números negativos se almacenan como complemento a dos.

Kevin Rave
fuente
El complemento a dos significa necesariamente que los números positivos están representados por los valores de bits reales de ese número ... al menos según tengo entendido. EDITAR: Además, el complemento de dos significa un bit menos en el número total de bytes en la primitiva, no un bit menos POR byte.
LJ2
su suposición es correcta: los números positivos y negativos son el complemento de dos, y su xy yson correctos.
jlordo
Una nota al margen: es una especie de WTF, que Java, un lenguaje de la era de Internet, no tiene un tipo de datos para representar, por ejemplo. Número de puerto TCP / IP (valor sin firmar de 16 bits) con precisión, lo que a veces conduce a un código realmente desagradable.
Hyde
comprobar el artículo de wiki en.wikipedia.org/wiki/... número complementario del 2 que ha dado para 15 está mal
Dungeon Hunter
@hyde 'Código realmente feo' como?
Marqués de Lorne

Respuestas:

102

Comencemos resumiendo los tipos de datos primitivos de Java:

byte : el tipo de datos Byte es un entero de complemento a dos con signo de 8 bits .

Corto : el tipo de datos corto es un entero de complemento a dos con signo de 16 bits .

int: el tipo de datos Int es un entero de complemento a dos con signo de 32 bits .

long: el tipo de datos Long es un entero de complemento a dos con signo de 64 bits .

float: el tipo de datos Float es un punto flotante IEEE 754 de 32 bits de precisión simple .

double : el tipo de datos doble es un punto flotante IEEE 754 de 64 bits de doble precisión .

booleano: el tipo de datos booleano representa un bit de información .

char: el tipo de datos char es un solo carácter Unicode de 16 bits .

Fuente

Complemento a dos

"El buen ejemplo de wiki es que la relación con el complemento a dos se realiza al observar que 256 = 255 + 1, y (255 - x) es el complemento a uno de x

0000 0111 = 7 el complemento a dos es 1111 1001 = -7

la forma en que funciona es que el MSB (el bit más significativo) recibe un valor negativo, por lo que en el caso anterior

-7 = 1001 = -8 + 0+ 0+ 1

Los enteros positivos generalmente se almacenan como números binarios simples (1 es 1, 10 es 2, 11 es 3 y así sucesivamente).

Los enteros negativos se almacenan como el complemento a dos de su valor absoluto. El complemento a dos de un número positivo es cuando se usa esta notación como un número negativo.

Fuente

Como recibí algunos puntos por esta respuesta, decidí agregarle más información.

Una respuesta más detallada:

Entre otros, hay cuatro enfoques principales para representar números positivos y negativos en binario, a saber:

  1. Magnitud firmada
  2. Complemento de uno
  3. Complemento de dos
  4. Parcialidad

1. Magnitud firmada

Utiliza el bit más significativo para representar el signo, los bits restantes se utilizan para representar el valor absoluto. Donde 0 representa un número positivo y 1 representa un número negativo , ejemplo:

1011 = -3
0011 = +3

Esta representación es más sencilla. Sin embargo, no puede agregar números binarios de la misma manera que agrega números decimales, lo que dificulta la implementación a nivel de hardware. Además, este enfoque utiliza dos patrones binarios para representar 0, 100 ... 0 y 0 .... 0.

2. Complemento de uno

En esta representación, invertimos todos los bits de un número dado para averiguar su complementario. Por ejemplo:

010 = 2, so -2 = 101 (inverting all bits).

El problema de esta representación es que todavía existen dos patrones de bits para representar el 0 (00..0 y 11..1)

3. Complemento de dos

Para encontrar el negativo de un número, en esta representación, invertimos todos los bits y luego agregamos un bit. Agregar un bit resuelve el problema de tener dos patrones de bits que representan 0. En esta representación, solo tenemos uno (00 ... 0).

Por ejemplo, queremos encontrar la representación binaria negativa de 4 (decimal) usando 4 bits. Primero, convertimos 4 a binario:

4 = 0100

luego invertimos todos los bits

0100 -> 1011

finalmente, agregamos un poco

1011 + 1 = 1100.

Entonces 1100 es equivalente a -4 en decimal si usamos una representación binaria de complemento a dos con 4 bits.

Una forma más rápida de encontrar el complementario es fijando el primer bit como valor 1 e invirtiendo los bits restantes. En el ejemplo anterior, sería algo como:

0100 -> 1100
^^ 
||-(fixing this value)
|--(inverting this one)

La representación del complemento a dos, además de tener una sola representación para el 0, también suma dos valores binarios de la misma forma que en decimal, números pares con diferentes signos. Sin embargo, es necesario verificar los casos de desbordamiento.

4. Sesgo

Esta representación se utiliza para representar el exponente en la norma IEEE 754 para puntos flotantes. Tiene la ventaja de que el valor binario con todos los bits a cero representa el valor más pequeño. Y el valor binario con todos los bits a 1 representa el valor más grande. Como su nombre indica, el valor está codificado (positivo o negativo) en binario con n bits con sesgo (normalmente 2 ^ (n-1) o 2 ^ (n-1) -1).

Entonces, si estamos usando 8 bits, el valor 1 en decimal se representa en binario usando un sesgo de 2 ^ (n-1), por el valor:

+1 + bias = +1 + 2^(8-1) = 1 + 128 = 129
converting to binary
1000 0001
sueño
fuente
2
Mi pregunta precisamente: ¿se almacenan los números + ve binary as ismientras que los números -ve se almacenan two's complement?
Kevin Rave
1
Los enteros positivos generalmente se almacenan como números binarios simples y los enteros negativos se almacenan como complemento a dos.
Dreamcrash
Eso responde a mi pregunta. ¿Alguna fuente? No encontré ningún documento que diga esto claramente.
Kevin Rave
el enlace anterior de ecomware.com está roto @dreamcrash, ¿puede proporcionar algún otro?
Ram Patra
@Ramswaroop Hola, ¿qué pasa con éste stackoverflow.com/questions/1049722/what-is-2s-complement
dreamcrash
61

Los enteros de Java son de 32 bits y siempre están firmados. Esto significa que el bit más significativo (MSB) funciona como bit de signo. El número entero representado por an intno es más que la suma ponderada de los bits. Los pesos se asignan de la siguiente manera:

Bit#    Weight
31      -2^31
30       2^30
29       2^29
...      ...
2        2^2
1        2^1
0        2^0

Tenga en cuenta que el peso del MSB es negativo (el mayor negativo posible en realidad), por lo que cuando este bit está activado, el número entero (la suma ponderada) se vuelve negativo.

Simulemos con números de 4 bits:

Binary    Weighted sum            Integer value
0000       0 + 0 + 0 + 0           0
0001       0 + 0 + 0 + 2^0         1
0010       0 + 0 + 2^1 + 0         2
0011       0 + 0 + 2^1 + 2^0       3
0100       0 + 2^2 + 0 + 0         4
0101       0 + 2^2 + 0 + 2^0       5
0110       0 + 2^2 + 2^1 + 0       6
0111       0 + 2^2 + 2^1 + 2^0     7 -> the most positive value
1000      -2^3 + 0 + 0 + 0        -8 -> the most negative value
1001      -2^3 + 0 + 0 + 2^0      -7
1010      -2^3 + 0 + 2^1 + 0      -6
1011      -2^3 + 0 + 2^1 + 2^0    -5
1100      -2^3 + 2^2 + 0 + 0      -4
1101      -2^3 + 2^2 + 0 + 2^0    -3
1110      -2^3 + 2^2 + 2^1 + 0    -2
1111      -2^3 + 2^2 + 2^1 + 2^0  -1

Entonces, el complemento a dos no es un esquema exclusivo para representar números enteros negativos, más bien podemos decir que la representación binaria de números enteros es siempre la misma, simplemente negamos el peso del bit más significativo. Y ese bit determina el signo del número entero.

En C, hay una palabra clave unsigned(no disponible en java), que se puede usar para declarar unsigned int x;. En los enteros sin signo, el peso del MSB es positivo ( 2^31) en lugar de negativo. En ese caso, el rango de an unsigned intes 0to 2^32 - 1, mientras que an inttiene rango -2^31to 2^31 - 1.

Desde otro punto de vista, si considera el complemento a dos de xcomo ~x + 1(NO x más uno), aquí está la explicación:

Para cualquiera x, ~xes solo el inverso de bit a bit x, por lo que siempre que xtenga un 1-bit, ~xtendrá un 0-bit allí (y viceversa). Entonces, si los suma, no habrá acarreo en la suma y la suma será solo un número entero, cada bit de lo que sea 1.

Para enteros de 32 bits:

x + ~x = 1111 1111 1111 1111 1111 1111 1111 1111
x + ~x + 1 =   1111 1111 1111 1111 1111 1111 1111 1111 + 1
           = 1 0000 0000 0000 0000 0000 0000 0000 0000

El 1-bit más a la izquierda simplemente se descartará, porque no cabe en 32 bits (desbordamiento de enteros). Entonces,

x + ~x + 1 = 0
-x = ~x + 1

Entonces puede ver que el negativo xpuede ser representado por ~x + 1, lo que llamamos complemento a dos de x.

0605002
fuente
Mi pregunta precisamente: ¿se almacenan los números + ve binary as ismientras que los números -ve se almacenan two's complement?
Kevin Rave
Bueno, sí. un número negativo se representa en una computadora como el complemento a dos de su valor positivo.
0605002
4
Gran respuesta y explicación Bonny @ 0605002, +1 :)
KM Rakibul Islam
@ 0605002: ¿Podría dar la referencia a esta respuesta, si la hubiera? Aunque conocía los conceptos, pero nunca los pensé de esa manera. Respuesta más simple y precisa.
Abhishek Singh
Cuatro años de universidad, y nunca entendí el complemento de 2. Esta respuesta me ha enseñado más. Es muy triste que en todo el mundo se enseñen cosas tan sencillas de formas tan misteriosas.
Prashant Pandey
10

He ejecutado el siguiente programa para saberlo

public class Negative {
    public static void main(String[] args) {
        int i =10;
        int j = -10;

        System.out.println(Integer.toBinaryString(i));
        System.out.println(Integer.toBinaryString(j));
    }
}

La salida es

1010
11111111111111111111111111110110

De la salida parece que ha estado usando el complemento a dos.

Cazador de mazmorras
fuente
1
Complemento a dos de 10 es 11111111 11111111 11111111 11110110. La suya imprime mientras que Binary tal como está para 10 es 1010. ¿Entonces solo -ve números se almacenan como complemento a dos?
Kevin Rave
revisa el artículo de wiki en.wikipedia.org/wiki/ ... el número de complemento a 2 que has dado para 15 es incorrecto
Dungeon Hunter
si el bit msb comienza con 1, será un número negativo
Dungeon Hunter
sí, el complemento de dos de 10 es 11111111 11111111 11111111 11110110 que es -10
Dungeon Hunter
+ ve números se almacenarán como binarios dejando el bit de signo en complemento a 2
Dungeon Hunter
4

Oracle proporciona cierta documentación sobre los tipos de datos Java que puede resultarle interesante. Específicamente:

int: el tipo de datos int es un entero de complemento a dos con signo de 32 bits. Tiene un valor mínimo de -2,147,483,648 y un valor máximo de 2,147,483,647 (inclusive).

Por cierto, el corto también se almacena como complemento a dos.

matsev
fuente
3

Según este documento , todos los enteros se firman y almacenan en formato de complemento a dos para java. No estoy seguro de su fiabilidad.

Joel
fuente
"En formato de complemento a dos, un valor positivo se representa como un número binario sencillo". escrito en el mismo documento ... entonces técnicamente es correcto. :)
Shashi
3

Los números positivos se almacenan / recuperan tal cual.

e.g) For +ve number 10; byte representation will be like 0-000 0010 
                                               (0 - MSB will represent that it is +ve).
So while retrieving based on MSB; it says it is +ve, 
so the value will be taken as it is. 

Pero los números negativos se almacenarán después del complemento a 2 (que no sea el bit MSB) y el bit MSB se establecerá en 1.

ej.) al almacenar -10 entonces

  0-000 0010  -> (1's complement) -> 0-111 1101 
              -> (2's complement) 0-111 1101 + 1 -> 0-111 1110
  Now MSB will be set to one, since it is negative no -> 1-111 1110

al recuperar, encontró que MSB está establecido en 1. Por lo tanto, es un no negativo. Y el complemento a 2 se realizará de forma distinta a MSB.

  1-111 1110  --> 1-000 0001 + 1 --> 1-000 0010
  Since MSB representing this is negative 10 --> hence  -10 will be retrived.

Fundición

También tenga en cuenta que cuando está convirtiendo int / short en byte, solo se considerará el último byte junto con el último byte MSB,

Tome el ejemplo "-130" corto, podría almacenarse como se muestra a continuación

(MSB)1-(2's complement of)130(1000 0010) --> 1-111 1111 0111 1110

Ahora la conversión de bytes tomó el último byte, que es 0111 1110. (0-MSB) Dado que MSB dice que es un valor + ve, se tomará como está. Que es 126. (+ ve).

Tome otro ejemplo "130" corto, podría almacenarse como se muestra a continuación

  0-000 000 1000 0010     (MSB = 0)

Ahora la conversión de bytes tomó el último byte, que es 1000 0010. (1 = MSB) Dado que MSB dice que es un valor -ve, se realizará el complemento a 2 y se devolverá un número negativo. Entonces, en este caso, se devolverá -126.

 1-000 0010  -> (1's complement) -> 1-111 1101 
             -> (2's complement) 1-111 1101 + 1 -> 1-111 1110 -> (-)111 1110
               = -126

Diferencia entre (int) (char) (byte) -1 Y (int) (corto) (byte) -1

(byte)-1       -> 0-000 0001 (2's Comp) -> 0-111 1111 (add sign) -> 1-111 1111
(char)(byte)-1 -> 1-111 1111 1111 1111  (sign bit is carry forwarded on left) 

similar

(short)(byte)-1-> 1-111 1111 1111 1111  (sign bit is carry forwarded on left) 

Pero

(int)(char)(byte)-1 -> 0-0000000 00000000 11111111 11111111  = 65535
since char is unsigned; MSB won't be carry forwarded. 

Y

(int)(Short)(byte)-1 -> 1-1111111 11111111 11111111 11111111 = -1
since short is signed; MSB is be carry forwarded. 

Referencias

¿Por qué se usa el complemento a dos para representar números negativos?

¿Qué es el "complemento de 2"?

Kanagavelu Sugumar
fuente
2

El bit más significativo (32º) indica que el número es positivo o negativo. Si es 0, significa que el número es positivo y está almacenado en su representación binaria real. pero si es 1, significa que el número es negativo y está almacenado en su representación en complemento a dos. Entonces, cuando le damos peso -2 ^ 32 al bit 32 mientras restauramos el valor entero de su representación binaria, obtenemos la respuesta real.

Sazzadur Rahaman
fuente
1
¡Bienvenido a StackOverflow! : D
0605002
2

Gracias, dreamcrash por la respuesta https://stackoverflow.com/a/13422442/1065835 ; en la página wiki dan un ejemplo que me ayudó a entender cómo encontrar la representación binaria de la contraparte negativa de un número positivo.

Por ejemplo, usando 1 byte (= 2 nibbles = 8 bits), el número decimal 5 está representado por

0000 01012 El bit más significativo es 0, por lo que el patrón representa un valor no negativo. Para convertir a −5 en notación en complemento a dos, los bits se invierten; 0 se convierte en 1 y 1 se convierte en 0:

1111 1010 En este punto, el numeral es el complemento a unidades del valor decimal −5. Para obtener el complemento a dos, se suma 1 al resultado, dando:

1111 1011 El resultado es un número binario con signo que representa el valor decimal −5 en forma de complemento a dos. El bit más significativo es 1, por lo que el valor representado es negativo.

Maksim Dmitriev
fuente
1

los números positivos se almacenan directamente como binarios. Se requiere el cumplido de 2 para números negativos.

por ejemplo:

15: 00000000 00000000 00000000 00001111-15
: 11111111 11111111 11111111 11110001

aquí está la diferencia en bit con signo.

Siva Padhy
fuente
1

Para el entero positivo 2, el valor del complemento es el mismo que el bit 0 de MSB (like +14 2'complement is 01110).

Solo para enteros negativos estamos calculando el valor de complemento de 2 ' (-14= 10001+1 = 10010).

Entonces, la respuesta final es que ambos valores (+ve and -ve)se almacenan solo en forma de complemento de 2 '.

Mangesh Gawali
fuente