jueves, 30 de junio de 2011

ANSI C: Introducción

En este post iniciaremos un interesante recorrido para aprender aspectos básicos acerca del lenguaje ANSI C. Los posts publicados respecto a este tema se apegan al curso de verano que actualmente está impartiendo la Dra. Elisa Schaeffer en la Universidad Autónoma de Nuevo León.

De acuerdo con Wikipedia, se le llama ANSI C a la familia de estándares para el lenguaje C que ha publicado la ANSI (American National Standards Institute), organización no lucrativa encargada de supervisar la creación de estándares para productos, servicios, procesos, sistemas o personal en los Estados Unidos y a nivel mundial.

¿Por qué es importante utilizar un estándar para programar?

Un estándar es un consenso al que se ha llegado para poder estar de acuerdo con respecto a algo. En el caso de la programación, es importante que todos los programadores tengan un punto de referencia para poder crear programas que se comporten de la misma manera (o casi de la misma manera) sin importar el equipo o la región geográfica donde se ejecuten. Quizá esto no parezca gran cosa si se piensa en programas muy sencillos, pero en el desarrollo de sistemas que manejan gran cantidad de datos o que requieren de operaciones que involucran una gran precisión, saber exactamente cómo se espera que se comporten puede ser vital. Un par de ejemplos de lo anterior podrían ser las aplicaciones bancarias que trabajan con números muy grandes que representan el manejo del dinero de sus clientes donde un error en el manejo de estas cantidades podría representar pérdidas millonarias, o en la milicia, cuando se desea guiar un misil, la precisión en las coordenadas de su lanzamiento puede tener consecuencias mortales si éste termina cayendo en el punto equivocado

Si deseas saber más respecto a este curso, visita su página, donde además puedes encontrar material adicional y el código fuente que se explica en cada sesión.

sábado, 4 de junio de 2011

Problemas que se resuelven por sistemas de ecuaciones lineales

Tal vez una de las aplicaciones más importantes de los sistemas de ecuaciones lineales se encuentra en la resolución de problemas a través de éstos. Resolver un problema de esta naturaleza no es tarea sencilla, pero existen algunas consideraciones que pueden hacer esta tarea un poco más clara.

Para explicar estas consideraciones, utilizaré el siguiente ejemplo:

Un videoclub está especializado en películas de tres tipos: infantiles, oeste americano y terror. Se sabe que:

El 60% de las películas infantiles más el 50% de las del oeste representan el 30% del total de las películas.

El 20% de las infantiles más el 60% de las del oeste más del 60% de las de terror representan la mitad del total de las películas.

Hay 100 películas más del oeste que de infantiles.

Halla el número de películas de cada tipo.

1. Identificar las incógnitas para poder establecer el número de ecuaciones que se deben plantear para resolver el problema:

En este caso, se tienen tres incógnitas:

  1. Películas infantiles (que representaré con la letra “f”)
  2. Películas del oeste americano (letra “a”)
  3. Películas de terror (letra “r”)

Para representar las incógnitas es preferible elegir letras que no se confundan fácilmente con números.

Podemos ver en este caso que se trata de tres incógnitas, por lo tanto debemos plantear un sistema de tres ecuaciones.

2. Plantear las ecuaciones de acuerdo con la información proporcionada por el problema:

Empecemos a analizar el primer enunciado que proporciona información acerca del problema: “El 60% de las películas infantiles más el 50% de las del oeste representan el 30% del total de las películas”. Primero, para representar los porcentajes podemos utilizar fracciones (por ejemplo el 60% quedaría como 60/100 o su equivalente: 6/10) o decimales (el mismo 60% lo representaríamos como 0.6). En este caso yo elegí decimales, por lo que el 60% de las películas infantiles quedaría como 0.6f y el 50% de las del oeste quedaría como 0.5a (de acuerdo con las letras que elegí para representar cada tipo de película en el paso 1). Segundo, cuando se habla del total de algo, significa que se debe hacer una suma de elementos, en este caso, se habla del total de películas, eso quiere decir que todas las películas del videoclub están conformadas por la suma de películas infantiles, del oeste y de terror, es decir: el total de las películas es igual a f + a + r, como se especifica que se necesita el 30% de este total, entonces este 30% se representaría de esta manera: 0.3(f + a + r) por lo tanto, la primera ecuación la planteamos como sigue:

1) 0.6f + 0.5a = 0.3(f + a + r)

El segundo enunciado dice: “El 20% de las infantiles más el 60% de las del oeste más del 60% de las de terror representan la mitad del total de las películas”. Siguiendo la misma lógica, el 20% de las infantiles las representamos como 0.2f, el 60% de las del oeste como 0.6a y el 60% de las de terror como 0.6r. Ahora bien, cuando se hable de la mitad de algo, esto puede expresarse como ½ de algo, algo dividido entre dos, o en este caso interpretarlo como el 50% para ser consistentes en el planteamiento de la ecuación y evitar confusiones. Y como nuevamente se nos presenta el total de las películas, entonces la mitad del total de las películas lo representamos como: 0.5(f + a + r). Por lo tanto, la segunda ecuación del sistema es la siguiente:

2) 0.2f + 0.6a + 0.6r = 0.5(f + a + r)

El tercer enunciado dice: “Hay 100 películas más del oeste que de infantiles”. Este es un enunciado muy fácil de interpretar, únicamente quiere decir que para igualar el número de películas infantiles con el número de películas del oeste, por ejemplo, podemos sumar 100 a las infantiles, esto es:

3) a = f + 100

Y esta sería la tercera ecuación.

En resumen, nuestro sistema de ecuaciones sería este:

  1. 0.6f + 0.5a = 0.3(f + a + r)
  2. 0.2f + 0.6a + 0.6r = 0.5(f + a + r)
  3. a = f + 100

3. Resolver el sistema de ecuaciones planteado en el paso 2.

En este caso en la ecuación 3, ya tenemos una de las incógnitas (la letra “a”) igualada a algo (f + 100). Esta información se puede utilizar para sustituir a la letra “a” por “f + 100” en las otras dos ecuaciones y reducir el sistema de tres ecuaciones a un sistema de dos ecuaciones con dos incógnitas como a continuación:

  1. 0.6f + 0.5(f + 100) = 0.3(f + (f + 100) + r)
  2. 0.2f + 0.6(f + 100) + 0.6r = 0.5(f + (f + 100) + r)

Realizando las operaciones con “f + 100”:

  1. 0.6f + 0.5f + 50 = 0.3(2f + 100 + r)
  2. 0.2f + 0.6f + 60 + 0.6r = 0.5(2f + 100 + r)

Y finalmente realizando las multiplicaciones a la derecha del signo igual y reduciendo términos semejantes, obtenemos el siguiente sistema:

  1. 0.5f + 20 -0.3r = 0
  2. –0.2f + 10 + 0.1r = 0

Podemos realizar un despeje. Yo elegí a “r” de la ecuación 2:

r = (0.2f – 10)/0.1 (los paréntesis indican que tanto 0.2f como 10 se dividen entre 0.1)

Ahora bien, podemos aprovechar el hecho de que 0.1 = 1/10 para simplificar esta expresión:

r = (0.2f – 10)/(1/10) (usé paréntesis para evitar confusiones a la hora de escribir el 1/10)

Aplicando la regla “del sándwich”, entonces obtenemos que:

r = 2f – 100

Y si sustituimos a “r” en la ecuación 1 de nuestro sistema de dos ecuaciones tenemos:

0.5f + 20 – 0.3(2f – 100) = 0

Resolviendo las operaciones:

0.5f + 20 – 0.6f + 30 = 0

Y simplificando:

–0.1f + 50 = 0

Por lo tanto:

–0.1f = –50

Y finalmente:

f = –50/(–0.1)

f = –50/(–1/10) (teniendo en cuenta nuevamente que –0.1 = –1/10)

Nuevamente aplicando la regla “del sándwich”:

f = 500

Ahora sustituimos a “f” en r = 2f -100 y obtenemos a “r”:

r = 2(500) – 100

r = 1000 – 100

r = 900

Y también podemos obtener a “a” (de la ecuación 3 del sistema de ecuaciones original):

a = f + 100

a = 500 + 100

a = 600

4. Comprobar los resultados.

Ahora ya sabemos que:

f = 500

r = 900

a = 600

Podemos sustituir estos valores en las ecuaciones originales para comprobar que éstas se cumplen:

Para la primera ecuación:

0.6f + 0.5a = 0.3(f + a + r)

0.6(500) + 0.5(600) = 0.3(500 + 600 + 900)

0.6(500) + 0.5(600) = 0.3(2000)

Resolviendo las operaciones de multiplicación:

300 + 300 = 600

600 = 600

Por lo tanto, para la primera ecuación estos resultados son correctos. Ahora debemos verificar la siguiente:

0.2f + 0.6a + 0.6r = 0.5(f + a + r)

0.2(500) + 0.6(600) + 0.6(900) = 0.5(500 + 600 + 900)

0.2(500) + 0.6(600) + 0.6(900) = 0.5(2000)

Resolviendo las multiplicaciones:

100 + 360 + 540 = 1000

1000 = 1000

Por lo tanto con estos resultados, la segunda ecuación sí se cumple. Para la tercera ecuación tenemos entonces que:

a = f + 100

600 = 500 + 100

600 = 600

Podría parecer que esta última comprobación no es necesaria, sin embargo, la realicé debido a que SIEMPRE se deben comprobar todas las ecuaciones del sistema planteado.

5. Finalmente, una vez que comprobamos las soluciones y estamos seguros de que son correctas, entonces expresamos la respuesta al problema en forma de enunciado:

En el videoclub existen 500 películas infantiles, 600 películas del oeste americano y 900 películas de terror.

martes, 10 de mayo de 2011

Teoría de las Telecomunicaciones tema 5.3: Internet

En este post se encuentra el material que se utilizó durante la exposición del tema 5.3 (Internet) en la materia de Teoría de las Telecomunicaciones del Instituto Tecnológico de Toluca para la carrera de Ingeniería en Sistemas Computacionales.

El material está conformado por las diapositivas de la exposición y un documento que contiene el marco teórico sobre el cual se realizaron dichas diapositivas.

Descargar diapositivas

Descargar documento

domingo, 8 de mayo de 2011

Java: Operadores Incremento/Decremento

Los operadores de pre/post-incremento/decremento pueden ser fuente de confusión a pesar de lo simples que parecen. ¿Qué imprime el siguiente fragmento de código?

  int i = 10, k = 10, x;
  x = (i++*--k) + (i++*--k);
  System.out.println("x=" + x + ",i=" + i + ",k=" + k); 

Hasta donde entendía, los operadores de pre-incremento/decremento se ejecutan antes de evaluar la expresión completa y los de post-incremento/decremento después de evaluar la expresión completa. En nuestro ejemplo, yo pensé que los "--k" eran ejecutados primero, dejando k=8. Después se ejecutaban las operaciones, x = (10*8) + (10*8) = 160. Y por último incrementamos dos veces i, es decir i=12. Para mi sorpresa, el resultado fue: x=178,i=12,k=8.

Esto despertó mi curiosidad de ver lo que realmente estaba ejecutando la máquina virtual de java. Para ello, utilicé el comando javap para obtener una versión más amigable del bytecode que se encuentra en los archivos .class. La siguiente tabla muestra del lado izquierdo la salida de javap y del lado derecho una versión más fácil de leer.

Pasojavap 
1bipush 10
istore_0
i=10
2bipush 10
istore_1
k=10
3iload_0i_temp = i = 10
4iinc 0, 1i=11
5iinc 1, -1k=9
6iload_1k_temp = k = 9
7imulsumando_1 = i_temp * k_temp = 90
8iload_0i_temp = i = 11
9iinc 0, 1i = 12
10iinc 1, -1k = 8
11iload_1k_temp = k = 8
12imulsumando_2 = i_temp * k_temp = 88
13iaddsuma = sumando_1 + sumando_2 = 178
14istore_2x = suma = 178

Observen en el paso 7, que el primer sumando es calculado usando variables temporales (siendo más precisos, es un stack de operandos que usa la JVM). De hecho, en los pasos 3 al 6 se guardan los valores de i y k en el stack de operandos y también se realiza su respectiva operación de post-incremento y pre-decremento. La diferencia es que para i, primero se copia su valor en el stack de operandos y luego se incrementa; y para k, primero se decrementa su valor y después se copia en el stack.

Al momento de ejecutar el paso 7, las dos variables i(11) y k(9) ya fueron modificadas. Los pasos 8-12 son similares a los pasos 3-7. Por último, en los pasos 13-14 se calcula y se guarda el resultado final. Es importante notar que las operaciones de pre/post-incremento/decremento afectan a su operando conforme van siendo evaluadas dentro de una expresión más compleja. La única diferencia entre pre y post es si el valor del operando se copia al stack de operandos antes o depués de ser modificado. Sin embargo, subsequentes ocurrencias de la misma variable dentro de la expresión verán el valor modificado (por ejemplo, la segunda ocurrencia de i o k en la expresión anterior.)

Como ejercicio, ¿cuál es el valor de r al ejecutar la siguiente operación?

  int x = 10;
  int r = ++x * x++ * x

Es claro que los operadores de pre/post-incremento/decremento pueden ser fuente de confusión, tal vez esa es una razón por la cual el lenguaje Python no contiene estos operadores. ¿Qué opinan? ¿Qué resultado obtuvieron en el ejercicio anterior?

Ubuntu como mi Sistema Operativo Primario

Este es el resumen de nuestra experiencia al cambiar de Windows a Ubuntu. En el primer post hablamos de los preparativos para la instalación, el porqué tuvimos que realizar una instalción de cero para poder particionar el disco duro a la medida y del pequeño detalle que tuvimos con la tarjeta de red inalámbrica. En el segundo post presentamos Ninite, una aplicación muy útil para instalar varias aplicaciones en Windows con un solo instalador. En el siguiente post presentamos una lista de aplicaciones que usamos en Windows y sus equivalentes en Ubuntu, como pudimos ver muchas de las aplicaciones ya tienen implementaciones para ambas plataformas. En el cuarto post compartimos unos links para poder compartir fólders con Samba y de cómo montar una partición NTFS automáticamente al reiniciar Ubuntu. En el último post dimos los toques finales a Ubuntu, configuramos: atajos del teclado, autokey para expandir texto, la responsividad de los paneles y la terminal de comandos.

Este viernes me apareció la notificación para actualizar a Ubuntu 11.04 y al parecer la actualización fue correcta. Intenté utilizar la interfaz por default: Unity. La barra para lanzar aplicaciones está muy bien; sin embargo, la falta de personalización de la barra donde está el menú global no me convenció. Por el momento regresé a Gnome (sin Unity), esto lo pueden hacer al momento de autenticarse, después de seleccionar su usuario en la parte inferior hay un menú donde pueden elegir Ubutu Clásico.

Esperamos que los tips y los links a lo largo de esta serie sean de ayuda. Si tienen más tips, aplicaciones o comentarios acerca de Ubuntu 11.04 compártanlos en los comentarios o aún mejor comenten en Facebook.

martes, 3 de mayo de 2011

Presentación: Manejo de imagenes, animaciones y video en Java

En este apartado se encuentra el enlace para obtener la presentación acerca de los subtemas 5.3, 5.4 y 5.5 de la materia de Tópicos Selectos de Programación en el Instituto Tecnológico de Toluca.

El enlace conduce a un repositorio público en la página de bitbucket desde donde podrán descargar los ejemplos vistos durante la exposición así como la presentación, que contiene las referencias del material consultado.

https://bitbucket.org/

INSTRUCCIONES: En la caja de texto de la esquina superior derecha, donde dice "find a project", busquen el repositorio llamado ejmtema5.4, éste fue creado por el usuario LuisBV. A continuación, den clic sobre el nombre del repositorio y en la pestaña "get source" podrán descargar una versión comprimida del contenido del repositorio (es decir, la presentación más los proyectos de ejemplo).

NOTA: Para los ejemplos de video, deberán descargar la API de Java Media Framework (JMF) de la siguiente página (en este sitio también se encuentran las instrucciones para instalar dicha API): http://www.oracle.com/technetwork/java/javase/download-142937.html

Comprueben que su instalación de JMF es correcta ingresando al siguiente sitio: http://ku-prism.org/virtualprism/explorations/JavaTest/javatestpage.html

viernes, 22 de abril de 2011

Personalizando Gnome y la Terminal

Hasta el momento he estado usando Ubuntu durante cuatro meses como mi sistema operativo principal. En esta última parte de la serie, mostraré algunas configuraciones que realicé al escritorio y a la terminal para hacer más cómodo el usar Ubuntu.

Atajos del teclado.

Para hacer la navegación más eficiente y rápida es importante familiarizarse con algunos atajos. Uno de mis favoritos es Ctrl + Alt + Flecha izquierda o derecha para cambiar entre los distintos escritorios o Shift + Ctrl + Alt + Flecha izquierda o derecha para mover la ventana activa a otro escritorio. En la siguiente liga podrán encontrar varios atajos:

https://help.ubuntu.com/community/KeyboardShortcuts

Otra forma de acelerar las tareas es tener atajos a programas o carpetas usadas frecuentemente, para ello usé la utilería de atajos que proporciona Gnome en System > Preferences > Keyboard Shortcuts. Tengo atajos para abrir Chrome, NetBeans, Rhythmbox, la terminal de comandos, entre otros.

El toque final en cuanto atajos es el poder expandir texto. Actualmente estoy realizando varias pruebas con Java, por lo que dos líneas de código que tecleo una y otra vez son:

public static void main(String[] args){}
System.out.println("");

Para ahorrar tiempo, usé AutoKey. Este programa me permite configurar abreviaturas que se expanden por el texto que especifiquemos. Por ejemplo, para las dos líneas anteriores creé dos abreviaturas jmain y jpr. También configuré que AutoKey iniciara al reiniciar Ubuntu.

Responsividad de los paneles

Prefiero que los paneles permanezcan ocultos y que sólo aparezcan cuando posiciono el cursor cerca de la orilla de la pantalla. Sin embargo, algunas veces sólo paso rápidamente el cursor cerca de la orilla y el panel aparece, aún cuando no era mi intención usar el panel (esto se puede volver un poco molesto). Afortunadamente es posible configurar el tiempo que tenemos que posicionar el cursor cerca de una orilla antes de que aparezca el panel:

  1. Abrir el editor de configuraciones ejecutando gconf-editor en la terminal de comandos.
  2. Entra al siguiente fólder apps/panel/toplevels, ahí podrás ver tus paneles.
  3. Poner el valor deseado a la propiedad unhide_delay (lo tengo en 500 milisegundos).

Personalizando la terminal de comandos

Si vas a estar usando la terminal de comandos es mejor que realices algunos ajustes para que se ajuste mejor a tus preferencias. La siguiente imagen muestra cómo tengo configurada la terminal:

El primer punto es modificar el prompt. Al inicio me parecía útil el tener toda la ruta en el cursor, pero al navegar directorios anidados puede resultar hasta confuso ver tantas letras. Lo que prefiero es sólo ver el nombre del directorio actual y que el cursor sea de un color diferente. Para ello, configuré los colores para que fuera fondo negro con letras verdes. Después edité el archivo .bashrc en mi directorio raíz, modifiqué las líneas que configuran el prompt:

  1. Habilitar la línea “force_color_prompt=yes” para que el cursor tenga un color diferente.
  2. Configurar la línea que controla el formato del prompt, por ejemplo:
    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;33m\]\W:\[\033[00m\]'
    

Para dar el toque final, añadí una tecla de atajo para abrir rápidamente la terminal en un directorio que uso frecuentemente y que aparezca alineada a la derecha de la pantalla. El comando de la tecla de atajo es:

gnome-terminal –working-directory=/un_dir_muy_usado/ --geometry=80x48+950+0

El siguiente link describe las opciones que se pueden pasar al iniciar la terminal de comandos:

http://multignometerm.sourceforge.net/web/doc/options.html

Con esto cerramos los tips básicos que me ayudaron a cambiar a Ubuntu como mi sistema operativo primario. En el siguiente post presentaré un resumen y ligas a los cinco posts que comprenden esta serie.