miércoles, 28 de agosto de 2013

La instrucción goto y etiquetas

El lenguaje C proporciona la instrucción goto como una forma de transferir el control del programa. Por ejemplo considere el siguiente código

/*+++++++++++++++++++++++++++++++++++++++++++++++++
+ Este programa hace uso de la proposicion goto   +
**************************************************/

#include <stdio.h>

int main()

{ /* Abre main */
printf("\nEsta es la primera instruccion del programa.");

/* Se usa goto */
goto instruccion;

printf("\nEsta es la segunda instruccion del programa.");

instruccion:
printf("\nEsta es la tercera instruccion del programa.");
printf("\nEsta es la cuarta instruccion del programa.\n");
return 0;

} /* Cierra main */


Aquí se presenta una instrucción goto seguido del nombre de una etiqueta llamada instruccion. La función de goto es omitir la realización de todas las líneas que hay entre goto y la etiqueta. Una ejecución del programa es la siguiente:

hernandez@miMaquina ~/Programas $ ./a.out 

Esta es la primera instruccion del programa.
Esta es la tercera instruccion del programa.

Esta es la cuarta instruccion del programa.

Observe que la segunda línea printf no se imprime, debido al uso de la etiqueta goto. A partir de donde está la etiqueta, se reinicia la ejecución del programa en el orden en que aparecen las líneas de código. El uso de goto puede ser muy cómodo, pero es muy poco recomendado. La programación estructurada ha venido a ser sinónimo de "programación sin goto". En el pasado los ingenieros y desarrolladores se dieron cuenta de que los programas con goto eran más difíciles de mantener y depurar, debido a que no hay un orden en las instrucciones.

lunes, 22 de julio de 2013

Kernighan_Ritchie_2_7.c (Inversión de bits)

______________________________________________________________________________________________________________________
2.7 Escriba una función invert(x, p,n) que regresa x con los n bits que principian en la posición p invertidos (esto es, 1 cambiado a 0 y viceversa), dejando los otros sin cambio.
______________________________________________________________________________________________________________________
Solución:
Primero, hay que dejar claro de lo que se trata éste programa. Para ésto, vamos a suponer que se recibe como entrada el número 90, y se quiere invertir los 3 bits que empiezan a partir del tercero. Lo que éste programa hace, se muestra en la siguiente figura:
Éste programa invierte los bits en rojo.
Se observa que hay sustitución de 1 por 0 a partir del tercer bit (el primero es el 0), por lo cual, el número se transforma en 42.

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *                                                                  + 
 * Este programa recibe un entero sin signo e  invierte los n bits  + 
 * de dicho entero a   partir de la posicion p.                     +
 *                                                                  + 
 * Recibe x, que en binario es:                                     + 
 *                                                                  + 
 * |x|x|x|x|x|x|x|x|                                                + 
 * en donde x es 1 o 0                                              + 
 *                                                                  + 
 * tambien se recibe p (la posicion a partir de la cual se invertiran
 * los bits)  y n, el numero de bits a invertir. Por ejemplo, si se *
 * recibe x = 30, n = 2, p = 2.                                     *
 *             p                                                    *
 *   30 = |1|1|1|1|0|                                               * 
 *           2 1                                                    *
 *           n                                                      *
 *                                                                  *
 * Este programa inviert (cambia 1 por 0 y viceversa) los n bits    *
 * desde p. (la cuenta es hacia la izquierda, el primer bit es el 0 *
 * Así que para este caso el numero quedaria como:                  *
 *                                                                  *
 *        |1|0|0|1|0| = 18                                          *
 *                                                                  *
 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/*******************************************************************+
 *                         ALGORITMO                                +
 * El problema se dividira en 2 partes principales                  +
 *                                                                  *
 * 1) Obtener el numero binario                                     *
 *                           p                                      *
 *    |0|0|0|0|...|0|x|x|...|x|0|...|0|                             *
 *                   p + n                                          *
 *                                                                  *
 *   donde los bits marcados con x son el complemento a 1 (inverso) *
 *   del numero entre 0 y p                                         *
 *                                                                  *
 * 2) Obtener el numero binario                                     *
 *                 p+n     n                                        *
 *    |x|x|x|...|x|0|0|...|0|x|....|x|                              *
 *                                                                  * 
 *    donde los bits marcados con x tienen el mismo valor que el    *
 *    numero original.                                              *
 *                                                                  *
 * El numero deseado se obtiene uniendo los que aparecen en 1) y 2) *
 * mediante el operador binario |                                   *
 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include <stdio.h>

///////////////////////////////////////////////////////////////////////////
//UNSIGNED
/////////////////////////////////////////////////////////////////////////// 
unsigned invert(unsigned x,int p,int n)

{ /* Abre invert */
return (((~(~0 << p + n) & (~0 << p)) & ~x) | ((( ~0 << p+n) | ~(~0 <<p)) & x) ); 
} /* Cierra invert */

///////////////////////////////////////////////////////////////////////////
//MAIN
///////////////////////////////////////////////////////////////////////////

int main()
{ /* Abre main */
unsigned numero;
int a, b;

printf("\nPor favor introduzca un entero sin signo: \n");
scanf("%d", &numero);

printf("\nPor favor introduzca el numero de bits a invertir: \n");
scanf("%d", &b);

printf("\nPor favor introduzca el bit a partir del cual se hara la inversion: \n");
scanf("%d", &a);

printf("\nEl numero, despues de invertir los %d bits a partir de la posicion ", a);
printf("%d es: %d\n", b, invert(numero, b,a));

return 0;
}  /* Cierra main*/

miércoles, 8 de mayo de 2013

Kernighan_Ritchie_2.6 (Desplazamiento y sustitución de bits)

_______________________________________________________________________________________
2.6 Escriba una función setbits(x,p,n,y) que regresa x con los n bits que principian en la posición p iguales a los n bits más a la derecha de y, dejando los otros bits sin cambio.
_______________________________________________________________________________________
Solución:
Lo primero, igual que en este ejemplo, es entender bien el enunciado. Para ésto, vamos a visualizar la representación binaria de un par de números enteros positivos, digamos el 51 y el 42. Para estos números bastan seis bits. Vamos a suponer que el número de bits del primer entero (51) que vamos a cambiar por otros tantos del segundo (42) serán 3 (la variable n de setbits), y que además queremos cambiarlos a partir de la posición 1 (variable p ). Es importante recordar que la posición extrema derecha de un byte es el bit 0. Una vez establecido ésto, lo que el programa quiere es lo que se muestra en la siguiente figura:
La función setbits elimina los bits rojos y los sustituye por los azules.
La función setbits intercambia los 3 bits a partir del primero en la representación binaria de 51, con los tres primeros de la representación binaria de 42. El resultado es el número 53. Una vez entendida esta gráfica, es muy fácil entender la línea única de la función:

return (~((~0 << p) & ~(~0 <<(p+n))) & x ) | (~(~0 << p+n) & (y << p));

Esta línea, a pesar de parecer muy poco intuitiva, surge de una análisis simple.
1) Hacer 0 los bits entre p y p+n en el primer número. Ésto se logra creando una máscara que contenga 1s en todas las entradas, salvo en dichos bits. Esa máscara se crea con (~((~0 << p) & ~(~0 <<(p+n))) & x ). 2) Correr los bits del segundo número hasta la posición p. Ésto es, (y << p). 3) Hacer 0 los bits del segundo número, salvo en los intervalos 0-p y p+n hasta el último. Esto se logra con la máscara (~(~0 << p+n) & (y << p)). 4) Usar el operador | para lograr la unión de los bits distintos de 0 en de ambos números.
En los comentarios del programa se presenta éste mismo procedimiento como explicación del algoritmo.


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
* Este programa recibe dos enteros sin signo. Regresa otro entero sin    *
* signo, el que se obtiene al cambiar n bits del primero, a partir de la *
* posicion p, con los n bits mas a la derecha del segundo.               *
*                                                                        *
* Lo que recibe: 4 enteros positivos.                                    *
* Lo que regresa: 1 entero positivo.                                     *
*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*                               ALGORITMO:                               *
*Establecer a o los n bits del primer numero, a partir de la posicion p  *
*                                                                        *
*                                              p                         *
*      | x | x | x | x | x | x | 0 | 0 | ... | 0 | x | x | x |           *
*                              -     n   --------                        *
*                                                                        * 
*Mover los bits del segundo numero p posiciones a la izquierda           *
*                                                                        *
*Establecer a 0 todos los bits (antes de la posicion p y despues de la n)*
*del segundo numero                                                      *
*                                                                        *
*                                  n             p                       *
*      | 0 | 0 | 0 | 0 | ... | 0 | x | x | ... | x | 0 | 0 | 0 |         *
*                                                                        *
*Con el operador o inclusivo | (puede ser el ^ o exclusivo) obtener el   *
*numero buscado.                                                         *
*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include 

///////////////////////////////////////////////////////////////////////
//setbits
///////////////////////////////////////////////////////////////////////

unsigned setbits( unsigned x, int p, int n, unsigned y)
{ /* Abre setbits */
 return (~((~0 << p) & ~(~0 <<(p+n))) & x ) | (~(~0 << p+n) & (y << p));
} /*Cierra setbits */

///////////////////////////////////////////////////////////////////////
//MAIN
///////////////////////////////////////////////////////////////////////

int main()
{  /* Abre main */
unsigned numero1, numero2;
int a, b;

printf("\nIntroduzca un entero sin signo: ");
scanf("%d", &numero1);

printf("\nIntroduzca un segundo entero sin signo: ");
scanf("%d", &numero2);

printf("\nIntroduzca el numero de bits a cambiar: ");
scanf("%d", &a);

printf("\nIntroduzca el bit a partir del cual se hara el cambio: ");
scanf("%d", &b);

printf("\nEl numero resultante es: %d\n", setbits(numero1, b, a, numero2));  

return 0; 
}  /* Cierra main */

ÉSte programa no tiene la precaución de verificar que los valores sean válidos. Por ejemplo, se podría introducir un valor de p mayor que el número total de bits. Ésto se puede evitar colocando algunos condicionales en la función main. No he querido colocarlos para no complicar el código. Es fácil hacerlo.
Aquí una ejecución, usando los números presentados anteriormente.

[hernandez@localhost Programas]$ ./a.out 

Introduzca un entero sin signo: 51

Introduzca un segundo entero sin signo: 42

Introduzca el numero de bits a cambiar: 3

Introduzca el bit a partir del cual se hara el cambio: 1

El numero resultante es: 53

__________________________________________________________________________________________
Esta entrada es parte de los problemas resueltos del libro El Lenguaje de Programación C de B. Kernighan y D. Ritchie
Entrada Anterior

Un ejemplo usando operadores para manejo de bits

Éste programa usa la función getbits (sección 2.9 de El Lenguaje de Programación C, de Kernighan y Ritchie). La razón para ponerlo aquí es que no es claro a primera vista, al menos para mí, lo que esa función hace. En la sección 2.9 se estudian los operadores binarios y getbits hace uso de &, el and de bits; <<, corrimiento a la izquierda; >>, corrimiento a la derecha y ~, complemento a uno, para hacer lo siguiente:
"regresa el campo de n bits de x (ajustado a la derecha) que principia en la posición p. Se supone que la posición del bit 0 está en el borde derecho y que n y p son valores positivos adecuados. Por ejemplo, getbits(x,4,3) regresa los tres bits que están en la posición 4, 3 y 2 ajustados a la derecha."

No soy el único que encuentra difícil la redacción (la original, en inglés) del libro de Kernighan y Ritchie. He encontrado varias páginas y foros en los que la gente se pregunta qué quisieron decir en tal o caul parte. Afortunadamente, aquí se puede entender sin ambigûedades.
Vamos a suponer que las variables son éstas: x = 179, p = 4 y n = 3. Para hacer ésto más fácil, la representación binaria de 179 es la siguiente:

Representación binaria de 179, en 10 bits.
Lo que hace nuestra función es mostrar dejar únicamente los 3 bits que comienzan a partir de la posición 4 (la posición extrema derecha es la 0). Éstos bits son 1 0 0, y deben aparecer corridos hacia la derecha. Todos los demás bits deben estar establecidos en 0.
El número 179 después de aplicar getbits.
El corazón del programa es, desde luego, la instrucción

return ((x >> (p+1-n)) & ~(~0 << n));

Ésta línea se divide en dos partes, separadas por el operador &. La instrucción x >> (p+1-n) corre hacia la derecha (4+1-3 = 2) bits. Esto es, se eliminan los bits 0 y 1 (ambos con 1), que deja el número binario 0000101100.
~(~0 << n) crea una máscara de bits. ~0 genera el binario 1111111111 y ~0 << n, con n = 3, corre hacia la izquierda el primer bit y llena los espacios con 0. Se produce entonces el número binario 1111111000. Finalmente, ~(~0 << n) crea el binario 0000000111. Esta es la máscara. Aplicando el operador & a 0000101100 y 0000000111 produce 0000000100. Este número es 4. Es precisamente lo que se obtiene al ejecutar el programa
/*++++++++++++++++++++++++++++++++++++++++++++
 * "regresa el campo de n bits de x (ajustado *
 * a la derecha) que principia en la posicion *
 * p. Se supone que la posicion del bit 0     *
 * esta en el borde derecho y que n y p son   *
 * valores positivos adecuados" Kernighan-    *
 * Ritchie                                    *
 *+++++++++++++++++++++++++++++++++++++++++++*/
#include 

///////////////////////////////////////
// FUNCION GETBITS
// ////////////////////////////////////

unsigned getbits(unsigned x, int p, int n)
{ /* Abre getbits*/
 
return ((x >> (p+1-n)) & ~(~0 << n));

} /*Cierra getbits*/

////////////////////////////////////////
//FUNCION MAIN
////////////////////////////////////////

int main()
{ /* Abre main*/

unsigned numero;
int a, b;

printf("\nIntroduzca un entero sin signo: ");
scanf("%d", &numero);

printf("\nIntroduzca el numero de bits a mostrar: ");
scanf("%d", &b);

printf("\nIntroduzca el numero de bit a partir del cual se mostraran: ");
scanf("%d", &a);

printf("El numero es: %d\n", getbits(numero,a,b));

return 0;
}/*Cierra main*/
Aquí la ejecución

[hernandez@localhost Programas]$ ./a.out 

Introduzca un entero sin signo: 179

Introduzca el numero de bits a mostrar: 3

Introduzca el numero de bit a partir del cual se mostraran: 4
El numero es: 4

jueves, 2 de mayo de 2013

De decimal a octal con una función recursiva

Éste programa es una consecuencia natural de la entrada anterior. Es tan simple como cambiar 2 por 8. En realidad, como puede verse, éste procedimiento sirve para convertir de decimal a cualquier base posicional entre 2 y 9. También es posible usarlo para una conversión a sistema hexadecimal.

#include <stdio.h>

/*////////////////////////////////////
 * Funcion Octal                     *
 *///////////////////////////////////*/

void Octal( int x)

{  /* Abre Octal*/
if ( x != 0 )
{ /* Abre if*/
Octal(x/8);

printf("%d\t", x%8);
} /*Cierra if */

else;
 /*printf("0\n");*/

}  /*Cierra Octal*/

/****************************************
 * main                                 *
 ***************************************/
int main()

{  /*Abre main */
 int num; 

 printf("\nIntroduzca un numero entero: ");
 scanf("%d", &num);

 Octal(num);
 printf("\n");

 return 0;
}  /*Cierra main */


Y aquí una ejecución, con el número 100 como entrada

[hernandez@localhost Programas]$ ./a.out 

Introduzca un numero entero: 100                                                     
1       4       4                   


miércoles, 1 de mayo de 2013

De decimal a binario con una función recursiva

Tengo una versión de éste programa que es bastante más complicada, pero por mucho tiempo recordé que lo había visto resuelto usando recursión. Ahora he pensado algunas formas de hacerlo, por ejemplo ésta:
Supongamos que tenemos el número 41, y que queremos convertirlo de su notación decimal a binario.
41 En binario  = 1 0 0 0 0 0 + (41 - 32) En binario

                                   9 En binario = 1 0 0 0 +  (9 - 8) En binario

                                                                1 En binario = 1.
El problema se va reduciendo cada vez por medio de llamadas a sí mismo con argumentos más simples. Al final sólo es necesario sumar las representaciones binarias de 32 + 8 + 1. Sin embargo no es ésto lo que yo quiero aquí. Además, sumar será en éste caso más complicado que la propia conversión. Por lo tanto descarté ésta posibilidad.
Otra forma es sugerida por el siguiente proceso, que puede encontrarse por ejemplo en el libro de Diseño Digital, de Morris Mano:
Número          División       Residuo          Binario
  41/2     =       40/2    +     1/2              1
  
  20/2     =       20/2    +      0               0

  10/2     =       10/2    +      0               0
 
   5/2     =        4/2    +     1/2              1
 
   2/2     =        2/2    +      0               0

   1/2     =          0    +     1/2              1
Éste algoritmo es fácilmente programable usando el operador %. Sin embargo, tiene el gran inconveniente de que los dígitos se imprimen en el orden inverso, como puede verse al ejecutar el siguiente código

#include <stdio.h>

/*////////////////////////////////////
 * Funcion Binario                   *
 *///////////////////////////////////*/

void Binario( int x)

{  /* Abre binario*/
if ( x != 0 )
{ /* Abre if*/
printf("%d\t", x%2);

Binario(x/2);

} /*Cierra if */

else;
 /*printf("0\n");*/

}  /*Cierra binario*/

/****************************************
 * main                                 *
 ***************************************/
int main()

{  /*Abre main */
 int num; 

 printf("\nIntroduzca un numero entero: ");
 scanf("%d", &num);

 Binario(num);

 return 0;
}  /*Cierra main */


La ejecución es la siguiente

[hernandez@localhost Programas]$ ./a.out 

Introduzca un numero entero: 41
1       0       0       1       0       1  

De nuevo el problema es que se está imprimiendo el número al revés. Ésto es grave, porque el código es muy bueno, y cualquier intento por corregir el defecto, requiere algoritmos más complicados que la propia conversión.
Sin embargo, después de pensarle, la solución es muy simple. En la función Binario, basta con cambiar el orden de los dos únicos enunciados. Primero hay que hacer una llamada a Binario, y ésto llevará la ejecución hasta el final, hasta el caso más simple, y el control se regresará desde el último caso, imprimiendo los dígitos binarios en el orden inverso. El programa correcto es el siguiente:

#include <stdio.h>

/*////////////////////////////////////
 * Funcion Binario                   *
 *///////////////////////////////////*/

void Binario( int x)

{  /* Abre binario*/
if ( x != 0 )
{ /* Abre if*/
Binario(x/2);

printf("%d\t", x%2);
} /*Cierra if */

else;
 /*printf("0\n");*/

}  /*Cierra binario*/

/****************************************
 * main                                 *
 ***************************************/
int main()

{  /*Abre main */
 int num; 

 printf("\nIntroduzca un numero entero: ");
 scanf("%d", &num);

 Binario(num);

 return 0;
}  /*Cierra main */


La ejecución,
[hernandez@localhost Programas]$ ./a.out 

Introduzca un numero entero: 41
1       0       1       0       0       1
Comopuede verse, son muy pocas las líneas que se requieren para hacer la conversión de binario a decimal usando la recursión, y es un cambio mínimo el que hace esta diferencia.

lunes, 29 de abril de 2013

Factoriales y Números de Fibonacci en java.

El siguiente programa en java recibe un número entero positivo. Si el número es par, se imprime el factorial, de lo contrario se imprime el número de fibonacci correspondiente a dicho entero. En los comentarios se esbozan los algoritmos.
Éste archivo debe guardarse con el nombre Main.

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* Programa que recibe un entero positivo y verifica si es par +
* o impar                                                     *
* Si es par                                                   *
*   Se calcula e imprime el factorial del numero              *
* Si es impar                                                 *
*   Se calcula e imprime los primeros n numeros de fibonacci  *
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

import java.util.Scanner;

public class Main
{  // Abre clase Main
public static void main(String args[])
{  // Abre main

int n = 0; // Esta variable almacenara el numero
Scanner entrada = new Scanner(System.in);

while ( 0 >= n )
 // con este condicional while se garantiza que el usuario introduzca numeros positivos.
{  // Abre while
System.out.print("\nPor favor introduzca un numero entero. Si el numero es par ");
System.out.print("se imprimira el factorial, de lo contrario, se imprimiran los primeros n terminos ");
System.out.println("de la serie de Fibonacci. "); 
n = entrada.nextInt();

}  // Cierra while

if ( 0 == n%2 )  // Si el numero es par
System.out.printf("\nEl factorial del numero es: %d\n\n", factorial(n));
else  // Si el numero es impar
fibonacci(n);

}  // Cierra main

///////////////////////////////
//Metodo fibonacci
//////////////////////////////

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *                                                                             *
 *                              ALGORITMO                                      *
 *                              _________                                      *
 *                                                                             *
 * El primer numero de fibonacci (fib1) es 0                                   *
 * El segundo numero de Fibonacci (fib2) es 1                                  *
 *                                                                             *
 * Si el usuario introduce 1 o 2, entonces es necesario desplegar f1 o f2      *
 * Si el usuario introduce un entero positivo mayor que 2, entonces            *
 *     desde 2 hasta n (el numero introducido)                                 *
 *     fibn = fib1 + fib2                                                      *
 *     temp =  fib2                                                            *
 *     fib2 = fibn                                                             *
 *     fib1 = temp                                                             *
 *                                                                             *
 * Imprimir el valor de fibn                                                   * 
 *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

public static void fibonacci( int x)
{  // Abre Metodo fibonacci

int fib1 = 0;
int fib2 = 1;
int fibn;

if (1 != x)
{  // Abre if
System.out.printf("\nEl primer numero de Fibonacci es: %d", fib1);
System.out.printf("\nEl segundo numero de Fibonacci es: %d", fib2);

for ( int i = 3; i <= x; i++ )
{  // Abre for
fibn = fib2 + fib1;
fib1 = fib2;
fib2 = fibn;

System.out.printf("\nEl numero de Fibonacci %d es %d", i, fibn);

}  // Cierra for  
System.out.println();
}  // Cierra if
else
System.out.println("\nEl primer numero de Fibonacci es: 0");


}  // Cierra Metodo fibonacci


/////////////////////////////////////////////////////
//Metodo factorial
/////////////////////////////////////////////////////

/*++++++++++++++++++++++++++++++++++++++++++++++++++*
*                                                   *
* fact = 1;                                         *
* Desde i = 1 hasta i = n                           *
*    fact = fact * i;                               *
*    i  =  i + 1;                                   *
*+++++++++++++++++++++++++++++++++++++++++++++++++++*/

public static int factorial( int n)
{  // Abre metodo factorial
int i; // La variable i servira como contador
int fact = 1; // Esta variable almacena el factorial

for ( i = 1; i <= n; i++ )
fact *= i;

return fact; // El valor de retorno es el factorial
}  // Cierra metodo factorial

}  // Cierra clase Main

Abajo aparece un par de ejecuciones del programa, una con un número par y otra con un número impar.

[hernandez@localhost Programas]$ java Main

Por favor introduzca un numero entero. Si el numero es par, se imprimira el factorial, de lo contrario, se imprimiran los primeros n terminos de la serie de Fibonacci. 
4

El factorial del numero es: 24

[hernandez@localhost Programas]$ java Main

Por favor introduzca un numero entero. Si el numero es par se imprimira el factorial, de lo contrario, se imprimiran los primeros n terminos de la serie de Fibonacci. 
7

El primer numero de Fibonacci es: 0
El segundo numero de Fibonacci es: 1
El numero de Fibonacci 3 es 1
El numero de Fibonacci 4 es 2
El numero de Fibonacci 5 es 3
El numero de Fibonacci 6 es 5
El numero de Fibonacci 7 es 8

viernes, 26 de abril de 2013

El Operador ~ de bits

El operador ~ de bits, también llamado operador de complemento a uno, actúa sobre tipos enteros (char, int, shor, long) a nivel de bits. Lo que hace es cambiar 0 por 1 y viceversa. Por ejemplo, si se tiene el la constante int x = 47 en una representación binaria de 6 bits, 101111, la instrucción ~x da como resultado el número 010000. Hay que tener cuidado antes de apresurarnos a decir cual será el resultado aplicando éste operador en un programa en C. El punto importante aquí es que si nosotros imprimimos el valor actual de x, mediante una instrucción printf, obtendremos -48.

La acción del operador complemento a uno
Sea el siguiente programa


/*+++++++++++++++++++++++++++++++++++++++++++++
 * Este programa cambia un numero sin sigo a  +
 * su complemento a uno a nivel de bits       +
 * ++++++++++++++++++++++++++++++++++++++++++*/

#include 

int main()
{  /* Abre main*/
unsigned contador;
unsigned x;
unsigned temporal;

printf("\nIntroduzca un número: ");
scanf("%d", &x);

temporal = ~x;

printf("\nEl complemento a uno de %d es: %d\n", x, temporal);

printf("\nEl valor final de x: %d\n", x);

return 0;
}  /* Cierra main*/

Una ejecución con 47 como entrada es la siguiente:


Introduzca un número: 47

El complemento a uno de 47 es: -48

El valor final de x: 47

Si las computadoras representaran los enteros con signo mediante el complemento a 1, el número al aplicar ~x sería -47, sin embargo, las computadoras almacenan los enteros con signo mediante la representación en complemento a dos. En ésta entrada hay más información al respecto.

miércoles, 24 de abril de 2013

El operador & de bits

El operador &, llamado AND de bits, compara dos números de tipo entero (int, short, long, char) bit por bit, dando por resultado un tercer número, que se forma al colocar un 0 ó 1 en el bit correspondiente a la comparación realizada de acuerdo con la siguiente regla: si los dos bits son iguales a 1, entonces se obtiene 1, de otra forma se obtiene un 0. Sean, por ejemplo, los números 19 y 25, que en representación binaria de 5 bits se escriben 19 = 1 0 0 1 1, 25 = 1 1 0 0 1. Si se realiza la comparación, se verá que los bits de la derecha son los dos iguales a 1, por lo tanto el número resultante tendrá un 1 en el bit de la extrema derecha. De manera similar, el segundo bit de 19 tiene un 1, en tanto que el de 25 tiene un 0, el resultado, por lo tanto, es 0. La comparación completa aparece en la figura de abajo.

El operador lógico & de bits.
El operador & también es utilizado para hacer referencia a una localidad de memoria,por ejemplo en la función scanf. Los usuarios de C++, que utilizan un lenguaje orientado a objetos, le llamarían a ésto una sobrecarga: el mismo operador se utiliza en situaciones distintas para realizar distintas tareas. La razón por la cual & no puede operar sobre tipos flotantes es porque la representación de números enteros es distinta a la de los tipos float. El programa que aparece abajo hace uso de el operador de bits &.

/*+++++++++++++++++++++++++++++++++++++++*
*Este programa recibe un par de numeros  *
*e imprime el resultado de aplicarles el *
*operador binario &                      *
*+++++++++++++++++++++++++++++++++++++++*/

#include 

int main()
{   /*Abre main*/
 int x; 
 int y;
 
 printf("\nEste programa hace uso del operador binario &\n");
 printf("\nIntroduzca un entero: ");
 scanf("%d", &x);
 printf("\nIntroduzca un segundo entero: ");
 scanf("%d", &y);

 printf("\n%d & %d = %d\n", x, y, x&y);

 return 0;
}   /*Cierra main*/

Una ejecución del programa, co los números 19 y 25 es:

Este programa hace uso del operador binario &                                        
                                                                                     
Introduzca un entero: 19                                                             
                                                                                     
Introduzca un segundo entero: 25                                                     
                                                                                     
19 & 25 = 17  

En ocasiones es conveniente fijar una constante entera mediante un número binario, por ejemplo para crear una máscara de bits. La forma de hacer ésto en C es escribiendo la constante en sistema de numeración octal o en hexadecimal. Toda constante que es precedida por un 0, como 0177, es tomada como una cantidad octal (127 en éste caso); en tanto que las cantidades precedidas de 0x ó 0X, como 0x7F (también igual al 127 decimal) son cantidades hexadecimales. En particular el número 0x7F se representa, en notación binaria, como 01111111 por lo cual, una instrucción como x & 0x7F, hará 0 todos los bits de x, salvo los primeros 7 de la derecha.

miércoles, 13 de febrero de 2013

Dale-Weems _3_1 (El volumen de un cono en C++)

A continuación presento unos ejercicios del libro de programación de Nale Cale y Chip Weems, cuarta edición: Programación y resolución de problemas con C++, que aparecerán en la etiqueta Dale - Weems.
_______________________________________________________________________________________
3.1 Escriba un programa en C++ que calcule y produzca elvolumen de un cono, dados el diámetro de su base y su altura. La fórmula para calcular el volumen del cono es:
(1/3)*Radio*Radio*Altura
Asegúrese de usar el formato y comentarios apropiados en su código. La salida debe ser etiquetada de manera clara.
_______________________________________________________________________________________
Solución:

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*  Este programa calcula e imprime el volumen de un cono  +
*                                                         +  
*  Lo que recibe:                                         +
*   - Diametro de la base                                 +
*   - Altura                                              +
*                                                         +
*  Lo que devuelve:                                       +
*   - El volumen                                          +
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 *                      ALGORITMO                         +
 *                                                        +
 * Recibir el diametro de la base.                        +
 * Recibir la altura                                      +
 *                                                        +
 * radio = diametro/2                                     +
 * volumen = (1/3)radio*radio*altura                      +
 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include<iostream>
using namespace::std;

int main()

{  /* Abre main*/
/* Se declaran los datos */
float diametro, radio, altura, volumen;

/* Se reciben los datos */
cout <<"\nEste programa calcula el volumen de un cono."<<endl;
cout<<"Por favor introduzca el diametro de la base: " << endl;
cin >> diametro;

cout<<"Por favor introduzca la altura del cono: " << endl;
cin >> altura;

/*Se calcula el volumen */
radio = diametro/2;
volumen = ((float)1/3)*radio*radio*altura;

cout <<"\nEl radio del cono es: " <<radio<< endl;
cout <<"\nLa altura del cono es: " <<altura<< endl;
/*Se imprime el resultado*/
cout <<"\nEl volumen del cono es: " <<volumen << endl;

return 0;
}  /* Cierra main*/

_______________________________________________________________________________________
Éste programa hace uso de la fórmula dada en el enunciado, y lo único en lo que hay que tener cuidado es en la sintaxis correcta.
La línea

volumen = ((float)1/3)*radio*radio*altura;

es importante. Aquí se hace una conversión explícita del numerador en la fracción 1/3. De no hacerse, la división de enteros se trunca a 0. Basta con convertir el numerador (o el denominador) para que la fracción sea un número flotante.
Aquí una ejecución del programa:

Este programa calcula el volumen de un cono.
Por favor introduzca el diametro de la base: 
3
Por favor introduzca la altura del cono: 
4

El radio del cono es: 1.5

La altura del cono es: 4

El volumen del cono es: 3

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.

miércoles, 10 de octubre de 2012

Deitel_C++_5.18 (Construyendo la Computadora Simpletron)

SECCIÓN ESPECIAL: CONSTRUYA SU PROPIA COMPUTADORA
_____________________________________________________________________________________
En los siguientes problemas nos desviaremos temporalmente del mundo de la programación en lenguajes de alto nivel para "abrir de par en par" una computadora y ver su estructura interna. Presentaremos la programación en lenguaje máquina y escribiremos varios programas en este lenguaje. Para que ésta sea una experiencia valiosa, crearemos también una computadora (mediante la técnica de la simulación basada en software) en la que pueda ejecutar sus programas en lenguaje máquina.
_____________________________________________________________________________________
5.18 (Programación en Lenguaje Máquina) Crearemos una computadora a la que llamaremos Simpletron. Como su nombre lo indica, es una máquina simple, pero poderosa. Simpletron sólo ejecuta programas escritos en el único lenguaje que entiende directamente: el lengaje máquina de Simpletron, o LMS.
Simpletron contiene un acumulador, un registro especial en el cual se coloca la información antes de que Simpletron la utilice en los cálculos, o que la analice de distintas maneras. Toda la información dentro de Simpletron se manipula en términos de palabras. Una palabra es un número decimal con signo de cuatro dígitos, como +3364, -1293, +0007 y -0001. Simpletron está equipada con una memoria de 100 palabras, y se hace referencia a estas palabras mediante sus números de ubicación 00, 01, ..99.
Antes de ejecutar un programa LMS debemos cargar, o colocar, el programa en la memoria. La primera instrucción de cada programa LMS se coloca siempre en la ubicación 00. El simulador empezará a ejecutarse en esta ubicación. Cada instrucción escrita en LMS ocupa una palabra de la memoria de Simpletron (y, por lo tanto, las instrucciones son números decimales de cuatro dígitos con signo). Supondremos que el signo de una instrucción LMS siempre será positivo, pero el signo de una palabra de información puede ser positivo o negativo. Cada una de las ubicaciones en la memoria de Simpletron puede contener una instrucción, un valor de datos utilizado por un programa o un área no utilizada (y, por lo tanto, indefinida) de memoria. Los primeros dos dígitos de cada instrucción LMS son el código de operación que especifica la operación a realizar. Los códigos de operación de LMS se sintetizan en la figura siguiente.

_________________________________________________________________________________________________________
CÓDIGO DE OPERACIÓN                       SIGNIFICADO
_________________________________________________________________________________________________________

Operaciones de entrada/salida
_________________________________________________________________________________________________________

final int LEE = 10;                       Lee una palabra desde el teclado y la introduce en una 
                                          ubicación específica de memoria.

final int Escribe = 11:                   Escribe una palabra de una ubicación específica de memoria
                                          y la imprime en la pantalla.
_________________________________________________________________________________________________________

Operaciones de carga/almacenamiento
_________________________________________________________________________________________________________
final int CARGA = 20;                     Carga una palabra de una ubicación específica de memoria y 
                                          la coloca en el acumulador.

final int ALMACENA = 21;                  Almacena una palabra del acumulador dentro de una ubicación
                                          específica de memoria.
_________________________________________________________________________________________________________
Opoeraciones aritméticas
_________________________________________________________________________________________________________
final int SUMA = 30;                      Suma una palabra de una ubicación específica de memoria a la
                                          palabra en el acumulador (deja el resultado en el acumulador).

final int RESTA = 31;                     Suma una palabra de una ubicación específica de memoria a la
                                          palabra en el acumulador (deja el resultado en el acumulador).

final int DIVIDE = 32;                    Divide una palabra de una ubicación específica de memoria a la
                                          palabra en el acumulador (deja el resultado en el acumulador).

final int MULTIPLICA                      Multiplica una palabra de una ubicación específica de memoria a la
                                          palabra en el acumulador (deja el resultado en el acumulador).
_________________________________________________________________________________________________________

Operaciones de transferencia de control
_________________________________________________________________________________________________________
final int BIFURCA = 40;                   Bifurca hacia una ubicación específica de memoria.

final int BIFURCANEG = 41;                Bifurca hacia una ubicación específica de memoria si el 
                                          acumulador es negativo.

final int BIFURCACERO = 42;               Bifurca hacia una ubicación específica de memoria si el 
                                          acumulador es cero.

const int ALTO = 43;                      Alto. El programa completó su tarea.
__________________________________________________________________________________________________________

Los dos últimos dígitos de una instrucción LMS son el operando (la dirección de la ubicación en memoria que contiene la palabra a la cual se aplica la operación). Consideremos varios programas simples en LMS.

El primer programa en LMS, figura siguiente, lee dos números del teclado, cualcula e imprime su suma. La instrucción +1007 lee el primer número del teclado y lo coloca en la ubicación 07 (que se ha inicializado con 0). Después, la instrucción +1008 lee el siguiente número y lo coloca en la ubicación 08. La instrucción carga, +2007, coloca el primer número en el acumulador y la instrucción suma, +3008, suma el segundo número al número en el acumulador. Todas las instrucciones LMS aritméticas dejan sus resultados en el acumulador. La instrucción almacena, +2109, coloca el resultado de vuelta en la ubicación de memoria 09, desde la cual la instrucción escribe, +1109, toma el número y lo imprime (como un número decimal de cuatro dígitos con signo). La instrucción alto, +4300, termina la ejecución.

Ubicación         Número               Instrucción
00                +1007                (Lee A)
01                +1008                (Lee B)
02                +2007                (Carga A)
03                +3008                (Suma B)
04                +2109                (Almacena C)
05                +1109                (Escribe C)
06                +4300                (Alto)
07                +0000                (Variable A)
08                +0000                (Variable B)
09                +0000                (Resultado C)

El segundo programa en LMS (figura siguiente) lee dos números desde el teclado, determina e imprime el valor más grande. Observe el uso de la instrucción +4107 como una transferencia de control condicional, en forma muy similar a la instrucción if de Java.

Ubicación         Número               Instrucción
00                +1009                (Lee A)
01                +1010                (Lee B)
02                +2009                (Carga A)
03                +3110                (Resta B)
04                +4107                (Bifurcación negatuva a 07)
05                +1109                (Escribe A)
06                +4300                (Alto)
07                +1110                (Escribe B)
08                +4300                (Alto)
09                +0000                (Variable A)
10                +0000                (Variable B)

Ahora escriba un programa en LMS para realizar cada una de las siguientes tareas:

a) Usar un ciclo controlado por centinela para leer 10 números positivos. Calcular e imprimir la suma.
b) Usar un ciclo controlado por contador para leer siete números, algunos positivos y otros negativos, y calcular e imprimir su promedio.
c) Leer una serie de números, determinar e imprimir el número más grande. El primer número leído indica cuántos números deben procesarse.
_____________________________________________________________________________________
SOLUCIÓN:
a) Usar un ciclo controlado por centinela para leer 10 números positivos. Calcular e imprimir la suma.

Ubicacion         Numero               Instruccion
00                +1015                Lee el primer numero y lo almacena en la localidad 15
01                +2015                Carga el numero almacenado en 15
02                +4004                Bifurcacion positiva a la localidad 04
03                +4300                Para
04                +1016                Lee un segundo numero y lo almacena en la localidad 16
05                +2016                Carga el numero de la localidad 16
06                +4009                Bifurcacion positiva a 09
07                +1115                Imprime el numero de la localidad 15
08                +4300                Para
09                +3015                Suma el numero de la localidad 15
10                +2115                Almacena la suma en la localidad 15
11                +1016                Lee otro numero y lo almacena en la localidad 16
12                +4009                Bifurcacion positiva a 09
13                +1115                Imprime el numero almacenado en 15
14                +4300                Para
15                +0000                Variable
16                +0000                Variable

1) Recibe un número y para si es negativo (00 a 03) Si el número es positvivo, se guarda en la variable Suma.
2) Recibe un segundo número y si es negativo, se imprime Suma y se para (04-08) Si el número es positivo, se suma a la variable Suma.
3) Se realiza el ciclo hasta que se recibe un número negativo (09-12)
4) Se imprime la suma y se detiene la ejecución (13-14)
5) Variables (15 y 16)

b) Usar un ciclo controlado por contador para leer siete números, algunos positivos y otros negativos, y calcular e imprimir su promedio.

Ubicacion         Numero               Instruccion
00                +1020                Lee un numero y lo almacena en la localidad 20
01                +2020                Carga el numero almacenado en 20
02                +4100                Bifurcacion negativa a la localidad 00
03                +2020                Carga el numero almacenado en 20
04                +4200                Bifurcacion 0 a la localidad 00

05                +1024                Lee un numero y lo almacena en la localidad 24
06                +2024                Carga el valor almacenado en la localidad 24
07                +3023                Suma el valor de la localidad 23 al acumulador
08                +2123                Almacena la suma en la localidad 23

09                +2121                Carga el valor almacenado en 21
10                +2022                Suma el valor de la localidad 22
11                +2121                Almacena la suma en la localidad 21

12                +2021                Se carga el valor de la localidad 21
13                +3120                Se resta el valor almacenado en la localidad 20
14                +4005                Si la diferencia es positiva, bifurca a la localidad 05

15                +2021                Carga la variable de la localidad 21
16                +3223                Se divide el contenido de 18 entre el contenido en el acumulador
17                +2125                Se almacena el resultado en la localidad 25
18                +1125                Se Imprime el resultado
19                +4300                Para


20                +0000                Limite
21                +0000                Contador (Inicializado en 0)
22                +0000                Uno (Inicializado en uno)
23                +0000                Suma (Inicializado en 0)
24                +0000                Variable

Éste es el programa. No recibe 7 números, sino cualquiera que el usuario introduzca al principio. Por lo demás, el procedimiento es igual para 7 o para cualquier número N. Se requiere una variable que haga las veces de contador, en la localidad 21, inicializada en 0. Esta variable se incrementa cada vez que se realiza el ciclo. El incremento es siempre en uno, y se hace sumando la constante uno almacenada en la localidad 22. También es necesaria otra variable más, llamada suma, localizada en la localidad 23, la cual se inicia con el valor 0 y se incrementa cada vez con el valor del número recibido.
El programa consta de 6 partes, separadas por espacios para hacer más visible esta división. Éstas partes son:
1) Recepción del límite ( de la localidad 00 a la 04) Verifica que el primer número (el que indica cuántos enteros se recibirán) sea positivo. Para ésto, primero se revisa que no sea negativo; si lo es, el control se regresa al inicio, a la localidad 00. Después de ésto, se verifica que el número sea distinto de 0. Si lo es, de nuevo se regresa el control a la localidad 00.
2) Suma del número. (De las localidades 05 a 08) Recibe un número y lo suma al contenido de la variable suma, la cual, inicialmente tiene el valor 0.
3) Incremento del contador (De las localidades 09 a 11) Para incrementar la viariable Contador, almacenada en la localidad 21, se hace uso de la constante Uno, almacenada en la localidad 22.
4) Verificación de la condición para verificar que Contador no haya superado a Límite, se resta el primero del segundo. En caso de que el resultado no sea positivo (esto incluye 0 o un número negativo), se termina el ciclo, de lo contrario, se transfiere el control a 05.
5) Impresión de los resultados (de la localidad 15 a la 19) En estas instrucciones se divide la Suma entre el Límite y se presenta el resultado.
6) Variables (Localidades 20 a 25) En esta sección se almacenan las variables a las que se hace referencia en el programa.

c) Leer una serie de números, determinar e imprimir el número más grande. El primer número leído indica cuántos números deben procesarse.

Ubicacion         Numero               Instruccion
00                +1026                Lee un numero y lo almacena en la localidad 26
01                +2026                Carga el numero almacenado en 26
02                +4100                Bifurcacion negativa a la localidad 00
03                +2026                Carga el numero almacenado en 26
04                +4200                Bifurcacion 0 a la localidad 00

05                +1024                Lee un numero y lo almacena en la localidad 24

06                +2025                Carga el valor almacenado en la localidad 25
07                +3126                Resta el valor almacenado en 26
08                +4221                Bifurcacion cero (transferencia de control) a la localidad 21

09                +1023                Recibe un número y lo almacena en 23

10                +2024                Carga el numero de la localidad 24
11                +3123                Resta el número de la localidad 23
12                +4015                Bifurca positivo a la localidad 15

13                +2023                Carga el número almacenado en la localidad 23
14                +2124                Almacena el número en la localidad 24

15                +2025                Carga la variable de la localidad 25
16                +3027                Suma el contenido de la localidad 27
17                +2125                Se almacena el resultado en la localidad 25

18                +2025                Se carga el contenido de la localidad 25
19                +3126                Se resta el contenido de la localidad 26
20                +4109                Bifurca negativo a la lodalidad 09

21                +1124                Imprime la localidad 24
22                +4300                Para

23                +0000                Numero
24                +0000                Mayor
25                +0000                Contador (Inicializado a 1)
26                +0000                Limite
27                +0000                Uno (Inicializado a 1) (Inicializado en 0)

También éste programa ha sido dividido en partes para su mejor comprensión.
1) Recepción del límite ( 00 a 04) Ésta variable indica cuántos números se recibirán. No se aceptan negativos ni 0.
2) Recepción del primer número (05) Éste número, por ser el primero, se almacena en la variable Mayor, localidad 24.
3) Primera verificación del límite (06-08) En caso de que el límite sea sólo 1 número, éste condicional lleva el control a la localidad 21.
4) Recepción de número (09) Si el límite es 2 o más, se recibe el siguiente número y se almacena en la variable Número (localidad 23).
5) ¿Es más grande Mayor o Número? (10 a 12) Si Mayor - Número > 0, entonces el control se transfiere a la localidad 15, de lo contrario se lleva a cabo las instrucciones siguientes.
6) Mayor = Número (13-14) Estas líneas asignan un nuevo valor a la variable Mayor.
7) Incremento del contador (15-17) Éste incremento hace uso de la variable Uno, la cual se inicializa en 1.
8) Verificación del contador (18- 20) Si Contador - limite es negativo, se transfiere el control a la localidad 9. De lo contrario (una diferencia igual a 0), se realiza la siguiente instrucción.
9) Se imprime el número Mayor y se termina el programa (21-22) Esta instrucción se realiza cualesquiera que sean las transferencias de control anteriores.
10) Variables (23-27) La variable Número almacena los sucesivos números que se introducen. La variable Mayor almacena siempre el mayor, Contador debe ser inicializado a 0, Límite se recibe del usuario al principio, y Uno debe inicializarse a 1.
Related Posts Plugin for WordPress, Blogger...