viernes, 4 de octubre de 2013

Tipo Byte en Java

En esta entrada quiero mostrarles uno de los datos de tipo entero en java: Byte. Para ello seguiré el siguiente esquema
  1. Operaciones básicas con datos tipo Byte.
  2. Conversión de binario a  Byte.
  3. Posibles errores que podemos cometer.
Antes de comenzar veamos que son los datos tipo Byte.

Son un dato tipo entero de 8 bits, luego puede tomar valores entre -128 y 127 (incluyendo). La utilidad de este tipo de datos reside en el ahorro de espacio: si tenemos dos vectores, uno de tipo int y otro de tipo  byte, y comparamos la cantidad de memoria que usan, notaremos que la usada por el de tipo byte es mucho menor.

Operaciones Básicas con Datos de Tipo Byte

Con datos de tipo byte es posible realizar las 4 operaciones básicas: suma, resta, multiplicación y división. Veamos lo anterior con un ejemplo:
 
public class PruebasBlog {
    public static void main(String[] args) {
        byte b1 = 4;
        byte b2 = 3;
        
        byte suma =  (byte) (b1 + b2);
        byte resta =  (byte) (b1 - b2);
        byte division =  (byte) (b1/b2);
        byte multiplicacion = (byte) (b1*b2);
      
        System.out.println("Suma: " + suma);
        System.out.println("Resta: " + resta);
        System.out.println("Division: " + division);
        System.out.println("Multiplicacion: " + multiplicacion);
    }
}

En el anterior código observamos las 4 operaciones básicas. El resultado mostrará que la suma es igual a 7, la resta a 1, la división a 1 y la multiplicación a 12. Seguramente les han surgido algunas dudas, intentaré adivinarlas y responderlas:
  • ¿Por qué estamos haciendo un casting en suma, resta división y multiplicación?: Primero, si no sabes a que me refiero con casting, digamos simplemente que es esta línea de código (en el caso de la suma):
     
            byte suma =  (byte) (b1 + b2);
    

    La razón fundamental es que la suma, resta, multiplicación y división de dos bytes me retorna un entero; luego, debo transformarlo para volver a guardarlo en un tipo byte. Si quieres saber más sobre el casting, puedes visitar este recurso.
  • ¿Por qué la división da 1 y no 1,333...?: En el mundo real sabemos que al dividir 4 entre 3 el resultado no es un número entero; sin embargo, en nuestro programa estamos almacenando ese resultado en un entero tipo byte, y un entero no puede tener decimales. Luego, lo que sucede es que guardamos el cociente de la división en nuestra variable byte.

 Conversión de Binario a Byte

Antes de comenzar es importante saber que que el tipo byte es un tipo entero de 8 bits complemento a dos. ¿Qué significa eso de "complemento a dos"?, pues es básicamente una forma de representar datos positivos y negativos en binario. Resulta que un entero tipo byte es almacenado en 8 bits, donde el último representa el signo. Ver figura 1:

Figura 1: Representación binaria de un objeto tipo byte.
Según lo anterior, si el último bit (b7) es 0, el número es positivo y si es 1 será negativo. Las reglas para aplicar el complemento a dos son bastante sencillas:
  • Si el número es positivo (b7 = 0) no se hace nada, y el número en decimal será el equivalente de transformar la parte en azul de la figura 1.
  • Si el número es negativo (b7 = 1), el decimal resultante será igual a invertir los 0 por 1 y viceversa y luego sumar 1 al resultado. 
Si quieren saber más del complemento a dos, pueden visitar este enlace.
Sabiendo lo anterior, ahora veamos un ejemplo de como transformar un binario en un byte.
 
public class PruebasBlog {
    public static void main(String[] args) {
        // Es equivalente a: byte numero1 = (byte)Short.parseShort("00000001", 2);
        byte numero1 = Byte.parseByte("0000001", 2);
        // NO es equivalente a: byte numero2 = Byte.parseByte("10000001", 2);
        byte numero2 = (byte)Short.parseShort("10000001", 2);
        System.out.println("Numero 1: "+numero1);
        System.out.println("Numero 2: "+numero2);
    }
}

El ejemplo anterior mostrará que numero1 es igual a 1 y numero2 es igual a -127. Hay varias cosas que es importante resaltar:
  • ¿Por qué en numero1 y numero2 hacemos diferente la conversión?: Simplemente quiero mostrar cuan importante es saber cómo guarda el computador los datos. En el caso de numero1, la conversión se puede tanto usando parseShort() junto a un casting como con un simple parseByte(); sin embargo, en numero2 si es necesario usar el parseShort().

    Ahora la pregunta que seguramente se están haciendo, ¿por qué?. Resulta que, en el caso de numero2, si intentamos hacer:
     
            byte numero2 = Byte.parseByte("10000001", 2);
    

    Se generará un error, porque 10000001 en binario es igual a 129 en decimal, un valor por fuera del rango del tipo byte. Es por esto que es necesario primero "parsearlo" en un objeto tipo short, y luego ya almacenarlo en uno de tipo byte.

  • ¿Por qué numero2 es igual a -127?: Esto esta relacionado con el complemento a dos. Al ser negativo (el último bit de derecha a izquierda es igual a 1), es necesario aplicarle a los 6 primeros dicho complemento, con lo cual 0000001 se transforma en 1111110 (126 en decimal), y finalmente al sumarle 1 se obtiene el 127.

Posibles Errores que Podemos Cometer

Considero que el error más común es desbordar la capacidad del tipo byte, es decir, intentar guardar un número fuera del rango [-127, 128]. Por ejemplo, el siguiente código tiene un error, ya que esta intentando almacenar en la variable numero2 el decimal 129 en binario.
 
public class PruebasBlog {
    public static void main(String[] args) {
        byte numero2 = Byte.parseByte("10000001", 2);
        System.out.println("Numero 2: "+numero2);
    }
}

En este caso obtendremos una NumberFormatException, como apreciamos en la figura 2:

Figura 2: NumberFormatException al intentar guardar 129 en un byte
Un ejemplo interante, y que nos muestra cuan cuidadosos debemos ser a la hora de hacer operaciones entre datos tipo byte, es el siguiente:
 
public class PruebasBlog {
    public static void main(String[] args) {
        byte numero1 = 100;
        byte numero2 = 125;
        byte suma = (byte) (numero1 + numero2);
        System.out.println("Suma: "+ suma);
    }
}

El anterior código no genera ninguna excepción al compilarlo; sin embargo, el resultado obtenido es "Suma: -31". Todos sabemos que 100 + 125 es igual a 225, ¿entonces por qué el resultado es -31?. Todo esta nuevamente relacionado con la forma como nuestro computador almacena y trabaja con los datos, ya que la máquina no suma en decimal, si no en binario. Por tanto esta adicionando los números 01100100 (100) y 01111101 (125); el resultado de esta operación es 11100001, y aquí viene la parte divertida: le estamos diciendo a nuestro computador que guarde 11100001 en una variable byte, y este al ver el último bit observa que es 1, luego ¡asume que nuestro número es negativo y le aplica el complemento a dos!. Es decir, 1100001 se transforma en 0011110 (30 en decimal), se le suma 1 y se le pone signo negativo, obteniendose -31.

4 comentarios: