domingo, 18 de noviembre de 2012

Operadores y Máscaras de Bits

Las computadoras almacenan datos en forma de 0s y 1s. La razón de ésto es que el binario es el sistema de numeración posicional más simple. Un bit es la menor cantidad de información que se puede almacenar. Un conjunto de 8 bits recibe el nombre de palabra o byte. El lenguaje de programación C es un lenguaje de nivel medio. Ésto, entre otras cosas, significa que es posible realizar operaciones a nivel de bits. Ésta es una interacción directa con el hardware y por lo tanto es mucho más rápida que la programación a alto nivel. Por ejemplo, es posible determinar el tamaño en bytes de cualquier tipo de datos con
=====================================================================================
El operador unario sizeof()
=====================================================================================
Vamos a considerar el siguiente programa

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *                                                         +
 * Este programa imprime los tamanios en bits de variables +
 * tipo char, int, double, etc.                            + 
 *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include 
#define TAMANO 2

int main()
{  /* Abre main*/
char c;
int x;
int Arreglo[TAMANO];
double y;

printf("\nEl tamanio en bytes de una variable char es: %d\n", sizeof(c));
printf("El tamanio en bytes de una variable int es: %d\n", sizeof(x));
printf("El tamanio en bytes de una arreglo int de %d localidades es: %d", TAMANO, sizeof(Arreglo));
printf("\nEl tamanio en bytes de una variable double es: %d\n", sizeof(y));

return 0;
}  /* Cierra main*/

La ejecución del mismo produce

El tamanio en bytes de una variable char es: 1
El tamanio en bytes de una variable int es: 4
El tamanio en bytes de una arreglo int de 2 localidades es: 8
El tamanio en bytes de una variable double es: 8
Cuando el operador sizeof se aplica a una variable char, el resultado es 1 porque 1 byte (8 bits) es el tamaño necesario para almacenar un carácter cualquiera de los 256 que forman el código ASCII. Así que por esa razón el tamaño de una variable tipo carácter es estándar. El tamaño de un entero en C, depende de la máquina en la que se ejecuta; para ésta máquina en particular es de 4 bytes (32 bits) (véase la entrada La representación en complemento a 2 para más detalles.) También se ha definido un arreglo de 2 localidades enteras; el número de bytes que ocupa dicho arreglo es 8, cuatro para cada localidad entera. Adicionalmente aparece una variable tipo double, que ocupa 8 bytes (64 bits).
=====================================================================================
& El Operador AND de Bits
=====================================================================================
El operador & (NO confundir con el operador lógico &&) es un operador lógico a nivel de bits. Compara un par de cadenas de bits bit por bit, el resultado para cada comparación es 1 si los dos bits son 1 y 0 en otro caso. Como ejemplo, vamos a considerar las siguientes cadenas:
Una máscara de bits
Empezando por la derecha, el primer bit de la primera cadena, tiene un 1, y la segunda cadena tiene también un 1, por lo tanto, 1 & 1 = 1. Aplicando & a los bits de la siguiente posición: 0 & 0 = 0, los siguientes: 1 & 0 = 0; después 0 & 1 = 0; los bits de la 5ta posición: 1 & 1 = 1, y los últimos dan 0, 1 & 0 = 0.
Con el operador & se puede ocultar un conjuto de bits que no son relevantes en determinada situación. Ésto constituye una máscara de bits. Vamos a considerar un pequeño problema y elaborar una solución: En un ciclo controlado por una variable llamada TAMANO, es necesario imprimir el valor del contador sólo desde 0 hasta 15, y comenzar después en 0, aún cuando TAMANO se siga incrementando. Con algunas instrucciones condicionales dentro del ciclo es posible realizar esta tarea, pero con una máscara de bits, se puede escribir un programa como el siguiente:

/*+++++++++++++++++++++++++++++++++++++++++++++
 *                                            +
 * Este programa imprime ciclicamente valores +
 * de una variable por debajo de un limite,   +
 * por medio de una mascara de bits.          +
 * +++++++++++++++++++++++++++++++++++++++++++*/

#include 
#define TAMANO 200
#define LIMITE 15

int  main()

{ /* Abre main*/
int i = 0;

for ( i = 0; i < TAMANO; i++ )
{
 printf("%d\n", i & LIMITE);
}

return 0;
} /* Cierra main*/

La salida de este programa es: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, ...
Se ha mantenido la impresión por debajo de la variable LIMITE. La línea relevante, para los fines de esta entrada, es la siguiente:

printf("%d\n", i & LIMITE);

la función printf imprime un entero, el entero que se produce de la comparación de los bits de el primer número, el contador i, con el número LIMITE. Es importante mencionar que éste y los siguientes operadores son aplicables únicamente a variables de tipo entero, como char, int, long, short, con los calificativos signed y unsigned. En éste caso, la variable límite funciona como una máscara, que oculta todos los bits a la izquierda de el último 1 a la izquierda.
Máscara de bits para controlar un ciclo.
Ésta figura presenta los primeros 6 bits de los los números LIMITE (15) y un valor de TAMANO (25), recuerde que, en nuestra máquina, los enteros tienen tìpicamente 32 bits, o sea que hacia la izquierda de cada renglón se encuentran muchos ceros que no se han dibujado por comodidad. Aplicando el operador & bit por bit a ambas representaciones obtenemos el renglón de abajo, el cual es el número 9 en el sistema de numeración binario. Observe que más allá del último 1 (el de la extrema izquierda)de la máscara (15) todos los bits del resultado se vuelven 0, y si hubiera algún 0 antes del último 1 ocurriría una ambigüedad, ya que 0 ó 1 en TAMANO produciría 0. ÉSta es la razón por la cual éste método funciona solamente con números que en su representación binaria tengan sólo 1s, como 3 (11), 7 (111), 15 (1111), 31 (11111), etc.
=====================================================================================
<< El Operador de desplazamiento izquierdo de Bits
=====================================================================================
Vamos a considerar el siguiente programa.

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*  Este programa hace uso de el operador de desplazamiento *
*  hacia la izquierda <<                                   *
*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include 
using namespace::std;

int main()
{   /* Abre main*/
int x = 1;
// Los operadores de bits solo se aplican a variables unsigned
cout <<"\nEl tamanio de una variable int es: "<< sizeof(int)<< endl;

cout <<"\nEl valor inicial de x: "<< x << endl;

for (unsigned i = 1; i <= 8; i++ ) 
{
  
unsigned desplazado = x << i;

cout <<"\nEl numero: " << desplazado << endl;
}

cout <<"\nEl valor final de x: " << x << endl;
}   /* Cierra main*/


La ejecución es la siguiente:

El tamanio de una variable int es: 4

El valor inicial de x: 1
El numero: 2
El numero: 4
El numero: 8
El numero: 16
El numero: 32
El numero: 64
El numero: 128
El numero: 256
El valor final de x: 1

Al principio se define una variable llamada x, la cual se inicializa con el valor 1. Un ciclo for, de 1 a 8 incluidos, utiliza el operador de desplazamiento izquierdo para recorrer los bits hacia la izquierda, lo cual, en el sistema posicional binario, hace que el valor se incremente en potencias de 2, tal como se muestra en la figura siguiente:

Observe que el valor de x, fuera del ciclo for, sigue siendo de 1.

=====================================================================================
>> El operador de desplazamiento derecho de bits
=====================================================================================
De manera similar, el lenguaje C proporciona el operador de desplazamiento derecho de bits >>. El siguiente programa muestra cómo opera:

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*  Este programa hace uso de el operador de desplazamiento *
*  hacia la derecha  >>                                    *
*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include 
using namespace::std;

int main()
{   /* Abre main*/
int x = 128;

cout <<"\nEl tamanio de una variable int es: "<< sizeof(int)<< endl;

cout <<"\nEl valor inicial de x: "<< x << endl;

for (unsigned i = 1; i <= 8; i++ ) 
{
  
unsigned desplazado = x >> i;

cout <<"\nEl numero: " << desplazado << endl;
}

cout <<"\nEl valor final de x: " << x << endl;
}   /* Cierra main*/

La salida es la siguiente:

El tamanio de una variable int es: 4

El valor inicial de x: 128

El numero: 64
El numero: 32
El numero: 16
El numero: 8
El numero: 4
El numero: 2
El numero: 1
El numero: 0
El valor final de x: 128

Se inicia con una variable llamada x, la cual se inicializa en 128, en un ciclo for se va disminuyendo el valor de dicha variable por medio del operador de desplazamiento derecho. La variable adquiere sucesivamente los valores 128, 64, 32, 16, 8, 4, 2, 1. Una representación esquemática del acarreo de bits es la siguiente:


martes, 6 de noviembre de 2012

100 000 visitas y mi otro Blog

Bueno, supongo que comparado con muchas páginas ésta cifra no es nada. El caso es que en éstos días, éste blog ha alcanzado las 100000 páginas vistas, lo cual me da mucho gusto. Sobre todo si tengo en cuenta que cuando inicié, hace poco más de dos años, recibía algunas decenas de visitantes al mes. Con el paso del tiempo, de manera lenta pero continua, las visitas se han incrementado. Como dije, esto me da mucho gusto, pero también me hace pensar que la mayoría de los que aquí entran vienen con la intención de resolver un problema o de encontrar información útil; por ésto he cambiado la orientación que tenía éste blog. Al principio fue, y lo sigue siendo, una forma de almacenar la información que yo tenía. No se me ocurrió nada mejor para guardar mis programas que hacerlos públicos en ésta página; cualquiera que haya intentado almacenar información por mucho tiempo en un disco duro se habrá dado cuenta qué tan peligrosa es esa práctica; el blog ha sido para mi un espacio más estable. Pero como decía, los visitantes no pueden leer mi mente, y casi todo el código que tengo aquí está muy poco explicado, a eso me refería con el cambio en la orientación. Ahora trato de escribir no sólo para mí, sino para las personas que ocasionalmente los visitan. También estoy reescribiendo muchas entradas, cambiando el formato (ahora simplemente no tengo formato) y tratando de ponerme en los zapatos de quien entra aquí por primera vez y no sabe siquiera qué es un blog. A lo largo de éste tiempo he tenido diversas plantillas, de las estándar de blogger a la presente, que me ha resultado más atractiva. He tenido ya varias generaciones de lectores y algunos de ellos incluso han regresado y han dejado comentarios útiles e interesantes.
La intención original de éste blog sigue siendo la misma: resolver problemas y ejercicios de programación. En particular los correspondientes a los libros de Deitel (Java y C++) y los de Kernighan y Ritchie (algunos de ellos bastante difíciles desde el enunciado mismo). Si no he podido terminarlos ha sido por una mezcla de circunstancias entre las que sobresale mi habitual pereza. Sin embargo, la idea sigue tan válida como en el principio.
Por otro lado, hace ya algún tiempo, decidí crear otro blog, en wordpress, para continuar con algo que empecé en éste: mis entradas relativas a Unix - Linux. Resulta que desde hace mucho he venido usando exclusivamente linux y, como no sabía absolutamente nada, he llevado un registro de las cosas que voy aprendiendo en el camino. Por eso no han aparecido más entradas clasificadas en la etiqueta Linux. Ahora están en Aprendiendo a Usar Linux
Aprendiendo A Usar Linux
Algunas de las entradas de Ejercicios Resueltos hacen referencia a Aprendiendo a Usar Linux, además de que algunos de los comentarios aquí son contestados con el perfil de wordpress. Estoy seguro de que muchos de los visitantes de éstos blogs tienen intereses comunes. La razón por la cual estas entradas no aparecen juntas es, entre otras cosas, porque blogspot y wordpress tienen ventajas y desventajas. Wordpress es más "estable" aunque ofrece menos servicios; blogspot ofrece mayores libertades.
En ambos casos, bloguear me ha sigo doblemente útil y divertido, por un lado los blogs sirven de archivos que están disponibles en culquier momento y por otro, el explicar algo para otra persona enseña bastante: una idea que parece bastante clara, resulta no serlo tanto cuando se tiene que explicar. También puedo añadir una tercera ventaja de tener un blog: los visitantes. Sean principiantes, avanzados o expertos en el tema, algunos dejan comentarios muy interesantes y educativos. Esta entrada es un agradecimiento a ellos.
Related Posts Plugin for WordPress, Blogger...