Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Apuntes de un curso de
Y METODOS
PROGRAMACION
NUMERICOS
Cuarta edici
on
Jose Rogan C.
Vctor Munoz G.
Indice
I Computaci
on. 1
1. Elementos del sistema operativo unix. 3
1.1. Introduccion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2. Ingresando al sistema. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.1. Terminales. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.2. Login. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.3. Passwords. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.4. Cerrando la sesion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3. Archivos y directorios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.4. Ordenes basicas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.4.1. Archivos y directorios. . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.4.2. Ordenes relacionadas con directorios. . . . . . . . . . . . . . . . . . . . 9
1.4.3. Visitando archivos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.4.4. Copiando, moviendo y borrando archivos. . . . . . . . . . . . . . . . . 10
1.4.5. Espacio de disco. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.4.6. Links. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.4.7. Proteccion de archivos. . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.4.8. Filtros. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.4.9. Otros usuarios y maquinas . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.4.10. Fecha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.4.11. Transferencia a diskettes. . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.4.12. Diferencias entre los sistemas. . . . . . . . . . . . . . . . . . . . . . . . 22
1.5. Shells. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.5.1. Variables de entorno. . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.5.2. Redireccion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.5.3. Ejecucion de comandos. . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.5.4. Aliases. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.5.5. Las shells csh y tcsh. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1.5.6. Las shell sh y bash. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
1.5.7. Archivos de script. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.6. Ayuda y documentacion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.7. Procesos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.8. Editores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.8.1. El editor vi. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.8.2. Editores modo emacs. . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
iii
iv INDICE
3. Grafica. 103
3.1. Visualizacion de archivos graficos. . . . . . . . . . . . . . . . . . . . . . . . . . 103
3.2. Modificando imagenes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
3.3. Conversion entre formatos graficos. . . . . . . . . . . . . . . . . . . . . . . . . 104
3.4. Captura de pantalla. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
3.5. Creando imagenes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
3.6. Graficando funciones y datos. . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
3.7. Graficando desde nuestros programas. . . . . . . . . . . . . . . . . . . . . . . . 107
II M
etodos Num
ericos. 163
5. Preliminares. 165
5.1. Programas y funciones. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
5.2. Errores numericos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
5.2.1. Errores de escala. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
5.2.2. Errores de redondeo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
III Ap
endices. 267
11.Una breve introducci on a Octave/Matlab 269
11.1. Introduccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
11.2. Interfase con el programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
11.3. Tipos de variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
INDICE ix
7.1.
Orbita elptica alrededor del Sol. . . . . . . . . . . . . . . . . . . . . . . . . . . 200
7.2. Trayectoria y energa usando el metodo de Euler. . . . . . . . . . . . . . . . . 203
7.3. Trayectoria y energa usando el metodo de Euler-Cromer. . . . . . . . . . . . . 204
7.4. Trayectoria y energa usando el metodo de Euler-Cromer. . . . . . . . . . . . . 204
7.5. Trayectoria y energa con el paso de tiempo mas peque no en Euler-Cromer. . . 205
7.6. Trayectoria y energa usando el metodo de Runge-Kutta. . . . . . . . . . . . . 209
7.7. Trayectoria y energa usando el metodo de Runge-Kutta adaptativo. . . . . . . 213
7.8. Paso de tiempo en funcion de la distancia radial del Runge-Kutta adaptativo. 213
8.1. Sistema de bloques acoplados por resortes anclados entre paredes. . . . . . . . 229
8.2. Representacion grafica del metodo de Newton. . . . . . . . . . . . . . . . . . . 231
xi
Parte I
Computaci
on.
1
Captulo 1
1.1. Introducci
on.
En este captulo se intentara dar los elementos basicos para poder trabajar en un am-
biente unix. Sin pretender cubrir todos los aspectos del mismo, nuestro interes se centra
en dar las herramientas al lector para que pueda realizar los trabajos del curso bajo este
sistema operativo. Como comentario adicional, conscientemente se ha evitado la traduccion
de gran parte de la terminologa tecnica teniendo en mente que documentacion disponible
se encuentre, por lo general, en ingles y nos interesa que el lector sea capaz de reconocer los
terminos.
El sistema operativo unix es el mas usado en investigacion cientfica, tiene una larga
historia y muchas de sus ideas y metodos se encuentran presentes en otros sistemas operativos.
Algunas de las caractersticas relevantes del unix moderno son:
Memoria grande, lineal y virtual: Un programa en una maquina de 32 Bits puede acceder
y usar direcciones hasta los 4 GB en un maquina de solo 4 MB de RAM. El sistema
solo asigna memoria autentica cuando le hace falta, en caso de falta de memoria de
RAM, se utiliza el disco duro (swap).
Multitarea (Multitasking): Cada programa tiene asignado su propio espacio de me-
moria. Es imposible que un programa afecte a otro sin usar los servicios del sistema
operativo. Si dos programas escriben en la misma direccion de memoria cada uno man-
tiene su propia idea de su contenido.
Multiusuario: Mas de una persona puede usar la maquina al mismo tiempo. Programas
de otros usuarios contin
uan ejecutandose a pesar de que un nuevo usuario entre a la
maquina.
Casi todo tipo de dispositivo puede ser accedido como un archivo.
Existen muchos aplicaciones dise nadas para trabajar desde la lnea de comandos. Ademas,
la mayora de las aplicaciones permiten que la salida de una pueda ser la entrada de la
otra.
Permite compartir dispositivos (como disco duro) entre una red de maquinas.
3
4 CAPITULO 1. ELEMENTOS DEL SISTEMA OPERATIVO UNIX.
Por su naturaleza de multiusuario, nunca se debe apagar una maquina unix1 , ya que
una maquina apagada sin razon puede matar trabajos de das, perder los u
ltimos cambios de
tus archivos e ir degradando el sistema de archivos en dispositivos como el disco duro.
Entre los sistemas operativos unix actuales cabe destacar:
Linux: esta disponible para: Intel x86 e IA-64; Motorola 68k, en particular, para las es-
taciones Sun3, computadores personales Apple Macintosh, Atari y Amiga; Sun SPARC;
Alpha; Motorola/IBM PowerPC; ARM, maquinas NetWinder; Sun UltraSPARC; MIPS
CPUs, maquinas SGI y estaciones Digital; HP PA-RISC; S/390, servidores IBM S/390
y SuperH procesadores Hitachi SuperH.
SunOS2 : disponible para la familia 68K as como para la familia sparc de estaciones
de trabajo sun
Solaris3 : disponible para la familia sparc de Sun as como para la familia x86.
OSF14 : disponible para Alpha.
Ultrix: disponible para vax de Digital
SYSVR45 : disponible para la familia x86, vax.
IRIX: disponible para mips.
AIX6 : disponible para RS6000 de IBM y PowerPC.
1.2.1. Terminales.
Para iniciar una sesion es necesario poder acceder a un terminal. Pueden destacarse dos
tipos de terminales:
Terminal de texto: consta de una pantalla y de un teclado. Como indica su nombre, en
la pantalla solo es posible imprimir caracteres de texto.
Terminal grafico: Consta de pantalla grafica, teclado y mouse. Dicha pantalla suele ser
de alta resolucion. En este modo se pueden emplear ventanas que emulan el comporta-
miento de un terminal de texto (xterm o gnome-terminal).
1
Incluyendo el caso en que la m
aquina es un PC normal corriendo Linux u otra version de unix.
2
SunOS 4.1.x tambien se conoce como Solaris 1.
3
Tambien conocido como SunOS 5.x, solaris 2 o Slowaris :-).
4
Tambien conocido como Dec Unix.
5
Tambien conocido como Unixware y Novell-Unix.
6
Tambien conocido como Aches.
1.2. INGRESANDO AL SISTEMA. 5
1.2.2. Login.
El primer paso es encontrar un terminal libre donde aparezca el login prompt del sistema:
hostname login:
Otra persona ha dejado una sesion abierta. En este caso existe la posibilidad de intentar
en otra maquina o bien finalizar la sesion de dicha persona (si esta no se halla en las
proximidades).
Una vez que se haya superado el paso anterior de encontrar el login prompt se procede
con la introduccion del Username al prompt de login y despues la contrase
na (password)
adecuada.
1.2.3. Passwords.
El password puede ser cualquier secuencia de caracteres a eleccion. Deben seguirse las
siguientes pautas:
Debe ser facil de recordar por uno mismo. Si se olvida, debera pasarse un mal rato
diciendole al administrador de sistema que uno lo ha olvidado.
Para evitar que alguna persona no deseada obtenga el password y tenga libre acceso a
los archivos de tu cuenta:
Debe cambiarlo si crees que su password es conocido por otras personas, o descubre
un intruso7 esta usando su cuenta.
que alg
La orden para cambiar el password en unix es passwd. A menudo cuando existen va-
rias maquinas que comparten recursos (disco duro, impresora, correo electronico, . . . ), para
facilitar la administracion de dicho sistema se unifican los recursos de red (entre los que se
hayan los usuarios de dicho sistema) en una base de datos com un. Dicho sistema se conoce
8
como NIS (Network Information Service) . Si el sistema empleado dispone de este servicio, la
modificacion de la contrasena en una maquina supone la modificacion en todas las maquinas
que constituyan el dominio NIS.
/-|--> bin
|--> boot
|--> cdrom
|--> dev
|--> etc
|--> floppy
|--> home
|--> lib
|--> mnt
|--> proc
|--> root
|--> sbin
|--> tmp
|--> usr -|--> X11
| |--> bin
| |--> include
| |--> lib
| |--> local -|--> bin
| | |--> lib
| |--> man
| |--> src --> linux
| |--> doc
|--> var --> adm
8
Antiguamente se conoca como YP (Yellow Pages), pero debido a un problema de marca registrada de
United Kingdom of British Telecomunications se adoptaron las siglas nis.
9
En caso que se estuviera trabajando bajo X-Windows debes cerrar la sesion con Log out of Gnome.
1.4. ORDENES
BASICAS. 7
El arbol que observamos muestra un tpico arbol de directorios en Linux. Pueden variar,
sin embargo, algunos de los nombres dependiendo de la distribucion o version de Linux que
se este usando. Algunos directorios destacados son:
hd: hda1 sera el disco duro IDE, primario (a), y la primera particion (1).
fd: los archivos que empiecen con las letras fd se referiran a los controladores de
las disketteras: fd0 sera la primera diskettera, fd1 sera la segunda y as sucesi-
vamente.
ttyS: se usan para acceder a los puertos seriales como por ejemplo, ttyS0 es el
puerto conocido como com1.
sd: son los dispositivos SCSI. Su uso es muy similar al del hd.
lp: son los puertos paralelos. lp0 es el puerto conocido como LPT1.
null: este es usado como un agujero negro, ya que todo lo que se dirige all desa-
parece.
tty: hacen referencia a cada una de las consolas virtuales. Como es de suponer,
tty1 sera la primera consola virtual, tty2 la segunda, etc.
/usr/local - Zona con las aplicaciones no comunes a todos los sistemas unix, pero no
por ello menos utilizadas. En /usr/share/doc se puede encontrar informacion relacio-
nada con dicha aplicacion (en forma de paginas de manual, texto, html o bien archivos
dvi, Postscript o pdf). Tambien encontramos archivos de ejemplo, tutoriales, HOWTO,
etc.
1.4.
Ordenes b
asicas.
Para ejecutar un comando, basta con teclear su nombre (tambien debes tener permiso para
hacerlo). Las opciones o modificadores empiezan normalmente con el caracter - (p. ej. ls -l).
Para especificar mas de una opcion, se pueden agrupar en una sola cadena de caracteres
(ls -l -h es equivalente a ls -lh). Algunos comandos aceptan tambien opciones dadas por
palabras completas, en cuyo caso usualmente comienzan con -- (ls --color=auto).
8 CAPITULO 1. ELEMENTOS DEL SISTEMA OPERATIVO UNIX.
Los caracteres comodn pueden ser empleados para acceder a un conjunto de archivos con
caractersticas comunes. El signo * puede sustituir cualquier conjunto de caracteres11 y el
signo ? a cualquier caracter individual. Por ejemplo:12
bash$ ls
f2c.1 flexdoc.1 rcmd.1 rptp.1 zforce.1
face.update.1 ftptool.1 rlab.1 rxvt.1 zip.1
faces.1 funzip.1 robot.1 zcat.1 zipinfo.1
flea.1 fvwm.1 rplay.1 zcmp.1 zmore.1
flex.1 rasttoppm.1 rplayd.1 zdiff.1 znew.1
bash$ ls rp*
rplay.1 rplayd.1 rptp.1
bash$ ls *e??
face.update.1 zforce.1 zmore.1
Los archivos cuyo nombre comiencen por . se denominan ocultos, as por ejemplo en el
directorio de partida de un usuario.
bash$ ls -a user
. .alias .fvwmrc .login .xinitrc
.. .cshrc .joverc .profile
.Xdefaults .enviroment .kshrc .tcshrc
10
Normalmente se acude a la imagen de una carpeta que puede contener informes, documentos o bien otras
carpetas, y as sucesivamente.
11
Incluido el punto ., unix no es dos.
12
bash$ es el prompt en todos los ejemplos.
1.4. ORDENES
BASICAS. 9
1.4.2.
Ordenes relacionadas con directorios.
ls (LiSt)
Este comando permite listar los archivos de un determinado directorio. Si no se le suministra
argumento, lista los archivos y directorios en el directorio actual. Si se a
nade el nombre de
un directorio el listado es del directorio suministrado. Existen varias opciones que modifican
su funcionamiento entre las que destacan:
-l (Long listing) proporciona un listado extenso, que consta de los permisos13 de cada
archivo, el usuario el tama
no del archivo, . . .
-i (interactive), impide que la copia provoque una perdida del archivo destino si este
existe14 .
mv (MoVe)
Mover un archivo(s) a otro nombre y/o a otro directorio. Dispone de opciones analogas al
caso anterior.
rm (ReMove)
Borrar un archivo(s). En caso de que el argumento sea un directorio y se haya suministrado
la opcion -r, es posible borrar el directorio y todo su contenido. La opcion -i pregunta antes
de borrar.
1.4.6. Links.
ln (LiNk)
Permite realizar un enlace (link) entre dos archivos o directorios. Un enlace puede ser:
hard link : se puede realizar solo entre archivos del mismo sistema de archivos. El archivo
enlazado apunta a la zona de disco donde se halla el archivo original. Por tanto, si se
elimina el archivo original, el enlace sigue teniendo acceso a dicha informacion. Es el
enlace por omision.
Un enlace permite el uso de un archivo en otro directorio distinto del original sin necesidad
de copiarlo, con el consiguiente ahorro de espacio.
1.4.7. Protecci
on de archivos.
Dado que el sistema de archivos unix es compartido por un conjunto de usuarios, surge el
problema de la necesidad de privacidad. Sin embargo, dado que existen conjuntos de personas
que trabajan en com un, es necesario la posibilidad de que un conjunto de usuarios puedan
tener acceso a una serie de archivos (que puede estar limitado para el resto de los usuarios).
Cada archivo y directorio del sistema dispone de un propietario, un grupo al que pertenece
y unos permisos. Existen tres tipos fundamentales de permisos:
other: el resto de los usuarios (excepto el usuario y los usuarios que pertenezcan al
grupo)
16
Debe hacerse notar que los directorios solo pueden ser enlazados simbolicamente.
12 CAPITULO 1. ELEMENTOS DEL SISTEMA OPERATIVO UNIX.
Tambien se puede emplear all que es la union de todos los anteriores. Para visualizar las
protecciones de un archivo o directorio se emplea la orden ls -l, cuya salida es de la forma:
-rw-r--r-- ...otra informaci on... nombre
Los 10 primeros caracteres muestran las protecciones de dicho archivo:
archivo
d directorio
l enlace (link )
c dispositivo de caracteres (p.e. puerta serial)
b dispositivo de bloques (p.e. disco duro)
s socket (conexion de red)
Modo simbolico o literal. Se realiza empleando una cadena (o cadenas separadas por
comas) para especificar los permisos. Esta cadena se compone de los siguientes tres
elementos: who operation permission
Por ejemplo:
chmod u+x tarea
Permite la ejecucion por parte del usuario17 del archivo tarea.
chmod u=rx, go=r *.txt
Permite la lectura y ejecucion del usuario, y solo la lectura por parte del grupo y el
resto de usuarios.
umask
Esta es una orden intrnseca del Shell que permite asignar los permisos que se desea tengan
los archivos y directorios por omision. El argumento que acompa na a la orden es un n
umero
octal que aplicara una xor sobre los permisos por omision (rw-rw-rw-) para archivos y
(rwxrwxrwx) para directorios. El valor por omision de la mascara es 022 que habilita al
usuario para lectura-escritura, al grupo y al resto para lectura. Sin argumentos muestra el
valor de la mascara.
17
Un error muy frecuente es la creaci
on de un archivo de ordenes (script file) y olvidar permitir la ejecucion
del mismo.
14 CAPITULO 1. ELEMENTOS DEL SISTEMA OPERATIVO UNIX.
user@hostname:~$ id
uid=1000(user) gid=1000(group) groups=1000(group),25(floppy),29(audio)
user@hostname:~$
1.4.8. Filtros.
Existe un conjunto de ordenes en unix que permiten el procesamiento de archivos de texto.
Se denominan filtros (Unix Filters), porque normalmente se trabaja empleando redireccion
recibiendo datos por su stdin19 y retornandolos modificados por su stdout20 .
Para facilitar la comprension de los ejemplos siguientes supondremos que existen dos
archivo llamado mylist.txt y yourlist.txt que tienen en su interior:
mylist.txt yourlist.txt
1 190 1 190
2 280 2 281
3 370 3 370
echo
Este no es propiamente un filtro, pero nos sera muy util mas adelante. Despliega sobre la
pantalla un mensaje, sin argumento despliega una lnea en blanco
chao
user@hostname:~$
18
A pesar de que el usuario se identifica por una cadena denominada username, tambien existe un n
umero
denominado uid que es un identificativo numerico de dicho usuario.
19
Entrada estandar.
20
Salida estandar.
1.4. ORDENES
BASICAS. 15
3
3 370
user@hostname:~$
Numera las lneas.
Solo muestra la lnea 3. El modificador -n suprime la impresion de todas las lneas excepto
aquellas especificadas por p. Separando por coma damos un rango en el n umero de lneas.
Muestra hasta la lnea 2 y luego se sale de sed. El modificador -e corre un script, secuencia
de comandos.
Reemplaza todos los 0 del archivo por la letra a. Este es uno de los usos mas comunes.
Busca las lneas con la secuencia 2 2 y en ellas reemplaza todos los 0 por la letra a.
Expresiones regulares:
^ Matches al comienzo de la lnea
$ Matches al final de la lnea
. Matches cualquier caracter.
[] Matches con todos los caracteres dentro de los parentesis
diff
Permite comparar el contenido de dos archivos
user@hostname:~$ diff mylist.txt yourlist.txt
2c2
< 2 280
---
> 2 281
user@hostname:~$
Hay una diferencia entre los archivos en la segunda fila.
sort
Permite ordenar alfabeticamente
user@hostname:~$ sort -n -r mylist.txt
3 370
2 280
1 190
user@hostname:~$
18 CAPITULO 1. ELEMENTOS DEL SISTEMA OPERATIVO UNIX.
x (eXtract) extraccion
r a
nadir al final
u (Update) anadir aquellos archivos que no se hallen en el tarfile o que hayan sido
modificados con posterioridad a la version que aparece.
v Verbose (indica que archivos son agregados a medida que son procesados)
user@hostname:~$ wc mylist.txt
3 6 18 mylist.txt
user@hostname:~$
ping
Verifica si una maquina esta conectada a la red y si el camino de Internet hasta la misma
funciona correctamente.
1.4. ORDENES
BASICAS. 21
finger
finger user, muestra informacion22 sobre el usuario user en la maquina local.
finger user@hostname, muestra informacion sobre un usuario llamado user en una maquina
hostname.
finger @hostname, muestra los usuarios conectados de la maquina hostname.
1.4.10. Fecha
cal
Muestra el calendario del mes actual. Con la opcion -y y el a
no presenta el calendario del
a
no completo.
date
Muestra el da y la hora actual.
Una posibilidad es disponer de una maquina win9x con ftp instalado y acceso a red.
Empleando dicha aplicacion se pueden intercambiar archivos entre un sistema y el otro.
el comando: mount -t vfat /dev/fd0 /floppy no puede ser dado por un usuario. Sin
embargo, el sistema aceptara el comando mount /floppy de parte del usuario. Una vez
terminado el trabajo con el floppy este debe ser desmontado, antes de sacarlo, mediante
el comando: umount /floppy.
En dos los nombres de los archivos pueden tener un maximo de 8 caracteres y una
extension de 3 caracteres. En unix no existe restriccion respecto a la longitud del
nombre, y aunque pueden llevar extension, no es obligatorio. Tambien pueden tener
mas de una extension algo.v01.tar.gz, esto complica mucho a otros sistemas que
tienen limitaciones en los nombres.
El cambio de lnea en dos se compone de Carriage Return y Line Feed. Sin embargo,
en unix solo existe el Carriage Return. As un archivo de unix visto desde DOS parece
una unica lnea. El caso inverso es la aparicion del caracter ^M al final de cada lnea.
Ademas, el fin de archivo en dos es ^Z y en unix es ^D.
La presencia de caracteres con codigo ascii por encima del 127 (ascii extendido) suele
plantear problemas. Debido a que en DOS dicho codigo depende de la asignacion hecha,
que a su vez depende del pas.
Usando el comando tr se puede transformar un archivo con cambios de lneas para dos
en uno para unix. Sabiendo que ^M es ascii 13 decimal, pero 15 en octal:
tr -d \015 < datafile > TEMPFILE
mv -f TEMPFILE datafile
En Debian, instalando el paquete sysutils, queda instalado el comando dos2unix que tam-
bien lo hace.
1.5. Shells.
El sistema operativo unix soporta varios interpretes de comandos o shells, que ayudan
a que la interaccion con el sistema sea lo mas comoda y amigable posible. La eleccion de
cual es el shell mas comoda es algo personal; en este punto solo indicaremos las cuatro mas
significativas y populares:
bash : Bourne-Again Shell, con lo mejor de sh, ksh y tcsh. El archivo de configuracion
es .bash_profile cuando se entra a la cuenta por primera vez, y despues el archivo de
configuracion es .bashrc siempre en el directorio $HOME. La lnea de comando puede
ser editada usando comandos (secuencias de teclas) del editor emacs. Es el shell por
defecto de Linux.
Si queremos cambiar de shell en un momento dado, solo sera necesario que tecleemos el
nombre del mismo y estaremos usando dicho shell. Si queremos usar de forma permanente otro
shell del que tenemos asignado por omision23 podemos emplear la orden chsh que permite
realizar esta accion.
En los archivos de configuracion se encuentran las definiciones de las variables de entorno
(enviroment variables) como camino de b usqueda PATH, los aliases y otras configuraciones
personales. Veamos unos caracteres con especial significado para el Shell:
PATH - El camino de b
usqueda, una lista de directorios separado con : para buscar
programas.
DISPLAY - Bajo el sistema de X windows, el nombre de maquina y pantalla que esta usan-
do. Si esta variable toma el valor :0 el despliegue es local.
1.5.2. Redirecci
on.
Cuando un programa espera que se teclee algo, aquello que el usuario teclea se conoce
como el Standard Input: stdin. Los caracteres que el programa retorna por pantalla es lo que
se conoce como Standard Output: stdout (o Standard Error : stderr27 ). El signo < permite
que un programa reciba el stdin desde un archivo en vez de la interaccion con el usuario.
Por ejemplo: mail root < file, invoca el comando mail con argumento (destinatario del
mail) root, siendo el contenido del mensaje el contenido del archivo file en vez del texto que
usualmente teclea el usuario. Mas a menudo aparece la necesidad de almacenar en un archivo
la salida de un comando. Para ello se emplea el signo >. Por ejemplo, man bash > file,
invoca el comando man con argumento (informacion deseada) bash pero indicando que la
informacion debe ser almacenada en el archivo file en vez de ser mostrada por pantalla.
En otras ocasiones uno desea que la salida de un programa sea la entrada de otro. Esto
se logra empleando los denominados pipes, para ello se usa el signo |. Este signo permite que
27
Si estos mensajes son de error.
1.5. SHELLS. 25
>& o &> (solo csh, tcsh y bash) Redireccionar el stdout y stderr. Con 2> redirec-
ciono solo el stderr.
>>! Igual que >>, pero con la adicion que funciona tambien cuando el archivo no existe.
1.5.3. Ejecuci
on de comandos.
Si el comando introducido es propio del shell (built-in), se ejecuta directamente.
En caso contrario:
1.5.4. Aliases.
Para facilitar la entrada de algunas ordenes o realizar operaciones complejas, los shells
interactivos permiten el uso de aliases. La orden alias permite ver que aliases hay definidos
y tambien definir nuevos. Es corriente definir el alias rm =rm -i, de esta forma la orden
siempre pide confirmacion para borrar un archivo. Si alguna vez quieres usar rm sin alias,
solo hace falta poner delante el smbolo \, denominado backslash . Por ejemplo \rm elimina
los alias aplicados a rm. Otro ejemplo, bastante frecuente (en tcsh/csh) podra ser (debido
a la complejidad de la orden): alias ffind find . -name \!* -print. Para emplearlo:
ffind tema.txt, el resultado es la b usqueda recursiva a partir del directorio actual de un
archivo que se llame tema.txt, mostrando el camino hasta el mismo.
Comandos propios.
Los comandos propios o intrnsecos, Built-In Commands, son aquellos que proporciona el
propio shell 30 .
alias name def
Asigna el nombre name al comando def.
history
Muestra las u
ltimas ordenes introducidas en el shell. Algunos comandos relacionados con el
Command history son:
!!
Repite la u
ltima orden.
!n
Repite la orden n-esima.
!string
Repite la orden mas reciente que empiece por la cadena string.
!?string
Repite la orden mas reciente que contenga la cadena string.
str1 str2 o !!:s/str1/str2/
(substitute) Repite la u
ltima orden reemplanzando la primera ocurrencia de la cadena
str1 por la cadena str2.
!!:gs/str1/str2/
(global substitute) Repite la u
ltima orden reemplazando todas las ocurrencias de la
cadena str1 por la cadena str2.
!$
Es el u
ltimo argumento de la orden anterior que se haya tecleado.
pushd
Cambia de directorio, recordando el directorio actual.
popd
Retorna al directorio desde donde se hizo pushd la u
ltima vez.
repeat count command
Repite count veces el comando command.
rehash
Rehace la tabla de comandos (hash table).
30
A diferencia de los comandos que provienen de un ejecutable situado en alguno de los directorios de la
variable PATH.
1.5. SHELLS. 27
de lnea de comandos) BASH es compatible con TCSH y KSH. El modo de completado (file
completion) es automatico (usando TAB solo) si el shell es interactivo.
alias
En bash, alias solo sirve para substitucion simple de una cadena por otra. Por ejemplo:
alias ls=ls -F. Para crear alias con argumentos se usan funciones, ver la documentacion.
#!/bin/bash
variable=/home/yo
cp $1 /tmp/$2
rm $1
cd $variable
# Hecho por mi
La primera lnea declara la shell especfica que se quiere usar. En la segunda lnea hay una
declaracion de una variable interna. La tercera contiene los dos primeros argumentos con que
32
En bash/sh la hash table se va generando dinamicamente a medida que el usuario va empleando las
ordenes. As el arranque del shell es m
as r
apido, y el uso de orden equivalente hash -r casi nunca hace falta.
1.6. AYUDA Y DOCUMENTACION. 29
fue llamado el script. Por ejemplo, si el anterior script esta en un archivo llamado ejemplo,
el comando ejemplo file1 file2 asocia $1 a file1 y $2 a file2. La lnea 5 hace uso de la
variable interna dentro de un comando. La u ltima lnea por comenzar con un # corresponde
a un comentario. Notemos que la primera tambien es un comentario, pero la combinacion #!
en la primera lnea fuerza a que se ejecute esa shell.
Esto solo es una mnima pincelada de una herramienta muy poderosa y u til. Los comandos
disponibles en la shell conforman un verdadero lenguaje de programacion en s, y los scripts
pueden dise narse para realizar tareas monotonas y complejas. Este es un tema que le sera u
til
profundizar.
1.7. Procesos.
En una maquina existen una multitud de procesos que pueden estar ejecutandose si-
multaneamente. La mayora de ellos no corresponden a ninguna accion realizada por el usua-
rio y no merecen que se les preste mayor atencion. Estos procesos corresponden a programas
ejecutados en el arranque del sistema y tienen que ver con el funcionamiento global del
servidor. En general, los programas suelen tener uno de estos dos modos de ejecucion:
foreground: Son aquellos procesos que requieren de la interaccion y/o atencion del
usuario mientras se estan ejecutando, o bien en una de sus fases de ejecucion (i.e.
introduccion de datos). As por ejemplo, la consulta de una pagina de manual es un
proceso que debe ejecutarse claramente en foreground.
background: Son aquellos procesos que no requieren de la interaccion con el usuario
para su ejecucion. Si bien el usuario deseara estar informado cuando este proceso
termine. Un ejemplo de este caso sera la impresion de un archivo.
Sin embargo, esta division que a primera vista pueda parecer tan clara y concisa, a menudo
en la practica aparece la necesidad de conmutar de un modo al otro, detencion de tareas
indeseadas, etc. As por ejemplo, puede darse el caso de que estemos leyendo una pagina de
manual y de repente necesitemos ejecutar otra tarea. Un proceso viene caracterizado por:
process number
job number
30 CAPITULO 1. ELEMENTOS DEL SISTEMA OPERATIVO UNIX.
ps x Lista todos los procesos que pertenezcan al usuario, incluyendo los que no estan
asociados a un terminal.
jobs Lista los procesos que se hayan ejecutado desde el shell actual, mostrando el job
number.
kill (process number) Enva una se nal34 a un proceso unix. En particular para
enviar la se
nal de termino a un programa, damos el comando kill -KILL, pero no
hace falta al ser la se
nal por defecto.
1.8. Editores.
Un editor es un programa que permite crear y/o modificar un archivo. Existen multitud
de editores diferentes, y al igual que ocurre con los shells, cada usuario tiene alguno de su
predileccion. Mencionaremos algunos de los mas conocidos:
emacs (xemacs) - Editor muy configurable escrito en lenguaje Lisp. Existen multitud
de modos para este editor (lector de mail, news, www,. . . ) que lo convierten en un
verdadero shell para multitud de usuarios. Las ultimas versiones del mismo permiten
la ejecucion desde X-windows o terminal indistintamente con el mismo binario. Posee
un tutorial en lnea, comando C-H t dentro del editor. El archivo de configuracion
personalizada es: $HOME/.emacs.
33
Por omision un comando se ejecuta siempre en el foreground.
34
Para ver las se
nales disponibles entra la orden kill -l (l por list).
1.8. EDITORES. 31
jove - Basado en Emacs, (Jonathans Own Version of Emacs). Posee tutorial en una uti-
lidad asociada: teachjove. El archivo de configuracion personalizada es: $HOME/.joverc.
gedit - Un peque
no y liviano editor de texto para Gnome
xjed - Version de jed para el X-windows system. Presenta como ventaja que es capaz
de funcionar en muchos modos: lenguaje C, Fortran, TeX, etc, reconociendo palabras
clave y signos de puntuacion, empleando un colorido distinto para ellos. El archivo de
configuracion personalizada es el mismo que el de de jed.
Dado que los editor del tipo de gedit disponen de menus auto explicativos, daremos a
continuacion unas ligeras nociones solo de vi y emacs.
~
~
~
/tmp/vi.9Xdrxi: new file: line 1
~
~
~
nombre.de.archivo: new file: line 1
a escribir. Para salir del modo de insercion de texto y volver al modo de ordenes se aprieta
ESC.
Opciones de comandos.
Para entrar al men u de comandos se debe presionar la tecla : en el modo de ordenes.
Apareceran los dos puntos (:). Aqu se pueden ingresar ordenes para guardar, salir, cambiar
de archivo entre otras cosas. Veamos algunos ejemplos:
:e file1.txt Si deseo editar otro archivo al que se le pondra por nombre file1.txt.
1.8. EDITORES. 33
La zona de edicion: donde aparece el texto que esta siendo editado y que ocupa la
mayor parte de la pantalla.
Emacs es un editor que permite la edicion visual de un archivo (en contraste con el modo
de edicion de vi). El texto se agrega o modifica en la zona de edicion, usando las teclas
disponibles en el teclado.
Ademas, existen una serie de comandos disponibles para asistir en esta tarea.
La mayora de los comandos de emacs se realizan empleando la tecla de CONTROL o la
tecla META36 . Emplearemos la nomenclatura: C-key para indicar que la tecla key debe de
ser pulsada junto con CONTROL y M-key para indicar que la tecla META debe de ser pulsada
junto a key. En este u ltimo caso NO es necesario pulsar simultaneamente las teclas ESC y
key, pudiendo pulsarse secuencialmente ESC y luego key, sin embargo, si se usa ALT como
META deben ser pulsadas simultaneamente. Observemos que en un teclado normal hay unos
50 caracteres (letras y numeros). Usando SHIFT se agregan otros 50. As, usando CONTROL
y META, hay unos 50 4 = 200 comandos disponibles. Ademas, existen comandos especiales
llamados prefijos, que modifican el comando siguiente. Por ejemplo, C-x es un prefijo, y si C-s
es un comando (de b usqueda en este caso), C-x C-s es otro (grabar archivo). As, a traves
35
La licencia de GNU, da el permiso de libre uso de los programas con su fuentes, pero los autores mantienen
el Copyright y no es permitido distribuir los binarios sin acceso a sus fuentes, los programas derivados de
dichos fuentes heredan la licencia GNU.
36
Dado que la mayora de los teclados actuales no poseen la tecla META se emplea ya sea ESC o ALT.
34 CAPITULO 1. ELEMENTOS DEL SISTEMA OPERATIVO UNIX.
de un prefijo, se duplican el n
umero de comandos disponibles solo con el teclado, hasta llegar
a unos 200 2 = 400 comandos en total.
Aparte de estos comandos accesibles por teclas, algunos de los cuales comentaremos a
continuacion, existen comandos que es posible ejecutar por nombre, haciendo as el n umero
de comandos disponibles virtualmente infinito.
Revisemos los comandos mas usuales, ordenados por topico.
Abortar y deshacer
En cualquier momento, es posible abortar la operacion en curso, o deshacer un comando
indeseado:
C-g abortar
C-x u deshacer
Archivos
Ventanas
Emacs permite dividir la pantalla en varias ventanas. En cada ventana se puede editar
texto e ingresar comandos independientemente. Esto es u til en dos situaciones: a) si necesi-
tamos editar un solo archivo, pero necesitamos ver su contenido en dos posiciones distintas
(por ejemplo, el comienzo y el final de archivos muy grandes); y b) si necesitamos editar o ver
varios archivos simultaneamente. Naturalmente, aunque son independientes, solo es posible
editar un archivo a la vez. A la ventana en la cual se encuentra el cursor en un momento
dado le llamamos la ventana actual.
El cambio del cursor a una ventana cualquiera se puede hacer tambien rapidamente a
traves del mouse.
Comandos de movimiento
Algunos de estos comandos tienen dos teclas asociadas, como se indica a continuacion.
1.8. EDITORES. 35
May
usculas y min
usculas
M-u Cambia a mayuscula desde la posicion del cursor hasta el fin de la palabra
M-l Cambia a minuscula desde la posicion del cursor hasta el fin de la palabra
M-c Cambia a mayuscula el caracter en la posicion del cursor y
a min
uscula hasta el fin de la palabra
Por ejemplo, veamos el efecto de cada uno de estos comandos sobre la palabra EmAcS, si
el cursor esta sobre la letra E (el efecto es distinto si esta sobre cualquier otra letra!):
Transposici on
Los siguientes comandos toman como referencia la posicion actual del cursor. Por ejemplo,
C-t intercambia el caracter justo antes del cursor con el caracter justo despues.
B
usqueda y reemplazo
C-s B
usqueda hacia el fin del texto
C-r B
usqueda hacia el inicio del texto
M- % B
usqueda y sustitucion (pide confirmacion cada vez)
M-& B
usqueda y sustitucion (sin confirmacion)
El concepto de kill buffer es mucho mas poderoso que lo explicado recien. En realidad,
muchos comandos, no solo M-w y C-w, copian texto en un kill buffer. En general, cualquier
comando que borre mas de un caracter a la vez, lo hace. Por ejemplo, C-k borra una lnea.
Lo que hace no es solo borrarla, sino ademas copiarla en un kill buffer. Lo mismo ocurre
con los comandos que borran palabras completas (M-d, M-Backspace), y muchos otros. Lo
1.8. EDITORES. 37
interesante es que C-y funciona tambien en todos esos casos: C-y lo u nico que hace es tomar
el ultimo texto colocado en un kill buffer (resultado de la ultima operacion que borro mas de
un caracter a la vez), y lo coloca en el archivo. Por lo tanto, no solo podemos copiar o mover
regiones, sino tambien palabras o lneas. Mas aun, el kill buffer no es borrado con el C-y,
as que ese mismo texto puede ser duplicado muchas veces. Continuara disponible con C-y
mientras no se ponga un nuevo texto en el kill buffer.
Ademas, emacs dispone no de uno sino de muchos kill buffers. Esto permite recuperar
texto borrado hace mucho rato. En efecto, cada vez que se borra mas de un caracter de una
vez, se una un nuevo kill buffer. Por ejemplo, consideremos el texto:
Si en este parrafo borramos la primera lnea (con C-k), despues borramos la primera
palabra de la segunda (con M-d, por ejemplo), y luego la segunda palabra de la u ltima,
entonces habra tres kill buffers ocupados:
Al colocar el cursor despues del punto final, C-y toma el contenido del u
ltimo kill buffer
y lo coloca en el texto:
segunda linea,
y la tercera. finalmente
segunda linea,
y la tercera. la
buffer 1 : finalmente
buffer 2 : La primera linea del texto,
buffer 3 : la
Sucesivas aplicaciones de M-y despues de un C-y rotan sobre todos los kill buffers (que
pueden ser muchos). El editor, as, conserva un conjunto de las u
ltimas zonas borradas durante
la edicion, pudiendo recuperarse una antigua a pesar de haber seleccionado una nueva zona,
o borrado una nueva palabra o lnea. Toda la informacion en los kill buffers se pierde al salir
de emacs (C-c).
Resumimos entonces los comandos para manejo de los kill buffers:
38 CAPITULO 1. ELEMENTOS DEL SISTEMA OPERATIVO UNIX.
Definici
on de macros
La clave de la configurabilidad de emacs esta en la posibilidad de definir nuevos comandos
que modifiquen su comportamiento o agreguen nuevas funciones de acuerdo a nuestras nece-
sidades. Un modo de hacerlo es a traves del archivo de configuracion $HOME/.emacs, para lo
cual se sugiere leer la documentacion disponible en la distribucion instalada. Sin embargo, si
solo necesitamos un nuevo comando en la sesion de trabajo actual, un modo mas simple es
definir una macro, un conjunto de ordenes que son ejecutados como un solo comando. Los
comandos relevantes son:
Todas las sucesiones de teclas y comandos dados entre C-x ( y C-x ) son recordados por
emacs, y despues pueden ser ejecutados de una vez con C-x e.
Como ejemplo, consideremos el siguiente texto, con los cinco primeros lugares del ranking
ATP (sistema de entrada) al 26 de marzo de 2002:
Supongamos que queremos: (a) poner los nombres y apellidos con may uscula (como de-
bera ser); (b) poner las siglas de pases solo en may
usculas.
Para definir una macro, colocamos el cursor al comienzo de la primera lnea, en el 1,
y damos C-x (. Ahora realizamos todos los comandos necesarios para hacer las tres tareas
solicitadas para el primer jugador solamente: M-f (avanza una palabra, hasta el espacio antes
de hewitt; M-c M-c (cambia a Hewitt, Lleyton); M-u (cambia a AUS); Home (vuelve el
cursor al comienzo de la lnea); (coloca el cursor al comienzo de la lnea siguiente, en el 2).
Los dos u ltimos pasos son importantes, porque dejan el cursor en la posicion correcta para
ejecutar el comando nuevamente. Ahora terminamos la definicion con C-x ). Listo. Si ahora
ejecutamos la macro, con C-x e, veremos que la segunda lnea queda modificada igual que
la primera, y as podemos continuar hasta el final:
.
Window Manager (WM) Es un cliente con privilegios especiales: controla el compor-
tamiento (forma, tama
no,. . . ) del resto de clientes. Existen varios, destacando:
40 CAPITULO 1. ELEMENTOS DEL SISTEMA OPERATIVO UNIX.
En caso de que tengas que correr una aplicacion de X que no este disponible en la maquina
que estas usando, eso no representa ning
un problema. Las ordenes necesarias son (por ejemplo,
para arrancar un gnome-terminal remoto):
Si todo esta previamente configurado, es posible que no haga falta dar el password.
Cuando quieres salir, normalmente puedes encontrar un icono con la opcion Log out, en
un menu o panel de la pantalla.
Bot
on izquierdo (LB): Seleccionar. Comienza el bloque de seleccion.
Bot
on central (MB): Pegar. Copia la seleccion en la posicion del cursor.
Bot
on derecho (RB): Habitualmente ofrece un men
u para partir aplicaciones.
Existen dos modos para determinar cual es la ventana activa, aquella que recibe las
entradas de teclado:
Focus Follows Mouse: La ventana que contenga al raton es la que es activa. No usado
por defecto actualmente.
Click To Focus: La ventana seleccionada es la activa. El modo que este activo depende
de la configuracion del Window Manager.
1.11. Internet.
En esta seccion denominaremos unix1 a la maquina local (desde donde ejecutamos la
orden) y unix2 a la maquina remota (con la que interaccionamos). Ambos son los hostnames
de las respectivas maquinas. Existen algunos conceptos que previamente debemos comentar:
hostname: es el nombre que tiene asociada la maquina (p.e. macul). A este nombre se
le suelen anadir una serie de sufijos separados por puntos que constituye el denominado
dominio (p.e. macul.ciencias.uchile.cl). Una maquina por tanto puede tener mas
de un nombre reconocido (se habla en este caso de alias). Se denomina resolucion
a la identificacion entre un hostname y el IP-number correspondiente. La consulta
se realiza inicialmente en el archivo /etc/hosts, donde normalmente se guardan las
identificaciones de las maquinas mas com unmente empleadas. En caso de que no se
logre se accede al servicio DNS (Domain Name Service), que permite la identificacion
(resolucion) entre un hostname y un IP-number.
mail-address: es el nombre que se emplea para enviar correo electronico. Este nombre
puede coincidir con el nombre de una maquina, pero se suele definir como un alias, con
objeto de que la direccion no deba de cambiarse si la maquina se estropea o se cambia
por otra.
talk usuario1@unix2, intenta hacer una conexion para hablar con el usuario1 en la
maquina unix2. Existen varias versiones de talk en los diferentes sistemas operativos,
de forma que no siempre es posible establecer una comunicacion entre maquinas con
sistemas operativos diferentes.
ftp unix2, (file transfer protocol) aplicacion para copiar archivos entre maquinas de
una red. ftp exige un nombre de cuenta y password para la maquina remota. Algunas
de las opciones mas empleadas (una vez establecida la conexion) son:
Existen versiones mejoradas de ftp con muchas mas posibilidades, por ejemplo, ncftp.
Tambien existen versiones graficas de clientes ftp donde la eleccion de archivo, el sentido
de la transferencia y el modo de esta, se elige con el mouse (p.e. wxftp).
rlogin -l nombre unix2, (remote login), hace un login a la maquina unix2 como el
usuario nombre por defecto, sin los argumentos -l nombre rlogin usa el nombre de la
cuenta local. Normalmente rlogin pide el password de la cuenta remota, pero con el
uso del archivo .rhosts o /etc/hosts.equiv esto no es siempre necesario.
rsh -l nombre unix2 orden, (remote shell ), ejecuta la orden en la maquina unix2
como usuario nombre. Es necesario que pueda entrar en la maquina remota sin password
para ejecutar una orden remota. Sin especificar orden act
ua como rlogin.
Nomenclatura.
Veamos algunos conceptos relacionados con el correo electronico:
Subject : Es una parte de un mensaje que piden los programas al comienzo y sirve
como ttulo para el mensaje.
Cc (Carbon Copy) : Permite el envo de copias del mensaje que esta siendo editado a
terceras personas.
Reply : Cuando se enva un mensaje en respuesta a otro se suele a nadir el comienzo
del subject: Re:, con objeto de orientar al destinatario sobre el tema que se responde.
Es frecuente que se incluya el mensaje al que se responde para facilitar al destinatario
la comprension de la respuesta.
Forward : Permite el envo de un mensaje (con modificaciones o sin ellas) a una tercera
persona.
44 CAPITULO 1. ELEMENTOS DEL SISTEMA OPERATIVO UNIX.
Aplicaci
on mail.
Es posiblemente la aplicacion mas simple. Para la lectura de mail teclear simplemente:
mail y a continuacion aparece un ndice con los diferentes mensajes recibidos. Cada mensaje
tiene una lnea de identificacion con n
umero. Para leer un mensaje basta teclear su n
umero y a
continuacion return. Para enviar un mensaje: mail (address) se pregunta por el Subject:
y a continuacion se introduce el mensaje. Para acabar se teclea solo un punto en una lnea
o bien Ctr-D. Por u ltimo, se pregunta por Cc:. Es posible personalizar el funcionamiento
mediante el archivo $HOME/.mailrc. Para enviar un archivo de texto a traves del correo se
suele emplear la redireccion de entrada: mail (address) < file.
1.11.4. WWW.
WWW son las siglas de World-Wide Web. Este servicio permite el acceso a informacion
entrelazada (dispone de un texto donde un termino puede conducir a otro texto): hyperlinks.
Los archivos estan realizados en un lenguaje denominado html. Para acceder a este servicio
es necesario disponer de un lector de dicho lenguaje conocido como browser o navegador.
Destacan actualmente: Netscape, Mozilla, Opera y el simple pero muy rapido Lynx.
38
Este comando debe usarse con conocimiento pues en caso contrario podra provocar un loop indefinido y
no recibir nunca correo.
1.12. IMPRESION. 45
1.12. Impresi
on.
Cuando se quiere obtener una copia impresa de un archivo se emplea el comando lpr.
lpr file - Enva el archivo file a la cola de impresion por defecto. Si la cola esta activa-
da, la impresora lista y ning
un trabajo por encima del enviado, nuestro trabajo sera procesado
de forma automatica.
A menudo existen varias posibles impresoras a las que poder enviar los trabajos. Para
seleccionar una impresora en concreto (en vez de la por defecto) se emplea el modificador:
lpr -Pimpresora, siendo impresora el nombre logico asignado a esta otra impresora. Para
recibir una lista de las posibles impresoras de un sistema, as como su estado, se puede em-
plear el comando /usr/sbin/lpc status. La lista de impresoras y su configuracion tambien
esta disponible en el archivo /etc/printcap.
Otras ordenes para la manipulacion de la cola de impresion son:
lpq [-Pimpresora], permite examinar el estado de una determinada cola (para ver la
cantidad de trabajos sin procesar de esta, por ejemplo).
1.13. Compresi
on.
A menudo necesitamos comprimir un archivo para disminuir su tama no, o bien crear un
respaldo (backup) de una determinada estructura de directorios. Se comentan a continuacion
una serie de comandos que permiten ejecutar dichas acciones:
El compresor compress esta relativamente fuera de uso, pero es la estandar de unix.
zcat file.Z : muestra por el stdout el contenido descomprimido del archivo (sin
destruir el original).
Otra alternativa de compresor mucho mas usada es gzip el compresor de GNU que posee
una mayor razon de compresion que compress. Veamos los comandos:
gzip file : comprime el archivo, creando el archivo file.gz, destruye el archivo ori-
ginal.
zless file.gz : muestra por el stdout el contenido descomprimido del archivo pagi-
nado por less.
La extension empleada en los archivos comprimidos con gzip suele ser .gz pero a veces
se usa .gzip. Adicionalmente el programa gunzip tambien puede descomprimir archivos
creados con compress.
La opcion con mayor tasa de compresion que gzip es bzip2 y su descompresor bunzip2.
La extension usada en este caso es .bz2. El kernel de Linux se distribuye en formato bzip2.
Existen tambien versiones de los compresores compatibles con otros sistemas operativos:
zip, unzip, unarj, lha, rar y zoo.
En caso que se desee crear un archivo comprimido con una estructura de directorios debe
ejecutarse la orden:
tar cvzf nombre.tgz directorio
o bien
tar cvjf nombre.tbz directorio
En el primer caso comprime con gzip y en el segundo con bzip2. Para descomprimir y
restablecer la estructura de directorio almacenada se usan los comandos:
tar xvzf nombre.tgz directorio
si se realizo la compresion con gzip o bien
tar xvjf nombre.tbz directorio
si se realizo la compresion con bzip2.
Captulo 2
En este captulo se intentara dar los elementos basicos del lenguaje de programacion
C++. No se pretende mas que satisfacer las mnimas necesidades del curso, sirviendo como
un ayuda de memoria de los topicos abordados, para futura referencia. Se debe consignar que
no se consideran todas las posibilidades del lenguaje y las explicaciones estan reducidas al
mnimo.
2.1. Estructura b
asica de un programa en C++.
2.1.1. El programa m
as simple.
El primer ejemplo de todo manual es el que permite escribir Hola en la pantalla.
//
// Los comentarios comienzan con //
//
#include <iostream>
int main()
{
cout << "Hola." << endl;
return 0 ;
}
Las tres primeras lneas corresponden a comentarios, todo lo que esta a la derecha de
los caracteres // son comentarios y no seran considerados en la compilacion. En la lnea
siguiente se incluye un archivo de cabecera, o header, con la instruccion de preprocesador
#include. El nombre del archivo se puede escribir como <nombre> o bien "nombre.h". En
el primer caso el archivo nombre sera buscado en el path por defecto para los include,
tpicamente /usr/include o /usr/include/g++-3/ en el caso de headers propios de C++;
en el segundo caso la b usqueda se hace en el directorio local. Tambien podramos incluir
un path completo cuando se ocupan las comillas. En nuestro ejemplo se incluye el archivo
iostream, en el cual se hacen las definiciones adecuadas para el manejo de la entrada y salida
en C++. Este archivo es necesario para enviar luego un mensaje a pantalla.
La funcion int main es donde comienza a ejecutarse el programa; siempre debe haber una
funcion main en nuestro programa. Debido a imposiciones del sistema operativo la funcion
47
48 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
main devuelve un entero y por tanto debe ser declarada int. Los parentesis vacos () indican
que el main no tiene argumentos de entrada (mas adelante se vera que puede tenerlos). Lo
que esta encerrado entre llaves {} corresponde al cuerpo de la funcion main. Cada una de
las lneas termina con el caracter ;. El identificador predefinido cout representa la salida a
pantalla. El operador << permite que lo que esta a su derecha se le de salida por el dispositivo
que esta a su izquierda, en este caso cout. Si se quiere enviar mas de un objeto al dispositivo
que esta al inicio de la lnea agregamos otro operador <<, y en este caso lo que esta a la derecha
del operador se agregara a lo que esta a la izquierda y todo junto sera enviado al dispositivo.
En nuestro caso se ha enviado endl, un objeto predefinido en el archivo iostream.h que
corresponde a un cambio de lnea, el cual sera agregado al final del mensaje. La lnea final
contiene la instruccion de retorno del entero cero, return 0.
Si escribimos nuestro primer programa en el editor xemacs con el nombre de primero.cc
las instrucciones para editarlo, compilarlo y correrlo seran:
2.1.2. Definici
on de funciones.
Las funciones en C++ son muy importantes, pues permiten aislar parte del codigo en
una entidad separada. Esto es un primer paso a la modularizaci on de nuestro programa,
es decir, a la posibilidad de escribirlo en partes que puedan ser editadas de modo lo mas
independiente posible. Ello facilita enormemente la creacion de codigo complicado, pues sim-
plifica su modificacion y la localizacion de errores. Nos encontraremos frecuentemente con
este concepto.
Aprovecharemos de introducir las funciones modificando el primer programa de manera
que se delegue la impresion del mensaje anterior a una funcion independiente:
//
// Segunda version incluye funcion adicional
//
#include <iostream>
void PrintHola()
{
cout << "Hola." << endl;
2.1. ESTRUCTURA BASICA DE UN PROGRAMA EN C++. 49
int main()
{
PrintHola();
return 0;
}
La funcion debe estar definida antes de que sea ocupada, por eso va primero en el codigo
fuente. Como ya se dijo antes, la ejecucion del programa comienza en la funcion main a
pesar de que no esta primera en el codigo fuente. Los parentesis vacos indican que la funcion
PrintHola no tiene argumentos y la palabra delante del nombre de la funcion indica el tipo
de dato que devuelve. En nuestro caso la palabra void indica que no devuelve nada a la
funcion main.
Una alternativa al codigo anterior es la siguiente:
#include <iostream>
void PrintHola();
int main()
{
PrintHola();
return 0 ;
}
void PrintHola()
{
cout << "Hola." << endl;
}
Pueden contener n
umeros, pero no comenzar por uno.
Longitud arbitraria.
int i;
i=10;
Esta necesidad de declarar cada variable a usar se relaciona con la caracterstica de C++ de
ser fuertemente tipeado2 . Algunos de los errores mas habituales en programacion se deben
al intento de asignar a variables valores que no corresponden a sus tipos originales. Si bien
esto puede no ser muy grave en ciertos contextos, a medida que los programas se vuelven
mas complejos puede convertirse en un verdadero problema. El compilador de C++ es capaz
de detectar los usos indebidos de las variables pues conoce sus tipos, y de este modo nuestro
codigo se vuelve mas seguro.
Es posible reunir las acciones de declaracion e inicializacion en una misma lnea:
int i=10;
o declarar mas de una variable del mismo tipo simultaneamente, e inicializar algunas en la
misma lnea:
A veces se requiere que una variable no vare una vez que se le asigna un valor. Por ejemplo,
podramos necesitar definir el valor de = 3.14159..., y naturalmente no nos gustara que,
por un descuido, a esa variable se le asignara otro valor en alguna parte del programa. Para
asegurarnos de que ello no ocurra, basta agregar el modificador const a la variable:
Para numeros reales se puede usar la notacion exponencial. Por ejemplo, 1.5e-3 repre-
umero 1.5 103 .
senta el n
Una variable puede ser declarada solo una vez, pero naturalmente se le pueden asignar
valores en un n
umero arbitrario de ocasiones.
Los tipos de variables disponibles son3 :
char c = a;
Ademas de las letras may usculas y minusculas, y smbolos como &, (, :, etc., hay una
serie de caracteres especiales (escape codes) que es posible asignar a una variable char. Ellos
son:
3
Los valores de los rangos indicados son simplemente representativos y dependen de la maquina utilizada.
Ademas, estos valores no corresponden exactamente a las versiones mas recientes de C++.
52 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
newline \n
horizontal tab \t
vertical tab \v
backspace \b
carriage return \r
form feed \f
alert (bell) \a
backslash \\
single quote \
double quote \"
Por ejemplo, la lnea:
corresponde al output
#include <iostream>
int main()
{
int i, j ;
cout << "Ingrese dos numeros enteros: " ;
cin >> i >> j ;
cout << "Los dos numeros ingresados fueron: " << i <<" "<< j << endl ;
return 0;
}
+ - * /
2.1. ESTRUCTURA BASICA DE UN PROGRAMA EN C++. 53
&& || !
2.1.8. Asignaciones.
a) Asignacion simple. Podemos asignar a una variable un valor explcito, o el valor de otra
variable:
i = 1;
j = k;
x = x + 2;
Si x fuera una variable matematica normal, esta expresion no tendra sentido. Esta
expresion es posible porque el compilador interpreta a x de modo distinto a cada lado
del signo igual: a la derecha del signo igual se usa el valor contenido en la variable x
(por ejemplo, 10); a la izquierda del signo igual se usa la direccion de memoria en la
cual esta alojada la variable x. De este modo, la asignacion anterior tiene el efecto de
colocar en la direccion de memoria que contiene a x, el valor que tiene x mas 2. En
general, todas las variables tienen un rvalue y un lvalue: el primero es el valor usado a
la derecha (right) del signo igual en una asignacion, y el segundo es el valor usado a la
izquierda (left), es decir, su direccion de memoria.
b) Asignacion compuesta.
La expresion x = x + 2 se puede reemplazar por x += 2.
Existen los operadores += -= *= /=
Los operadores para asignacion compuesta, y los de incremento y decremento, no son solo
abreviaciones. En realidad hay que preferirlas porque implican optimizaciones en el ejecutable
resultante.
2.1.9. Conversi
on de tipos.
Una consecuencia de que C++ sea fuertemente tipeado es que no se pueden hacer
operaciones binarias con objetos de tipos distintos. En la siguiente expresion,
int i = 3;
float x = 43.8;
cout << "Suma = " << x + i << endl;
a) Conversion explcita.
Si i es un int, por ejemplo, entonces float(i) la convierte en float. As, el programa
anterior se puede reescribir:
int i = 3;
float x = 43.8;
cout << "Suma = " << x + float(i) << endl;
2.1. ESTRUCTURA BASICA DE UN PROGRAMA EN C++. 55
Ahora la suma es claramente entre dos variables float, y se puede realizar. Sin em-
bargo, esto es bastante tedioso, por cuanto el programador debe realizar el trabajo de
conversion personalmente cada vez que en su codigo se desee sumar un real con un
n
umero entero.
b) Conversion implcita.
En este caso, el compilador realiza las conversiones de modo automatico, prefiriendo
siempre la conversion desde un tipo de variable de menor precision a uno de mayor
precision (de int a double, de short a int, etc.). As, a pesar de lo que dijimos, el
codigo anterior habra funcionado en su forma original. Evidentemente esto es muy
comodo, porque no necesitamos hacer una conversion explcita cada vez que sumamos
un entero con un real. Sin embargo, debemos estar conscientes de que esta comodidad
solo es posible porque ocurren varias cosas: primero, el compilador detecta el intento de
operar sobre dos variables que no son del mismo tipo; segundo, el compilador detecta,
en sus reglas internas, la posibilidad de cambiar uno de los tipos (int en este caso) al
otro (float); tercero, el compilador realiza la conversion, y finalmente la operacion se
puede llevar a cabo. Entender este proceso nos permitira aprovechar las posibilidades
de la conversion implcita de tipos cuando nuestro codigo involucre tipos de variables
mas complicados, y entender varios mensajes de error del compilador.
Es interesante notar como las conversiones implcitas de tipos pueden tener consecuen-
cias insospechadas. Consideremos las tres expresiones:
i) x = (1/2) * (x + a/x) ;
ii) x = (0.5) * (x + a/x) ;
iii) x = (x + a/x)/2 ;
Si inicialmente x=0.5 y a=0.5, por ejemplo, i) entrega el valor x=0, mientras ii) y iii)
entregan el valor x=1.5. Lo que ocurre es que 1 y 2 son enteros, de modo que 1/2 = 0.
De acuerdo a lo que dijimos, uno esperara que en i), como conviven n umeros reales
con enteros, los n
umeros enteros fueran convertidos a reales y, por tanto, la expresion
tuviera el resultado esperado, 1.5. El problema es la prioridad de las operaciones. No
todas las operaciones tienen igual prioridad (las multiplicaciones y divisiones se realizan
antes que las sumas y restas, por ejemplo), y esto permite al compilador decidir cual
operacion efectuar primero. Cuando se encuentra con operaciones de igual prioridad
(dos multiplicaciones, por ejemplo), se procede a efectuarlas de izquierda a derecha.
Pues bien, en i), la primera operacion es 1/2, una division entre enteros, i.e. cero. En
ii) no hay problema, porque todas son operaciones entre reales. Y en iii) la primera
operacion es el parentesis, que es una operacion entre reales. Al dividir por 2 este es
convertido a real antes de calcular el resultado.
i) a
un podra utilizarse, cambiando el prefactor del parentesis a 1.0/2.0, una practica
que sera conveniente adoptar como standard cuando queremos utilizar enteros den-
tro de expresiones reales, para evitar errores que pueden llegar a ser muy difciles de
detectar.
56 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
if (a==b) {
cout << "a es igual a b" << endl;
}
En este y en muchos de los ejemplos que siguen, los parentesis cursivos son opcionales.
Ellos indican simplemente un grupo de instrucciones que debe ser tratado como una sola
instruccion. En el ejemplo anterior, los parentesis cursivos despues del if (o despues de
un while, for, etc. mas adelante) indican el conjunto de instrucciones que deben o no
ejecutarse dependiendo de si cierta proposicion es verdadera o falsa. Si ese conjunto de
instrucciones es una sola, se pueden omitir los parentesis:
if (c!=d) {
cout << "c es distinto de d" << endl;
}
else {
cout << "c es igual a d" << endl;
}
if (e > f) {
cout << "e es mayor que f" << endl;
}
else if (e == f) {
cout << "e es igual a f" << endl;
}
else {
cout << "e es menor que f" << endl;
}
Para C++, una expresion verdadera es igual a 1, y una falsa es igual a 0. Esto es, cuando
escribimos if(e>f), y e>f es falsa, en realidad estamos diciendo if(0). A la inversa, 0
es considerada una expresion falsa, y cualquier valor no nulo es considerado una expresion
verdadera. As, podramos hacer que una porcion del codigo siempre se ejecute (o nunca)
poniendo directamente if(1) o if(0), respectivamente.
Naturalmente, lo anterior no tiene mucho sentido, pero un error habitual (y particular-
mente difcil de detectar) es escribir a = b en vez de a == b en una expresion logica. Esto
normalmente trae consecuencias indeseadas, pues la asignacion a = b es una funcion que se
eval
ua siempre al nuevo valor de a. En efecto, una expresion como a=3 siempre equivale a
verdadero, y a=0 siempre equivale a falso. Por ejemplo, en el siguiente programa:
#include <iostream>
int main(){
int k=3;
if (k==3){
cout << "k es igual a 3" << endl;
}
k=4;
if (k=3){
cout << "k es igual a 3" << endl;
}
return 0;
}
k es igual a 3
k es igual a 3
2.2.2. Expresi
on condicional.
Una construccion if else simple, que solo asigna un valor distinto a una misma variable
seg
un si una proposicion es verdadera o falsa, es muy com
un en programacion. Por ejemplo:
58 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
if (a==b) {
c = 1;
} else {
c = 0;
}
Existen dos maneras de compactar este codigo. Este se puede reemplazar por
if (a==b) c = 1;
else c = 0;
Sin embargo, esto no es recomendable por razones de claridad al leer el codigo. Una expresion
mas compacta y clara, se consigue usando el operador ternario ? :
c = (a==b) ? 1 : 0;
2.2.3. switch.
La instruccion switch permite elegir m ultiples opciones a partir del valor de una variable
entera. En el ejemplo siguiente tenemos que si i==1 la ejecucion continuara a partir del caso
case 1:, si i==2 la ejecucion continuara a partir del caso case 2: y as sucesivamente. Si
i toma un valor que no esta enumerado en ning un case y existe la etiqueta default, la
ejecucion continuara a partir de ah. Si no existe default, la ejecucion contin ua luego del
u
ltimo parentesis cursivo.
switch (i)
{
case 1:
{
cout << "Caso 1." << endl;
}
break;
case 2:
{
cout << "Caso 2." << endl;
}
break;
default:
{
cout << "Otro caso." << endl;
}
break;
}
2.2. CONTROL DE FLUJO. 59
La instruccion break permite que la ejecucion del programa salte a la lnea siguiente despues
de la serie de instrucciones asociadas a switch. De esta manera solo se ejecutaran las lneas
correspondientes al case elegido y no el resto. Por ejemplo, si i==1 veramos en pantalla
solo la lnea Caso 1. En el otro caso, si no existieran los break, y tambien i==1, entonces
veramos en pantalla las lneas Caso 1., Caso 2. y Otro caso. La instruccion default es
opcional.
2.2.4. for.
Una instruccion que permite repetir un bloque de instrucciones un n umero definido de
veces es el for. Su sintaxis comienza con una o varias inicializaciones, luego una condicion
logica de continuacion mientras sea verdadera, y finalmente una o mas expresiones que se
evaluan vuelta por vuelta no incluyendo la primera vez. Siguiendo al for(...) viene una
instruccion o un bloque de ellas encerradas entre parentesis de llave. En el ejemplo siguiente
la variable entera i es inicializada al valor 1, luego se verifica que la condicion logica sea
cierta y se ejecuta el bloque de instrucciones. A la vuelta siguiente se eval ua la expresion a
la extrema derecha (suele ser uno o mas incrementadores), se verifica que la condicion logica
se mantenga cierta y se ejecuta nuevamente el bloque de instrucciones. Cuando la condicion
logica es falsa se termina el loop, saltando la ejecucion a la lnea siguiente al parentesis que
indica el fin del bloque de instrucciones del for. En este ejemplo, cuando i=4 la condicion
de continuacion sera falsa y terminara la ejecucion del for.
for (int i = 1; i < 4; i++) {
cout << "Valor del indice: " << i << endl;
}
El output correspondiente es:
Valor del indice: 1
Valor del indice: 2
Valor del indice: 3
Cualquier variable declarada en el primer argumento del for es local al loop. En este caso,
la variable i es local, y no interfiere con otras posibles variables i que existan en nuestro
codigo.
for es una instruccion particularmente flexible. En el primer y tercer argumento del for
se puede colocar mas de una instruccion, separadas por comas. Esto permite, por ejemplo,
involucrar mas de una variable en el ciclo. El codigo:
for (int i=0, k=20; (i<10) && (k<50); i++, k+=6) {
cout << "i + k = " << i + k << endl;
}
resulta en el output:
i + k = 20
i + k = 27
i + k = 34
60 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
i + k = 41
i + k = 48
Ademas, la condicion de continuacion (segundo argumento del for), no tiene por que de-
pender de las variables inicializadas en el primer argumento. Y el tercer argumento no tiene
por que ser un incremento o decremento de las variables del loop; puede ser cualquier expre-
sion que queramos ejecutar cada vez que un ciclo termina. En el siguiente ejemplo, ademas
de incrementar los contadores en cada ciclo, se enva un mensaje a pantalla:
for (int i=1, k=2;k<5 && i<20;k++, i+=2, cout << "Fin iteracion" << endl){
cout << " i = " << i <<,;
cout << " k = " << k << endl;
}
i = 1, k = 2
Fin iteracion
i = 3, k = 3
Fin iteracion
i = 5, k = 4
Fin iteracion
Todos los argumentos del for son opcionales (no los ;), por lo cual se puede tener un for
que carezca de inicializacion y/o de condicion de continuacion y/o de una expresion que se
eval
ue en cada iteracion.
Un caso tpico en que se aprovecha la opcionalidad de los argumentos del for es para
tener un loop infinito, que puede servir para dejar el programa en pausa indefinida. Para salir
del loop (y en general, para detener cualquier programa en C++), hay que presionar ^C:
da la salida a pantalla:
0 1 2 3 4
for (int i=1, k=2;k<5 && i<8;k++, i+=2, cout << "Fin iteracion" << endl){
cout << " i = " << i << ", k = " << k << endl;
k = k+5;
}
El resultado es:
i = 1, k = 2
Fin iteracion
En vez de pasar por el ciclo tres veces, como ocurra originalmente, el programa sale del loop,
al cabo del primer ciclo, k = 2 + 5 = 7 > 5.
En general no es una buena practica modificar las variables internas del ciclo en medio
de el, porque no es muy ordenado, y el desorden normalmente conduce a los errores en
programacion, pero ocasionalmente puede ser u til hacer uso de esta libertad que proporciona
el lenguaje. Los ciclos for pueden anidarse, tal que uno contenga a otro completamente.
2.2.5. while.
La instruccion while permite repetir un bloque de instrucciones encerradas entre parente-
sis de llave mientras la condicion logica que acompa na al while se mantenga cierta. La con-
dicion es evaluada antes de que comience la primera iteracion; si es falsa en esta o en una
posterior evaluacion no se ejecuta el bloque de instrucciones que le siguen y se contin ua la
ejecucion en la lnea siguiente al parentesis que indica el fin del bloque asociado al while.
Hay que notar que la instruccion while podra no ejecutarse ni una sola vez si la condicion
no se cumple inicialmente. Un ejemplo simple:
int i=1;
while (i < 3) {
cout << i++ << " ";
}
que da por resultado: 1 2.
En el siguiente loop, la salida sera: 5 4 3 2 1 (Por que?)
int k=5 ;
while(k) {
cout << k-- <<" ";
}
do {
cout << "Este es un segundo loop infinito, ^C para detenerlo"<< endl;
} while (1);
2.2.7. goto.
Existe tambien en C++ una instruccion goto que permite saltar de un punto a otro del
programa (goto salto; permite saltar a la lnea que contiene la instruccion salto:). Sin
embargo, se considera una mala tecnica de programacion usar goto, y siempre se puede di-
se
nar un programa evitandolo. Es altamente no recomendable, pero si su utilizacion simplifica
el codigo se puede usar.
2.3. Funciones.
Las funciones nos permiten programar partes del procedimiento por separado. Un ejemplo
simple de ellas lo vimos en la subseccion 2.1.2.
2.3.2. return.
Si deseamos definir una funcion que calcule una raz cuadrada, evidentemente esperamos
que la funcion nos entregue un resultado: el valor de la raz cuadrada. En este caso hay que
traspasar el valor de una variable desde la funcion al programa que la llamo. Esto se consigue
con return. Veamos un ejemplo muy simple:
int numero(){
int i = 3;
return i;
}
int main(){
cout << "Llamamos a la funcion" << endl;
cout << "El numero es: " << numero() << endl;
int i = 5;
i = i + numero();
cout << "El numero mas 5 es: " << i << endl;
2.3. FUNCIONES. 63
return 0;
}
En este caso, la funcion simplemente entrega el valor de la variable interna i, es decir 3, el
cual puede ser usado para salida en pantalla o dentro de operaciones matematicas corrientes.
Separando declaracion e implementacion de la funcion, el ejemplo anterior se escribe:
int numero();
int numero(){
int i = 3;
return i;
}
Dos observaciones u
tiles:
a) La declaracion de la funcion lleva antepuesto el tipo de variable que la funcion entrega.
En el ejemplo, la variable entregada es un entero, i, y la declaracion debe ser, por tanto,
int numero(). Podemos tener funciones tipo double, char, long, etc., de acuerdo al
tipo de variable que corresponde a return.
b) La variable i que se usa dentro de main() y la que se usa dentro de numero() son
distintas. A pesar de que tienen el mismo nombre, se pueden usar independientemente
como si se llamaran distinto. Se dice que i es una variable local.
Despues de return debe haber una expresion que se eval ue a una variable del tipo co-
rrespondiente, ya sea explcitamente o a traves de un cast implcito. Las siguientes funciones
devuelven un double al programa:
double f1(){
double l = 3.0;
return l;
}
double f2(){
double l = 3.0, m = 8e10;
return l*m;
}
double f3(){
int l = 3;
return l;
}
Sin embargo, la siguiente funcion hara que el compilador emita una advertencia, pues se
esta tratando de devolver un double donde debera ser un int, y la conversion implica una
perdida de precision:
64 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
int f4(){
double l=3.0;
return l;
}
Naturalmente, podemos modificar la funcion anterior haciendo una conversion explcita antes
de devolver el valor: return int(l).
int main(){
int i = 3;
cout << "El valor de la funcion es " << funcion(i)
<< endl;
cout << "El valor del parametro es " << i << endl;
return 0 ;
}
El valor de la funcion es 7
El valor del parametro es 3
La funcion funcion entrega el valor del parametro mas 4. Usamos el mismo nombre (i)
para las variables en main y funcion, pero son variables locales, as que no interfieren. Lo
importante es notar que cuando se llama a la funcion, la reasignacion del valor de i (i+=4)
ocurre solo para la variable local en funcion; el parametro externo mantiene su valor.
Separando declaracion e implementacion el ejemplo anterior se escribe:
int funcion(int);
int main(){...}
Si nuestra funcion necesita mas parametros, basta separarlos con comas, indicando para
cada uno su tipo:
int funcion2(int,double);
void funcion3(double,int,float);
double funcion4(float);
El compilador verifica cuidadosamente que cada funcion sea llamada con el n umero de
parametros adecuados, y que cada parametro corresponda al tipo especificado. En los ejem-
plos anteriores, funcion2 debe ser llamada siempre con dos argumentos, el primero de los
cuales es int y el segundo double. Como siempre, puede ser necesario un cast implcito (si se
llama funcion2 con el segundo argumento int, por ejemplo), pero si no existe una regla de
conversion automatica (llamando a funcion2 con el primer argumento double, por ejemplo),
el compilador enviara una advertencia. Ademas, el compilador verifica que el valor de retorno
de la funcion sea usado como corresponde. Por ejemplo, en las dos lneas:
double m = funcion2(2,1e-3);
int k = funcion4(0.4);
la primera compilara exitosamente (pero hay un cast implcito), y la segunda dara una
advertencia.
Existen dos modos de transferir parametros a una funcion:
a) Por valor. Se le pasan los parametros para que la funcion que es llamada copie sus
valores en sus propias variables locales, las cuales desapareceran cuando la funcion
termine y no tienen nada que ver con las variables originales.
Hasta ahora, en todos los ejemplos de esta subseccion el traspaso de parametros ha sido
por valor. En la funcion int funcion(int), en el codigo de la pagina 64, lo que ha
ocurrido es que la funcion copia el valor de la variable externa i en una nueva variable
(que tambien se llama i, pero esta en otra direccion de memoria). El valor con el que
trabaja la funcion es la copia, manteniendo inalterada la variable original.
int main()
{
int i = 3;
cout << "El valor de la funcion es " << funcion(i)
<< endl;
cout << "El valor del parametro es " << i << endl;
return 0;
66 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
}
int funcion(int & i)
{
i+=4;
return i;
}
El valor de la funcion es 7
El valor del parametro es 7
Debido a que las variables dejan de ser locales, el paso de parametros por referencia
debe ser usado con sabidura. De hecho el ejemplo presentado es poco recomendable.
Peor aun, el problema es no solo que las variables dejan de ser locales, sino que es
imposible saber que no lo son desde el main. En efecto, el main en ambas versiones de
funcion es el mismo. Lo u nico que cambio es la declaracion de la funcion. Puesto que un
usuario normal usualmente no conoce la declaracion e implementacion de cada funcion
que desea usar (pues pueden haber sido hechas por otros programadores), dejamos al
usuario en la indefension.
Por otro lado, hay al menos dos situaciones en que el paso de referencia es la u nica
opcion viable para entregar los parametros. Un caso es cuando hay que cuidar el uso
de la memoria. Supongamos que una funcion necesita un parametros que es una matriz
de 10 millones de filas por 10 millones de columnas. Seguramente estaremos llevando al
lmite los recursos de nuestra maquina, y sera una torpeza pasarle la matriz por valor:
ello involucrara, primero, duplicar la memoria utilizada, con el consiguiente riesgo de
que nuestro programa se interrumpa; y segundo, hara el programa mas lento, porque
la funcion necesitara llenar su version local de la matriz elemento por elemento. Es
decir, nada de eficiente. En esta situacion, el paso por referencia es lo adecuado.
Un segundo caso en que el paso por referencia es recomendable es cuando efectivamente
nuestra intencion es cambiar el valor de las variables. El ejemplo tpico es el intercambio
de dos variables entre s, digamos a1=1 y a2=3. Luego de ejecutar la funcion queremos
que a1=3 y a1=1. El siguiente codigo muestra la definicion y el uso de una funcion para
esta tarea, y por cierto requiere el paso de parametros por referencia:
#include <iostream>
void swap(int &,int &);
int main(){
int i = 3, k=10;
swap(i,k);
2.3. FUNCIONES. 67
El output es:
Primer argumento: 10
Segundo argumento: 3
En el ejemplo de la matriz anterior, sera interesante poder pasar el parametro por refe-
rencia, para ahorrar memoria y tiempo de ejecucion, pero sin correr el riesgo de que nuestra
matriz gigantesca sea modificada por accidente. Afortunadamente existe el modo de hacerlo,
usando una palabra que ya hemos visto antes: const. En el siguiente codigo:
int f5(const int &);
int main(){...}
int f5(const int & i){...};
f5 recibira su u
nico argumento por referencia, pero, debido a la presencia del modificador
const, el compilador avisara si se intenta modificar el argumento en medio del codigo de la
funcion.
2.3.4. Par
ametros por defecto.
C++ permite que omitamos algunos parametros de la funcion llamada, la cual reem-
plaza los valores omitidos por otros predeterminados. Tomemos por ejemplo la funcion
int funcion(int); de la subseccion 2.3.3, y modifiquemosla de modo que si no le entrega-
mos parametros, asuma que el n
umero entregado fue 5:
int funcion(int i = 5){
i+=4;
return i;
}
int main(){
cout << "El resultado default es " << funcion() << endl;
int i = 3;
cout << "Cuando el parametro vale " << i <<
" el resultado es " << funcion(i) << endl;
return 0;
}
68 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
El resultado default es 9
Cuando el parametro vale 3 el resultado es 7
En este caso, f1(2), f1(2,8), f2(2.3,5), f3(3), f3(), y muchas otras, son todas llamadas
validas de estas funciones. Cada vez, los parametros no especificados son reemplazados por
sus valores predeterminados.
double raiz(double);
Debido a la naturaleza de la funcion raz cuadrada, raiz() no tendra sentido, y por tanto
no corresponde declararla con un valor default.
2.3. FUNCIONES. 69
Ahora debemos pensar en como calcular la raz cuadrada. Usando una variante del metodo
de Newton-Raphson, se obtiene que la secuencia
1 a
xn+1 = xn +
2 xn
converge a a cuando n . Por tanto, podemos calcular la raz cuadrada con aproxima-
ciones sucesivas. El calculo terminara en el paso N , cuando la diferencia entre el cuadrado
de la aproximacion actual, xN , y el valor de a, sea menor que un cierto n umero pequeno:
2
| xN a | < 1. El valor de determinara la precision de nuestro calculo. Un ejemplo de
codigo lo encontramos a continuacion:
#include <iostream>
#include <cmath>
double raiz(double);
int main(){
double r;
cout.precision(20);
cout << "Ingrese un numero: " << endl;
cin >> r;
cout << raiz(r) << endl;
return 0 ;
}
while (fabs(dx)>epsilon){
x = (x + a/x)/2;
dx = x*x - a;
cout << "x = " << x << ", precision = " << dx << endl;
}
return x;
}
Factorial.
Otro ejemplo u
til es el calculo del factorial, definido para n
umeros naturales:
n! = n (n 1) 2 1 , 0! 1 .
La estrategia natural es utilizar un ciclo for, determinado por una variable entera i, que
va desde 1 a n, guardando los resultados en una variable auxiliar que contiene el producto
de todos los n
umeros naturales desde 1 hasta i:
#include <iostream>
int factorial(int);
int main(){
int n=5 ;
cout << "El factorial de " << n << " es: " << factorial(n) << endl;
return 0 ;
}
int factorial(int i)
{
int f =1;
for (int j=1;j<=i;j++){
f = f*j;
}
return f;
}
Observar que la variable auxiliar f, que contiene el producto de los primeros i n umeros
naturales, debe ser inicializada a 1. Si se inicializara a 0, factorial(n) sera 0 para todo n.
Esta funcion no considera el caso n=0, pero al menos para el resto de los naturales fun-
cionara bien.
2.3. FUNCIONES. 71
Alcance (scope) La seccion del codigo durante la cual el nombre de una variable puede ser
usado. Comprende desde la declaracion de la variable hasta el final del cuerpo de la
funcion donde es declarada.
Si la variable es declarada dentro de una funcion es local . Si es definida fuera de todas
las funciones (incluso fuera de main), la variable es global.
Visibilidad Indica cuales de las variables, actualmente al alcance, pueden ser accesadas. En
nuestros ejemplos (subseccion 2.3.3), la variable i en main aun esta al alcance dentro
de la funcion funcion, pero no es visible, y por eso es posible reutilizar el nombre.
Tiempo de vida Indica cuando las variables son creadas y cuando destruidas. En general
este concepto coincide con el alcance (las variables son creadas cuando son declaradas y
destruidas cuando la funcion dentro de la cual fueron declaradas termina), salvo porque
es posible definir: (a) variables din
amicas, que no tienen alcance, sino solo tiempo de
vida; (b) variables estaticas, que conservan su valor entre llamadas sucesivas de una
funcion (estas variables tienen tiempo de vida mayor que su alcance). Para declarar
estas ultimas se usa un modificador static.
#include <iostream>
int f();
int main(){
int f(){
int x=0;
x++;
return x;
}
La funcion f simplemente toma el valor inicial de x y le suma 1. Como cada vez que la
funcion es llamada la variable local x es creada e inicializada, el resultado de este programa
es siempre un 1 en pantalla:
72 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
1
1
Ahora modifiquemos la funcion, haciendo que x sea una variable estatica:
#include <iostream>
int f();
int main(){
int f(){
static int x=0;
x++;
return x;
}
Ahora, al llamar a f por primera vez, la variable x es creada e inicializada, pero no
destruida cuando la funcion termina, de modo que conserva su valor cuando es llamada por
segunda vez:
1
2
Veamos un ejemplo de una variable estatica en el calculo del factorial:
int factorial2(int i=1){
static int fac = 1;
fac*=i;
return fac ;
}
int main (){
int n=5;
int m=n;
while(n>0) factorial2(n--);
cout << "El factorial de "<< m << " es = " << factorial2() << endl;
return 0 ;
}
La idea, si se desea calcular el factorial de 5, por ejemplo, es llamar a la funcion factorial2
una vez, con argumento n = 5, y despues disminuir n en 1. Dentro de la funcion, una variable
estatica (fac) aloja el valor 1 5 = 5. Luego se llama nuevamente con n = 4, con lo cual
fac=1*5*4, y as sucesivamente, hasta llegar a n = 1, momento en el cual fac=1*5*4*3*2*1.
2.3. FUNCIONES. 73
Al disminuir n en 1 una vez mas, la condicion del while es falsa y se sale del ciclo. Al llamar
una vez mas a factorial2, esta vez sin argumentos, el programa asume que el argumento
tiene el valor predeterminado 1, y as el resultado es 1*5*4*3*2*1*1, es decir 5!.
Observemos el uso del operador de decremento en este programa: factorial2(n--) llama
a la funcion con argumento n y despues disminuye n en 1. Esto es porque el operador de
decremento esta actuando como sufijo, y es equivalente a las dos instrucciones:
factorial2(n);
n--;
2.3.7. Recursi
on.
C++ soporta un tipo especial de tecnica de programacion, la recursion, que permite que
una funcion se llame a s misma (esto es no trivial, por cuanto si definimos, digamos, una
funcion f, dentro del cuerpo de la implementacion no hay ninguna declaracion a una funcion
f, y por tanto en principio no se podra usar f porque dicho nombre no estara en scope;
C++ permite soslayar este hecho). La recursion permite definir de modo muy compacto una
funcion que calcule el factorial de un n
umero entero n.
int main(){
int n=5;
cout << "El factorial de "<< n << " es = " << factorial3(n) << endl;
return 0;
}
Este tercer codigo para el calculo del factorial s considera el caso n = 0, y ademas es mas
eficiente, al ser mas compacto.
La recursion debe ser empleada con cuidado. Es importante asegurarse de que existe
una condicion para la cual la recursion se detenga, de otro modo, caeramos en una recursion
infinita que hara in
util nuestro programa. En el caso del factorial, pudimos verificar que dicha
condicion existe, por tanto el programa es finito. En situaciones mas complicadas puede no
ser tan evidente, y es responsabilidad del programador como siempre revisar que todo
este bajo control.
Para elevar a potencias enteras, es mas conveniente usar la forma explcita en vez de la
funcion pow, i.e. calcular x^3 como x*x*x es mas eficiente computacionalmente que pow(x,3),
debido a los algoritmos que usa pow para calcular potencias. Estos son mas convenientes
cuando las potencias no son enteras, en cuyo caso no existe una forma explcita en terminos
de productos.
2.4. Punteros.
Una de las ventajas de C++ es permitir el acceso directo del programador a zonas de
memoria, ya sea para crearlas, asignarles un valor o destruirlas. Para ello, ademas de los tipos
de variables ya conocidos (int, double, etc.), C++ proporciona un nuevo tipo: el puntero.
2.4. PUNTEROS. 75
El puntero no contiene el valor de una variable, sino la direccion de memoria en la cual dicha
variable se encuentra.
Un peque no ejemplo nos permite ver la diferencia entre un puntero y la variable a la cual
ese puntero apunta:
int main(){
int i = 42;
int * p = &i;
cout << "El valor del puntero es: " << p << endl;
cout << "Y apunta a la variable: " << *p << endl;
return 0;
}
En este programa definimos una variable i entera. Al crear esta variable, el programa
reservo un espacio adecuado en alg
un sector de la memoria. Luego pusimos, en esa direccion
de memoria, el valor 42. En la siguiente lnea creamos un puntero a i, que en este caso
denominamos p. Los punteros no son punteros a cualquier cosa, sino punteros a un tipo
particular de variable. Ello es manifiesto en la forma de la declaracion: int * p. En la
misma lnea asignamos a este puntero un valor. Ese valor debe ser tambien una direccion de
memoria, y para eso usamos &i, que es la direccion de memoria donde esta i. Ya hemos visto
antes el uso de & para entregar una direccion de memoria, al estudiar paso de parametros a
funciones por referencia (2.3.3).
Al ejecutar este programa vemos en pantalla los mensajes:
int main(){
int * p = new int;
*p = 42;
cout << "El valor del puntero es: " << p << endl;
cout << "Y apunta a la variable: " << *p << endl;
delete p;
76 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
return 0;
}
La primera lnea crea un nuevo puntero a int llamado p. new verifica que haya suficiente
memoria para alojar un nuevo int, y si es as reserva ese espacio de memoria. En p queda la
direccion de la memoria reservada. Esto es equivalente a la declaracion int i; del programa
anterior, salvo que ahora la unica manera de accesar esa direccion de memoria es a traves del
puntero p. A continuacion se coloca dentro de esa direccion (observar la presencia del operador
de dereferenciacion *) el numero 42. El programa manda a pantalla la misma informacion
que la version anterior, salvo que seguramente el valor de p sera distinto.
Finalmente, ya que el puntero no volvera a ser usado, la direccion de memoria debe ser
liberada para que nuestro u otros programas puedan utilizarla. Ello se realiza con el operador
delete. Todo puntero creado con new debe ser, cuando ya no se utilice, borrado con delete.
Ello evitara desagradables problemas en nuestro programa debido a fuga de memoria (memory
leak ).
Los punteros tienen gran importancia cuando de manejar datos dinamicos se trata, es
decir, objetos que son creados durante la ejecucion del programa, en n umero imposible de
predecir al momento de compilar. Por ejemplo, una aplicacion X-windows normal que crea
una, dos, tres, etc. ventanas a medida que uno abre archivos. En este caso, cada ventana es
un objeto dinamico, creado durante la ejecucion, y la u nica forma de manejarlo es a traves
de un puntero a ese objeto, creado con new cuando la ventana es creada, y destruido con
delete cuando la ventana es cerrada.
int a[5];
double r[3] = {3.5, 4.1, -10.8};
char palabra[5];
Una vez declarada la matriz (digamos a[5]), los valores individuales se accesan con a[i],
con i desde 0 a 4. Por ejemplo, podemos inicializar los elementos de la matriz as:
a[0] = 3;
a[3] = 5; ...
o si queremos ingresarlos desde el teclado:
for (i = 0; i < 5; i++){
cin >> a[i];
}
Y si deseamos escribirlos en pantalla:
2.5. MATRICES O ARREGLOS. 77
int main(){
double matriz[5] = {3.5, 5.2, 2.4, -0.9, -10.8};
PrintMatriz(5, matriz);
return 0;
}
Observemos que la funcion debe recibir dos parametros, uno de los cuales es la dimension
de la matriz. Esto se debe a que cuando las matrices son usadas como parametros la infor-
macion de su dimension no es traspasada, y debe ser comunicada independientemente. Una
ligera optimizacion al programa anterior es modificar main a:
int main()
{
const int dim = 5;
double matriz[dim] = {3.5, 5.2, 2.4, -0.9, -10.8};
PrintMatriz(dim, matriz);
return 0;
}
De este modo, si eventualmente cambiamos de opinion y deseamos trabajar con matrices
de longitud distinta, solo hay que modificar una lnea de codigo (la primera) en todo el
programa, el cual puede llegar a ser bastante largo por cierto. (En el ejemplo, tambien habra
que cambiar la lnea de inicializacion de la matriz, porque asume que la matriz requiere solo 5
elementos, pero de todos modos debera ser clara la enorme conveniencia.) Podemos reescribir
este programa con un comando de preprocesador para hacer la definicion de la dimension:
#include <iostream>
#define DIM 5
78 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
int main(){
double matriz[DIM] = {3.5, 5.2, 2.4, -0.9, -10.8};
PrintMatriz(DIM, matriz);
return 0;
}
2.5.3. Asignaci
on din
amica.
La reserva de memoria para la matriz podemos hacerla en forma dinamica ocupando el
operador new que pedira al sistema la memoria necesaria, si esta disponible el sistema se
la asignara. Como con cualquier puntero, una vez desocupado el arreglo debemos liberar la
memoria con el comando delete.
#include <iostream>
int main()
{
cout<<"Ingrese la dimension deseada :" ;
int dim ;
cin >> dim ;
double * matriz = new double[dim] ; // Reserva la memoria
for(int i=0; i < dim; i++) {
cout << "Ingrese elemento "<< i <<" : ";
cin >> matriz[i] ;
}
Este ejemplo permite apreciar una gran ventaja del uso de punteros, al permitirnos libe-
rarnos de definir la dimension de una matriz como una constante. Aqu, dim es simplemente
un int. La asignacion dinamica permite definir matrices cuya dimension se determina recien
durante la ejecucion.
Observemos finalmente que la liberacion de memoria, en el caso de arreglos, se hace con
el operador delete [], no delete como en los punteros usuales.
2.5. MATRICES O ARREGLOS. 79
double array[10][8];
int array[2][3] = {{1, 2, 3},
{4, 5, 6}};
Una operacion usual es definir primero las dimensiones de la matriz, y luego llenar sus
elementos uno por uno (o desplegarlos en pantalla), recorriendo la matriz ya sea por filas o
por columnas. Hay que tener cuidado del orden en el cual uno realiza las operaciones. En
el siguiente codigo, definimos una matriz de 10 filas y 3 columnas, la llenamos con ceros
elemento por elemento, y luego inicializamos tres de sus elementos a n umeros distintos de
cero. Finalmente desplegamos la matriz resultante en pantalla:
#include <iostream>
int main(){
const int dimx=3, dimy=10;
double a[dimy][dimx];
a[0][0]=1;
a[3][2]=2;
a[9][2]=3;
int main()
{
int width;
int height;
width = 200;
height = 400;
resolver el problema es aceptar que una cadena tiene longitud arbitraria, pero debe indicar
donde termina. Esto se hace con el char nulo: \0. As, para asignar a la variable palabra
el valor Hola, debe definirse como una matriz de dimension 5 (una mas que el n umero de
letras):
Para escribir Hola en pantalla basta recorrer los elementos de palabra uno a uno:
Si tuvieramos que hacer esto cada vez que queremos escribir algo a pantalla no sera muy
comodo. Por ello, tambien podemos escribir Hola en pantalla simplemente con cout << "Hola",
y de hecho ese fue el primer ejemplo de este captulo. De hecho, la declaracion de palabra
podra haberse escrito:
Esto ya es bastante mas comodo, aunque persiste la inconsistencia de definir palabra con
dimension 5, cuando en realidad al lado derecho de la asignacion hay un objeto con solo 4
elementos (visibles).
Este y otros problemas asociados con el manejo convencional de cadenas en C++ se
resuelven incluyendo el header string.
string.
El codigo anterior se puede reescribir:
#include <iostream>
#include <string>
int main(){
string palabra = "Hola";
cout << palabra << endl;
return 0;
}
Observar que la lnea a incluir es #include <string>, sin la extension .h. Al incluir
string, las cadenas pueden ser declaradas como objetos tipo string en vez de arreglos
de char. El hecho de que ya no tengamos que definir a priori la dimension de la cadena
es una gran ventaja. De hecho, permite ingresar palabras desde el teclado trivialmente, sin
preocuparse de que el input del usuario sea demasiado grande (tal que supere la dimension del
arreglo que podamos haber declarado inicialmente) o demasiado corto (tal que se traduzca
en un despilfarro de memoria por reservar mas memoria para el arreglo de la que realmente
se necesita):
82 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
#include <iostream>
#include <string>
int main(){
string palabra;
cin >> palabra;
return 0;
}
Ademas, este nuevo tipo string permite acceder a un sin n
umero de funciones adicionales
que facilitan enormemente el manejo de cadenas. Por ejemplo, las cadenas se pueden sumar,
donde la suma de cadenas a y b esta definida (siguiendo la intuicion) como la cadena que
resulta de poner b a continuacion de a:
#include <iostream>
#include <string>
int main(){
string texto1 = "Primera palabra";
string texto2 = "Segunda palabra";
cout << texto1 << endl << texto2 << endl;
cout << texto1 + ", " + texto2 << endl;
// La ultima linea es equivalente a:
// string texto3 = texto1 + ", " + texto2;
// cout << texto3 << endl;
return 0 ;
}
El output de este programa sera: Primera palabra, Segunda palabra.
Dijimos que es muy facil ingresar una cadena desde el teclado, pues no es necesario
definir la dimension desde el comienzo. Sin embargo, el codigo anterior, usando cin, no
es muy general, porque el input termina cuando el usuario ingresa el primer cambio de
lnea o el primer espacio. Esto es muy comodo cuando queremos ingresar una serie de va-
lores (por ejemplo, para llenar un arreglo), pues podemos ingresarlos ya sea en la forma:
1<Enter> 2<Enter> 3<Enter>, etc., o 1 2 3, etc, pero no es optimo cuando deseamos in-
gresar texto, que podra constar de mas de una palabra y, por tanto, necesariamente incluira
espacios (por ejemplo, al ingresar el nombre y apellido de una persona). Sin explicar dema-
siado por que, digamos que la solucion a este problema es utilizar una funcion asociada a cin
llamada gets, y que espera input desde el teclado hasta que el usuario de el primer cambio
de lnea. Un ejemplo simple lo encontramos en el siguiente codigo:
#include <iostream>
#include <string>
int main(){
string texto1 = "El resultado es: " ;
char * texto2;
2.6. MANEJO DE ARCHIVOS. 83
cin.gets(&texto2);
cout << texto1 + string(texto2) << endl;
return 0;
}
#include <iostream>
#include <fstream>
int main(){
ofstream nombre_logico("nombre_fisico.dat");
int i = 3, j;
cout << i << endl;
nombre_logico << i << endl;
cout << "Ingrese un numero entero: ";
cin >> j;
cout << i << endl;
nombre_logico << j << endl;
nombre_logico.close();
return 0;
}
84 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
La primera lnea de main define un objeto de tipo ofstream (output file stream). Es-
to corresponde a un archivo de salida. Dentro de main este archivo sera identificado por
una variable llamada nombre_logico, y correspondera a un archivo en el disco duro llama-
do nombre_fisico.dat. Naturalmente, el identificador nombre_logico puede ser cualquier
nombre de variable valido para C++, y nombre_fisico.dat puede ser cualquier nombre de
archivo valido para el sistema operativo. En particular, se pueden tambien dar nombres que
incluyan paths absolutos o relativos:
ofstream nombre_logico_1("/home/vmunoz/temp/nombre_fisico.dat");
ofstream nombre_logico_2("../nombre_fisico.dat");
Las lneas tercera y sexta de main envan a nombre_logico (es decir, escribe en
nombre_fisico.dat), las variables i y j. Observar la analoga que existe entre estas opera-
ciones y las que envan la misma informacion a pantalla.4 Si ejecutamos el programa y en
el teclado ingresamos el numero 8, al finalizar la ejecucion el archivo nombre_fisico.dat
tendra los dos n
umeros escritos:
3
8
Finalmente, el archivo creado debe ser cerrado (nombre_logico.close()). Si esta u ltima
operacion se omite en el codigo, no habra errores de compilacion, y el programa se encar-
gara de cerrar por s solo los archivos abiertos durante su ejecucion, pero un buen programador
debiera tener cuidado de cerrarlos explcitamente. Por ejemplo, un mismo programa podra
desear utilizar un mismo archivo mas de una vez, o varios programas podran querer acceder
al mismo archivo, y si no se ha insertado un close en el punto adecuado esto podra provocar
problemas.
El archivo indicado al declarar la variable de tipo ofstream tiene modo de escritura, para
permitir la salida de datos hacia el. Si no existe un archivo llamado nombre_fisico.dat es
creado; si existe, los contenidos antiguos se pierden y son reemplazados por los nuevos. No
siempre deseamos este comportamiento. A veces deseamos agregar la salida de un programa
a un archivo de texto ya existente. En ese caso la declaracion del archivo es diferente, para
crear el archivo en modo append:
#include <iostream>
#include <fstream>
int main(){
ofstream nombre_logico("nombre_fisico.dat",ios::app);
int i = 3;
return 0;
}
el siguiente programa,
#include <iostream>
#include <fstream>
int main(){
ifstream nombre_logico("nombre_fisico.dat");
int i, j,k,l;
cout << i << "," << j << "," << k << "," << l << endl;
nombre_logico.close();
return 0;
}
sera equivalente a asignar i=3, j=6, k=9, l=12, y luego enviar los datos a pantalla. Observar
que la sintaxis para ingresar datos desde un archivo, nombre_logico >> i, es identica a
cin >> i, para hacerlo desde el teclado. Al igual que cin, espacios en blanco son equivalentes
a cambios de lnea, de modo que el archivo podra haber sido tambien:
3 6 9 12
Por cierto, el ingreso de datos desde un archivo se puede hacer con cualquier tecnica, por
ejemplo, usando un for:
ifstream nombre_logico("nombre_fisico.dat");
int i;
for (int j=0;j<10;j++){
nombre_logico >> i;
cout << i << ",";
}
nombre_logico.close();
}
Como con ofstream, es posible separar declaracion e implementacion:
ifstream a;
a.open("b");
a.close();
esos datos agregar mas datos a continuacion del mismo archivo, o reemplazar los datos ya
existentes con otros. Necesitamos entonces un tipo de variable flexible, que pueda ser usado
como entrada y salida. Ese tipo es fstream. Todo lo que hemos dicho para ofstream y
ifstream por separado es cierto simultaneamente para fstream.5 Para especificar si el archivo
debe ser abierto en modo de escritura o lectura, open contiene el argumento ios::out o
ios::in, respectivamente. Por ejemplo, el siguiente codigo escribe el n
umero 4 en un archivo,
y luego lo lee desde el mismo archivo:
#include <iostream>
#include <fstream>
int main(){
fstream nombre_logico;
nombre_logico.open("nombre_fisico.dat",ios::out);
int i = 4,j;
nombre_logico.open("nombre_fisico.dat",ios::in);
nombre_logico >> j;
j = j++;
cout << j << endl;
nombre_logico.close();
return 0;
}
Las dos primeras lneas de main separan declaracion y asignacion, y son equivalentes a
fstream nombre_logico("nombre_fisico.dat",ios::out);, pero lo hemos escrito as pa-
ra hacer evidente la simetra entre el uso del archivo como salida primero y como entrada
despues.
De lo anterior, se deduce que:
fstream archivo_salida("salida.dat",ios::out);
fstream archivo_entrada("entrada.dat",ios::in);
es equivalente a
ofstream archivo_salida("salida.dat");
ifstream archivo_entrada("entrada.dat");
5
Nuevamente, este hecho se debe al concepto de clases que subyace a las definiciones de estos tres tipos
de variables; fstream es una clase derivada a la vez de ofstream y de ifstream, heredando las propiedades
de ambas.
88 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
-t
-s
arg1
Observar que el primer argumento del programa es siempre el nombre del propio programa.
Naturalmente, este es un ejemplo muy simple. Es tarea del programador decidir como manejar
cada una de las opciones o argumentos que se le entregan al programa desde la lnea de
comandos, escribiendo el codigo correspondiente.
Un segundo aspecto con el cual no hemos sido sistematicos es que main, como toda funcion,
tiene un tipo de retorno. En el caso de main, ese tipo debe ser int. Este int es entregado al
sistema operativo, y puede servir para determinar si el programa se ejecuto con normalidad o
si ocurrio algo anormal. Podramos hacer ese valor de retorno igual a 0 o 1, respectivamente.
As, la siguiente estructura es correcta:
int main(){
// Codigo
return 0;
}
main(){
// Codigo
}
void main(){
// Codigo
}
tambien compilan, pero el compilador emite una advertencia si es llamado con la opcion
-Wall (Warning all ). En el primer caso, la advertencia es:
En el segundo:
En general, siempre es conveniente compilar con la opcion -Wall, para lograr que nuestro
codigo este realmente correcto (g++ -Wall <archivo>.cc -o <archivo>).
90 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
2.8. Clases.
C++ dispone de una serie de tipos de variables con las cuales nos esta permitido operar:
int, double, char, etc. Creamos variables de estos tipos y luego podemos operar con ellas:
int x, y;
x = 3;
y = 6;
int z = x + y;
No hay, sin embargo, en C++, una estructura predefinida que corresponda a n umeros
complejos, vectores de dimension n o matrices, por ejemplo. Y sin embargo, nos agradara
disponer de n
umeros complejos que pudieramos definir como
z = (3,5);
w = (6,8);
y que tuvieran sentido las expresiones
a = z + w;
b = z * w;
c = z / w;
d = z + 3;
e = modulo(z);
f = sqrt(z);
Todas estas expresiones son completamente naturales desde el punto de vista matematico,
y sera bueno que el lenguaje las entendiera. Esto es imposible en el estado actual, pues, por
ejemplo, el signo + es un operador que espera a ambos lados suyos un n umero. Sumar cualquier
cosa con cualquier cosa no significa nada necesariamente, as que solo esta permitido operar
con n umeros. Pero los humanos sabemos que los complejos son n umeros. Como decrselo
al computador? Como convencerlo de que sumar vectores o matrices es tambien posible
matematicamente, y que el mismo signo + debera servir para todas estas operaciones?
La respuesta es: a traves del concepto de clases. Lo que debemos hacer es definir una clase
de n umeros complejos. Llamemosla Complejo. Una vez definida correctamente, Complejo
sera un tipo mas de variable que el compilador reconocera, igual que int, double, char, etc.
Y sera tan facil operar con los Complejos como con todos los tipos de variables preexistentes.
Esta facilidad es la base de la extensibilidad de que es capaz C++, y por tanto de todas las
propiedades que lo convierten en un lenguaje muy poderoso.
Las clases responden a la necesidad del programador de construir objetos o tipos de datos
que respondan a sus necesidades. Si necesitamos trabajar con vectores de 5 coordenadas,
sera natural definir una clase que corresponda a vectores con 5 coordenadas; si se trata de
un programa de administracion de personal, la clase puede corresponder a un empleado, con
sus datos personales como elementos.
Si bien es cierto uno puede trabajar con clases en el contexto de orientacion al procedi-
miento, las clases muestran con mayor propiedad su potencial con la orientacion al objeto,
donde cada objeto corresponde a una clase. Por ejemplo, para efectuar una aplicacion para
X-windows, la ventana principal, las ventanas de los archivos abiertos, la barra de men u, las
cajas de dialogo, los botones, etc., cada uno de estos objetos estara asociado a una clase.
2.8. CLASES. 91
2.8.1. Definici
on.
Digamos que queremos una clase para representar a los empleados de una empresa.
Llamemosla Persona. La convencion aceptada es que los nombres de las clases comiencen
con may uscula. Esto es porque las clases, recordemos, corresponderan a tipos de variables
tan validos como los internos de C++ (int, char, etc.). Al usar nombres con may uscula
distinguimos visualmente los nombres de un tipo de variable interno y uno definido por el
usuario.
La estructura mnima de la definicion de la clase Persona es:
class Persona
{
};
2.8.2. Miembros.
Se denomina miembros de una clase a todas las variables y funciones declaradas dentro de
una clase. Por ejemplo, para personas, es natural caracterizarlas por su nombre y su edad. Y
si se trata de empleados de una empresa, es natural tambien tener una funcion que entregue
su sueldo:
class Persona
{
string nombre;
fecha nacimiento;
int rut;
double edad();
};
Los miembros de una clase pueden tener cualquier nombre, excepto el nombre de la propia
clase dentro de la cual se definen, ese nombre esta reservado.
2.8.3. Miembros p
ublicos y privados.
Una clase distingue informacion (datos o funciones) privada (accesible solo a otros miem-
bros de la misma clase) y publica (accesible a funciones externas a la clase). La parte privada
corresponde a la estructura interna de la clase, y la parte publica a la implementacion (tpi-
camente funciones), que permite la interaccion de la clase con el exterior.
Consideremos ahora nuestro deseo de tener una clase que represente n umeros complejos.
Un numero complejo tiene dos n umeros reales (parte real e imaginaria), y esos son elementos
privados, es decir, parte de su estructura interna. Sin embargo, nos gustara poder modificar
y conocer esas cantidades. Eso solo puede hacerse a traves de funciones p ublicas.
92 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
class Complejo
{
private:
double real, imaginaria;
public:
void setreal(double);
void setimag(double);
double getreal();
double getimag();
};
En este ejemplo, los miembros privados son solo variables, y los miembros p ublicos son solo
funciones. Este es el caso tpico, pero puede haber variables y funciones de ambos tipos.
class Complejo
{
private:
double real, imaginaria;
public:
void setreal(double);
void setimag(double);
double getreal();
double getimag();
};
int main()
{
Complejo z, w;
z.setreal(3);
z.setimag(2.8);
w.setreal(1.5);
w.setimag(5);
cout << "El primer numero complejo es: " << z.getreal()
<< " + i*" << z.getimag() << endl;
cout << "El segundo es: " << w.getreal() << " + i*"
<< z.getimag() << endl;
return 0;
}
2.8. CLASES. 93
Vemos en la primera lnea de main como la clase Complejo se usa del mismo modo que
usaramos int o double. Ahora Complejo es un tipo de variable tan valido como los tipos
predefinidos por C++. Una vez definida la variable, el operador de seleccion (.) permite
acceder a las funciones p
ublicas correspondientes a la clase Complejo, aplicadas a la variable
particular que nos interesa: z.setreal(3) pone en la parte real del Complejo z el n umero
3, y w.setreal(1.5) hace lo propio con w.
2.8.5. Implementaci
on de funciones miembros.
Ya sabemos como declarar funciones miembros en el interior de la clase y como usarlas.
Ahora veamos como se implementan.
void Complejo::setreal(double x)
{
real = x;
}
void Complejo::setimag(double x)
{
imaginaria = x;
}
double Complejo::getreal()
{
return real;
}
double Complejo::getimag()
{
return imaginaria;
}
Como toda funcion, primero va el tipo de la funcion (void o double en los ejemplos), luego
el nombre de la funcion y los argumentos. Finalmente la implementacion. Lo diferente es que
el nombre va precedido del nombre de la clase y el operador :: .
2.8.6. Constructor.
Al declarar una variable, el programa crea el espacio de memoria suficiente para alojarla.
Cuando se trata de variables de tipos predefinidos en C++ esto no es problema, pero cuando
son tipos definidos por el usuario, C++ debe saber como construir ese espacio. La funcion
que realiza esa tarea se denomina constructor.
El constructor es una funcion publica de la clase, que tiene el mismo nombre que ella.
Agreguemos un constructor a la clase Complejo:
class Complejo
94 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
{
private:
double real,imaginaria;
public:
Complejo(double,double);
void setreal(double);
void setimag(double);
double getreal();
double getimag();
};
2.8.7. Destructor.
As como es necesario crear espacio de memoria al definir una variable, hay que deshacerse
de ese espacio cuando la variable deja de ser necesaria. En otras palabras, la clase necesita
2.9. SOBRECARGA. 95
class Complejo
{
private:
double real, imaginaria;
public:
Complejo(double,double);
~Complejo();
void setreal(double);
void setimag(double);
double getreal();
double getimag();
};
Complejo::~Complejo()
{
}
Como con los constructores, al omitir un destructor C++ genera un default, pero es una
mala costumbre. . . , etc.
Complejo z[2];
2.9. Sobrecarga.
Para que la definicion de nuevos objetos sea realmente u
til, hay que ser capaz de hacer
con ellos muchas acciones que nos seran naturales. Como ya comentamos al introducir el
concepto de clase, nos gustara sumar n
umeros complejos, y que esa suma utilizara el mismo
96 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
signo + de la suma usual. O extraerles la raz cuadrada, y que la operacion sea tan facil
como escribir sqrt(z). Lo que estamos pidiendo es que el operador + o la funcion sqrt()
sean polim orficos, es decir, que act
uen de distinto modo segun el tipo de argumento que
se entregue. Si z es un real, sqrt(z) calculara la raz de un n
umero real; si es complejo,
calculara la raz de un n
umero complejo.
La tecnica de programacion mediante la cual podemos definir funciones polimorficas se
llama sobrecarga.
Complejo sqrt(Complejo z)
{
return Complejo (z.getreal()/2, z.getimag()/2);
}
Observemos que definimos una funcion sqrt que acepta argumentos de tipo Complejo, y que
entrega un n umero del mismo tipo. Cuando pidamos la raz de un n umero, el computador
se preguntara si el numero en cuestion es un int, double, float o Complejo, y seg
un eso
escogera la version de sqrt que corresponda.
Con la definicion anterior podemos obtener la raz cuadrada de un n umero complejo
simplemente con las instrucciones:
Complejo z(1,3);
Complejo raiz = sqrt(z);
2.9.3. Coerci
on.
Sabemos definir a + b, con a y b complejos. Pero que pasa si a o b son enteros? O reales?
Pareciera que tendramos que definir no solo
2.10. HERENCIA. 97
2.10. Herencia.
Herencia es el mecanismo mediante el cual es posible definir clases a partir de otras,
preservando parte de las propiedades de la primera y agregando o modificando otras.
Por ejemplo, si definimos la clase Persona, toda Persona tendra una variable miembro
que sea su nombre. Si definimos una clase Hombre, tambien sera Persona, y por tanto debera
tener nombre. Pero ademas puede tener esposa. Y ciertamente no toda Persona tiene esposa.
Solo un Hombre.
C++ provee mecanismos para implementar estas relaciones logicas y poder definir una
clase Hombre a partir de Persona. Lo vemos en el siguiente ejemplo:
class Persona
{
private:
string nombre;
public:
Persona(string = "");
~Persona();
string getname();
}
98 CAPITULO 2. UNA BREVE INTRODUCCION
A C++.
Primero definimos una clase Persona que tiene nombre. Luego definimos una clase Hombre
a partir de Persona (con la lnea class Hombre : public Persona). Esto permite de modo
automatico que Hombre tenga tambien una variable nombre. Y finalmente, dentro de la clase
Hombre, se definen todas aquellas caractersticas adicionales que una Persona no tiene pero
un Hombre s: esposa, y funciones miembros para modificar y obtener el nombre de ella.
Un ejemplo de uso de estas dos clases:
Persona cocinera("Maria");
Hombre panadero("Claudio");
panadero.setwife("Estela");
Observemos que panadero tambien tiene una funcion getname(), a pesar de que la clase
Hombre no la define explcitamente. Esta funcion se ha heredado de la clase de la cual Hombre
se ha derivado, Persona.
2.11. Compilaci
on y debugging.
2.11.1. Compiladores.
El comando para usar el compilador de lenguaje C es gcc, para usar el compilador de
C++ es g++ y para usar el compilador de fortran 77 es g77. Centremosnos en el compilador
de C++, los demas funcionan en forma muy similar. Su uso mas elemental es:
g++ filename.cc
Esto compila el archivo filename.cc y crea un archivo ejecutable que se denomina a.out
por omision. Existen diversas opciones para el compilador, solo comentaremos una pocas.
-o exename define el nombre del ejecutable creado, en lugar del por defecto a.out.
g++ -o outputfile filename.cc
-On optimizacion de grado n que puede tomar valores de 1 (por defecto) a 3. El objetivo
inicial del compilador es reducir el tiempo de la compilacion. Con -On, el compilador
trata de reducir el tama
no del ejecutable y el tiempo de ejecucion, con n se aumenta el
grado de optimizacion.
-Wall notifica todos los posibles warnings en el codigo que esta siendo compilado.
prog.o: $(INCLUDESFILE)
misc.o: $(INCLUDESMISC)
aux.o: aux.h
$(OUTPUTFILE): $(OBJS)
2.12. MAKE & MAKEFILE. 101
La lista de destinos especifica aquellos sobre los que se aplicara la regla. El destino patron y
las dependencias patrones dicen como calcular las dependencias para cada destino. Veamos
un ejemplo:
objects = foo.o \
bar.o
all: $(objects)
Cada uno de los destinos (foo.o bar.o) es comparado con el destino patron %.o para extraer
parte de su nombre. La parte que se extrae es conocida como el tronco o stem, foo y bar en
este caso. A partir del tronco y la regla patron de las dependencias %.cc make construye los
nombres completos de ellas (foo.cc bar.cc). Ademas, en el comando del ejemplo anterior
aparecen un tipo de variables especiales conocidas como automaticas. La variable $< man-
tiene el nombre de la dependencia actual y la variable $@ mantiene el nombre del destino
actual. Finalmente un ejemplo completo:
#
# Makefile para el programa eapp
#_________________________________________________________
CXX = g++
CXXFLAGS = -Wall -O3 -mcpu=i686 -march=i686
#CXXFLAGS = -Wall -g
LIBS = -lm
BIN = eapp
$(BIN): $(OBJECTS)
$(OBJECTS): %.o:%.cc
$(CXX) -c $(CXXFLAGS) $< -o $@
clean:
rm -fr $(OBJECTS) $(BIN)
#End
Captulo 3
Gr
afica.
versi
on 4.12, 24 de Octubre del 2003
En este captulo quisieramos mostrar algunas de las posibilidades graficas presentes en Li-
nux. Nuestra intension es cubrir temas como la visualizacion, conversion, captura y creacion
de archivos graficos. Solo mencionaremos las aplicaciones principales en cada caso centrando-
nos en sus posibilidades mas que en su utilizacion especfica, ya que la mayora posee una
interfase sencilla de manejar y una amplia documentacion.
3.1. Visualizaci
on de archivos gr
aficos.
Si disponemos de un archivo grafico conteniendo alg un tipo de imagen lo primero que es
importante determinar es en que tipo de formato grafico esta codificada. Existe un numero
realmente grande de diferentes tipos de codificaciones de imagenes, cada una de ellas se
considera un formato grafico. Por razones de reconocimiento inmediato del tipo de formato
grafico se suelen incluir en el nombre del archivo, que contiene la imagen, un tro de letras
finales, conocidas como la extension, que representan el formato. Por ejemplo: bmp, tiff, jpg,
ps, eps, fig, gif entre muchas otras, si uno quiere asegurarse puede dar el comando:
jrogan@huelen:~$file mono.jpg
mono.jpg: JPEG image data, JFIF standard 1.01, resolution (DPCM), 72 x 72
De que herramientas disponemos en Linux para visualizar estas imagenes? La respuesta
es que en Linux disponemos de variadas herramientas para este efecto.
Si se trata de archivos de tipo PostScript o Encapsulated PostScript, identificados por la
extension ps o eps, existen las aplicaciones gv, gnome-gv o kghostview, todos programas que
nos permitiran visualizar e imprimir este tipo de archivos. Si los archivos son tipo Portable
Document Format, con extension pdf, tenemos las aplicaciones gv, acroread o xpdf, Con
todas ellas podemos ver e imprimir dicho formato. Una mencion especial requieren los archivos
DeVice Independent con extension dvi ya que son el resultado de la compilacion de un
documento TEX o LATEX, para este tipo de archivo existen las aplicaciones xdvi, advi, gxdvi
y kdvi por nombrar las principales. La aplicacion xdvi solo permite visualizar estos archivos
y no imprimirlos, la mayora de las otras permiten imprimirlo directamente. Si usa xdvi y
desea imprimir el documento debe transformar a ps va dvips y luego se imprime como
cualquier otro Postscript.
Para la gran mayora de formatos graficos mas conocidos y usualmente usados para al-
macenar fotos existen otra serie se programas especializados en visualizacion que son capaces
103
104 CAPITULO 3. GRAFICA.
de entender la mayora de los formatos mas usados. Entre estos programas podemos mencio-
nar: Eye of Gnome (eog), Electric Eyes (eeyes), kview o display. Podemos mencionar que
aplicaciones como display entienden sobre ochenta formatos graficos distintos entre los que
se encuentran la mayora de los formatos conocidos mas otros como ps, eps, pdf, fig, html,
entre muchos otros. Una mencion especial merece el utilitario gthumb que nos permite hacer
un preview de un directorio con muchas imagenes de manera muy facil.
3.2. Modificando im
agenes
Si queremos modificaciones como rotaciones, ampliaciones, cortes, cambios de paleta de
colores, filtros o efectos sencillos, display es la herramienta precisa. Pero si se desea intervenir
la imagen en forma profesional, el programa gimp es el indicado. El nombre gimp viene de
GNU Image Manipulation Program. Se puede usar esta aplicacion para editar y manipular
imagenes. Pudiendo cargar y salvar en una variedad de formatos, lo que permite usarlo para
convertir entre ellos. La aplicacion gimp puede tambien ser usado como programa de pintar,
de hecho posee una gran variedad de herramientas en este sentido, tales como brocha de
aire, lapiz clonador, tijeras inteligentes, curvas bezier, etc. Ademas, permite incluir plugins
que realizan gran variedad de manipulaciones de imagen. Como hecho anecdotico podemos
mencionar que la imagen oficial de Tux, el ping uino mascota de Linux, fue creada en gimp. Sin
embargo, si gimp le parece muy profesional o usted solo necesita un programa para dibujar
en el cual se entretenga su hermano menor tuxpaint es la alternativa.
3.3. Conversi
on entre formatos gr
aficos.
El problema de transformar de un formato a otro es una situacion usual en el trabajo con
archivos graficos. Muchos softwares tienen salidas muy restringidas en formato o bien usan
formatos arcaicos (gif) por ejemplo. De ah que se presenta la necesidad de convertir estos
archivos de salida en otros formatos que nos sean mas manejables o practicos. Como ya se
menciono, gimp puede ser usado para convertir entre formatos graficos. Tambien display
permite este hecho. Sin embargo, en ambos casos la conversion es va men us, lo cual lo
hace engorroso para un gran n umero de conversiones e imposible para conversiones de tipo
automatico. Existe un programa llamado convert que realiza conversiones desde la lnea de
comando. Este programa junto con display, import y varios otros forman la suite grafica
ImageMagick, una de las mas importantes en unix, en general, y en especial en Linux y que
ya ha sido migrada a otras plataformas. Ademas, de la clara ventaja de automatizacion que
proporciona convert, posee otro aspecto interesante, puede convertir un grupo de imagenes
asociadas en una secuencia de animacion o pelcula. Veamos la sintaxis para este programa:
correlativo, crea una secuencia animada con imagenes que persisten por 20 centesimas de
segundos en un formato conocido como mng.
3.5. Creando im
agenes.
Para imagenes artsticas sin duda la alternativa es gimp, todo le que se dijo respecto a
sus posibilidades para modificar imagenes se aplica tambien en el caso de crearlas. En el caso
de necesitar imagenes mas bien tecnicas como esquemas o diagramas o una ilustracion para
aclarar un problema las alternativas pueden ser xfig, sodipodi o sketch todas herramientas
vectoriales muy poderosa. Este tipo de programas son manejados por medio de men us y
permiten dibujar y manipular objetos interactivamente. Las imagenes pueden ser salvadas,
en formato propios y posteriormente editadas. La gran ventaja de estos programas es que
trabaja con objetos y no con bitmaps. Ademas, puede exportar las imagenes a otros formatos:
PostScript o Encapsulated PostScript o bien gif o jpeg.
Habitualmente los dibujos necesarios para ilustrar problemas en Fsica en tareas, pruebas
y apuntes son realizados con software de este tipo, principalmente xfig, luego exportados
a PostScript e includos en los respectivos archivos LATEX. Tambien existe una herramienta
extremadamente u til que permite convertir un archivo PostScript, generado de cualquier
manera, a un archivo fig que puede ser editado y modificado. Esta aplicacion que transforma
se llama pstoedit y puede llegar a ser realmente practica. Otra herramienta interesante es
autotrace que permite pasar una figura en bitmap a forma vectorial.
Una aparente limitacion de este tipo de software es que se podra pensar que no podemos
incluir curvas analticas, es decir, si necesitamos ilustrar una funcion gaussiana no podemos
pretender dibujarla con las herramientas de que disponen. Sin embargo, este problema
puede ser resuelto ya que software que grafica funciones analticas, tales como gnuplot,
106 CAPITULO 3. GRAFICA.
permite exportar en formato que entienden los programas vectoriales (fig, por ejemplo)
luego podemos leer el archivo y editarlo. Ademas, xfig permite importar e incluir imagenes
del tipo bitmap, agregando riqueza a los diagramas que puede generar.
Una caracterstica importante de este tipo de programas es que trabajen por capas, las
cuales son tratadas independientemente, uno puede poner un objeto sobre otro o por debajo
de otro logrando diferentes efectos. Algunos programas de presentacion graficos basados en
LATEX y pdf estan utilizando esta capacidad en xfig para lograr animaciones de imagenes.
Finalmente el programa xfig permite construir una biblioteca de objetos reutilizables
ahorrando mucho trabajo. Por ejemplo, si uno dibuja los elementos de un circuito electrico y
los almacena en el lugar de las bibliotecas de imagenes podra incluir estos objetos en futuros
trabajos. El programa viene con varias bibliotecas de objetos listas para usar.
jrogan@huelen:~$ gnuplot
G N U P L O T
Version 3.7 patchlevel 2
last modified Sat Jan 19 15:23:37 GMT 2002
System: Linux 2.4.19
gnuplot> replot
gnuplot> set terminal postscript
Terminal type set to postscript
Options are landscape noenhanced monochrome dashed defaultplex "Helvetica" 14
gnuplot> set output "mygraph.ps"
gnuplot> replot
gnuplot> set terminal X
Terminal type set to X11
Options are 0
gnuplot> set xrange[-2:2]
gnuplot> set yrange[-2:2]
gnuplot> splot exp(-x*x-y*y)
gnuplot> plot "myfile.dat" w l
gnuplot> exit
jrogan@huelen:~$
En el caso de xmgrace y SciGraphica mucho mas directo manejarlo ya que esta ba-
sado en men us. Ademas, existe abundante documentacion de ambos softwares. El software
SciGraphica es una aplicacion de visualizacion y analisis de data cientfica que permite
el despliegue de graficos en 2 y 3 dimensiones, ademas, exporta los resultados a formato
PostScript. Realmente esta aplicacion nacio como un intento de clonar el programa comercial
origen no disponible para Linux.
#!/bin/bash
g++ -Wall -O3 -o $1 $1.cc -I. -I$HOME/iglu/ \
-L/usr/X11R6/lib/ -L$HOME/iglu/ -liglu -lX11 -lm
/* Ejemplo: sen(x) */
#include iglu.h
#include <cmath>
int main()
{
IgluDibujo v(Funcion Seno);
const int N=100;
double x[N], y[N];
108 CAPITULO 3. GRAFICA.
v.map_coordinates(0,2*M_PI,-1.2,1.2);
double dx = 2*M_PI/(N-1);
for (int i=0;i<N;i++){
x[i] = i*dx;
y[i] = sin(x[i]);
}
v.plot_line(x,y,N);
v.wait();
return 0;
}
// Ejemplo sen(x-vt)
#include "iglu.h"
#include <cmath>
int main(){
IgluDibujo v(Pelicula);
const int N=100, Nt=100;
double x[N], y[N];
v.map_coordinates(0,2*M_PI,-1.2,1.2);
double dx = 2*M_PI/(N-1), dt = 1, t=0;
for (int j=0;j<Nt;j++){
v.clean();
t += dt;
for (int i=0;i<N;i++){
x[i] = i*dx;
y[i] = sin(x[i]-.1*t);
}
v.plot_line(x,y,N);
v.wait(.03);
v.flush();
}
v.wait();
return 0;
}
Captulo 4
El sistema de preparaci
on de
documentos TEX .
versi
on 5.0, 30 de Julio del 2003
4.1. Introducci
on.
TEX es un procesador de texto o, mejor dicho, un avanzado sistema de preparacion de
documentos, creado por Donald Knuth, que permite el dise no de documentos de gran cali-
dad, conteniendo textos y formulas matematicas. A nos despues, LATEX fue desarrollado por
Leslie Lamport, facilitando la preparacion de documentos en TEX, gracias a la definicion de
macros o conjuntos de comandos de facil uso.
LATEX tuvo diversas versiones hasta la 2.09. Actualmente, LATEX ha recibido importantes
modificaciones, siendo la distribucion actualmente en uso y desarrollo LATEX 2 , una version
transitoria en espera de que alg
un da se llegue a la nueva version definitiva de LATEX, LATEX3.
En estas paginas cuando digamos LATEX nos referiremos a la version actual, LATEX 2 . Cuan-
do queramos hacer referencia a la version anterior, que debera quedar progresivamente en
desuso, diremos explcitamente LATEX 2.09.
4.2. Archivos.
El proceso de preparacion de un documento LATEX consta de tres pasos:
a) dvi. Es el archivo procesado que podemos ver en pantalla o imprimir. Una vez
compilado, este archivo puede ser enviado a otro computador, para imprimir en
otra impresora, o verlo en otro monitor, independiente de la maquina (de donde
su extension dvi, device independent).
109
110 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
4.3. Input b
asico.
4.3.1. Estructura de un archivo.
En un archivo no pueden faltar las siguientes lneas:
\documentclass[12pt]{article}
\begin{document}
\end{document}
Haremos algunas precisiones respecto a la primera lnea mas tarde. Lo importante es que
una lnea de esta forma debe ser la primera de nuestro archivo. Todo lo que se encuentra
antes de \begin{document} se denomina pre ambulo. El texto que queramos escribir va entre
\begin{document} y \end{document}. Todo lo que se encuentre despues de \end{document}
es ignorado.
4.3.2. Caracteres.
Pueden aparecer en nuestro texto todos los caracteres del codigo ASCII no extendido
(teclado ingles usual): letras, n
umeros y los signos de puntuacion:
. : ; , ? ! ( ) [ ] - / * @
# $ % & ~ _ ^ \ { }
tienen un significado especfico para LATEX. Algunos de ellos se pueden obtener anteponiendo-
les un backslash:
# \# $ \$ % \% & \& { \{ } \}
Los caracteres
+ = | < >
4.3. INPUT BASICO. 111
n
\~n a \a \{\i} u
\"u ! ?
4.3.3. Comandos.
Todos los comandos comienzan con un backslash, y se extienden hasta encontrar el primer
caracter que no sea una letra (es decir, un espacio, un n
umero, un signo de puntuacion o
matematico, etc.).
a) Observemos la siguiente palabra: fino. Esta palabra fue generada escribiendo simple-
mente fino, pero observemos que las letras f e i no estan separadas, sino que unidas
artsticamente. Esto es una ligadura, y es considerada una practica esteticamente pre-
ferible. LATEX sabe esto e inserta este peque no efecto tipografico sin que nos demos
cuenta.
b) Las comillas de apertura y de cierre son distintas. Por ejemplo: insigne (comillas
simples) o insigne (comillas dobles). Las comillas de apertura se hacen con uno o con
dos acentos graves (), para comillas simples o dobles, respectivamente, y las de cierre
con acentos agudos (): insigne, insigne. No es correcto entonces utilizar las
comillas dobles del teclado e intentar escribir "insigne" (el resultado de esto es el poco
estetico insigne).
En la pag. 11 encontraremos noticias desde la U.R.S.S. Estas fueron entrega-
das. . .
d) Enfasis de texto:
Este es un texto enfatizado. \Este es un texto
{\em enfatizado}.
4.3.6. F
ormulas matem
aticas.
LATEX distingue dos modos de escritura: un modo de texto, en el cual se escriben los
textos usuales como los ya mencionados, y un modo matematico, dentro del cual se escriben
las formulas. Cualquier formula debe ser escrita dentro de un modo matematico, y si alg
un
smbolo matematico aparece fuera del modo matematico el compilador acusara un error.
Hay tres formas principales para acceder al modo matematico:
a) $x+y=3$
b) $$xy=8$$
c) \begin{equation}
x/y=5
\end{equation}
4.3.7. Comentarios.
Uno puede hacer que el compilador ignore parte del archivo usando %. Todo el texto desde
este caracter hasta el fin de la lnea correspondiente sera ignorado (incluyendo el fin de lnea).
Un peque
no comentario. Un peque{\~n}o co% Texto ignorado
mentario.
4.3.10. Ttulo.
Un ttulo se genera con:
a) Sin ttulo:
\title{}
b) Sin autor:
\author{}
c) Sin fecha:
\date{}
e) Mas de un autor:
Para artculos cortos, LATEX coloca el ttulo en la parte superior de la primera pagina
del texto. Para artculos largos, en una pagina separada.
116 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
4.3.11. Secciones.
Los ttulos de las distintas secciones y subsecciones de un documento (numerados ade-
cuadamente, en negrita, como en este texto) se generan con comandos de la forma:
\section{Una secci\on}
\subsection{Una subsecci\on}
4.3.12. Listas.
Los dos modos usuales de generar listas:
a) Listas numeradas (ambiente enumerate):
\begin{enumerate}
1. Nivel 1, tem 1. \item Nivel 1, \{\i}tem 1.
\item Nivel 1, \{\i}tem 2.
2. Nivel 1, tem 2.
\begin{enumerate}
a) Nivel 2, tem 1. \item Nivel 2, \{\i}tem 1.
\begin{enumerate}
1) Nivel 3, tem 1. \item Nivel 3, \{\i}tem 1.
3. Nivel 1, tem 3. \end{enumerate}
\end{enumerate}
\item Nivel 1, \{\i}tem 3.
\end{enumerate}
Es posible anidar hasta tres niveles de listas. Cada uno usa tipos distintos de rotulos,
seg
un el ambiente usado: n umeros arabes, letras y n
umeros romanos para enumerate, y
puntos, guiones y asteriscos para itemize. Los rotulos son generados automaticamente por
cada \item, pero es posible modificarlos agregando un parametro opcional:
\rm es el default para texto normal; \it es el default para texto enfatizado; \bf es el
default para ttulos de captulos, secciones, subsecciones, etc.
\textrm, \textbf, etc., solo permiten cambiar porciones definidas del texto, contenido
entre los parentesis cursivos. Con \rm, \bf, etc. podemos, omitiendo los parentesis, cambiar
el font en todo el texto posterior:
Un cambio local de fonts y uno Un cambio {\sf local} de fonts
global, interminable e infini- \sl y uno global, interminable
to. . . e infinito...
Tambien es posible tener combinaciones de estos fonts, por ejemplo, bold italic, pero no
sirven los comandos anteriores, sino versiones modificadas de \rm, \bf, etc.:
\rmfamily
\sffamily
\ttfamily
\mdseries
118 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
\bfseries
\upshape
\itshape
\slshape
\scshape
Por ejemplo:
Para entender el uso de estos comandos hay que considerar que un font tiene tres atributos:
family (que distingue entre rm, sf y tt), series (que distingue entre md y bf), y shape (que
distingue entre up, it, sl y sc). Cada uno de los comandos \rmfamily, \bfseries, etc.,
cambia solo uno de estos atributos. Ello permite tener versiones mixtas de los fonts, como
un slanted sans serif, imposible de obtener usando los comandos \sl y \sf. Los defaults para
el texto usual son: \rmfamily, \mdseries y \upshape.
Tama
no.
Los tama
nos de letras disponibles son:
texto \small
Se usan igual que los comandos de cambio de font \rm, \sf, etc., de la seccion 4.3.13.
\normalsize es el default para texto normal; \scriptsize para sub o suprandices;
\footnotesize para notas a pie de pagina.
o \o o \~o o \v o o \c o
o` \o o \=o o \H o o. \d o
o \^o o \. o o o \t{oo} o \b o
o \"o o \u o
o \r o
Cuadro 4.1: Acentos.
\dag \oe l \l
\ddag \OE L \L
\S \ae \ss
\P \AE SS \SS
c \copyright
a \aa ?
a \textcircled a
A \AA !
\textvisiblespace \o
\pounds \O
Cuadro 4.2: Smbolos especiales y caracteres no ingleses.
LATEX emplea solo los caracteres ASCII basicos, que no contienen smbolos castellanos
como , , n
, etc. Ya hemos visto que existen comandos que permiten imprimir estos caracteres,
y por tanto es posible escribir cualquier texto en castellano (y otros idiomas, de hecho).
Sin embargo, esto no resuelve todo el problema, porque en ingles y castellano las palabras
se cortan en slabas de acuerdo a reglas distintas, y esto es relevante cuando se debe cortar el
texto en lneas. LATEX tiene incorporados algoritmos para cortar palabras en ingles y, si se ha
hecho una instalacion especial de LATEX en nuestro computador, tambien en castellano u otros
idiomas (a traves del programa babel, que es parte de la distribucion standard de LATEX 2 ).
En un computador con babel instalado y configurado para cortar en castellano basta incluir el
comando \usepackage[spanish]{babel} en el preambulo para poder escribir en castellano
cortando las palabras en slabas correctamente.3
Sin embargo, ocasionalmente LATEX se encuentra con una palabra que no sabe cortar,
en cuyo caso no lo intenta y permite que ella se salga del margen derecho del texto, o bien
toma decisiones no optimas. La solucion es sugerirle a LATEX la silabacion de la palabra. Por
ejemplo, si la palabra conflictiva es matem\aticas (generalmente hay problemas con las
palabras acentuadas), entonces basta con reescribirla en la forma: ma\-te\-m\a\-ti\-cas.
Con esto, le indicamos a LATEX en que puntos es posible cortar la palabra. El comando \- no
tiene ning
un otro efecto, de modo que si la palabra en cuestion no queda al final de la lnea,
LATEX por supuesto ignora nuestra sugerencia y no la corta.
Consideremos el siguiente ejemplo:
3
Esto resuelve tambien otro problema: los encabezados de captulos o ndices, por ejemplo, son escritos
Captulo e Indice, en vez de Chapter e Index, y cuando se usa el comando \date, la fecha aparece
en castellano.
120 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
4.4. F
ormulas matem
aticas.
Hemos mencionado tres formas de ingresar al modo matematico: $...$ (formulas dentro
del texto), $$...$$ (formulas separadas del texto, no numeradas) y \begin{equation} ...
\end{equation} (formulas separadas del texto, numeradas). Los comandos que revisaremos
en esta seccion solo pueden aparecer dentro del modo matematico.
4.4.2. Fracciones.
a) Horizontales
n/2 n/2
b) Verticales
1
\frac{1}{2}, \frac 1{2}, \frac{1}2 o \frac 12
2
y + z/2
x= x = \frac{y + z/2}{y^2+1}
y2 + 1
x+y
y \frac{x+y}{1 + \frac y{z+1}}
1 + z+1
4.4. FORMULAS
MATEMATICAS. 121
La forma a) es mas adecuada y la preferida para fracciones dentro del texto, y la se-
gunda para formulas separadas. \frac puede aparecer en formulas dentro del texto ( 21 con
$\frac 12$), pero esto es inusual y poco recomendable esteticamente, salvo estricta necesi-
dad.
4.4.3. Races.
n \sqrt{n} o \sqrt n
a2 + b 2 \sqrt{a^2 + b^2}
n
2 \sqrt[n]{2}
b) \cdots
Entre smbolos como +, , = :
..
c) . \vdots
x1
..
.
xn
..
d) . \ddots
1 0 0
0 1 0
Inn =
.. . . . ..
. .
0 0 ... 1
No corresponde usar tres puntos seguidos (...), pues el espaciado entre puntos es incorrecto.
122 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
Min
usculas
\alpha \theta o o \tau
\beta \vartheta \pi \upsilon
\gamma \iota $ \varpi \phi
\delta \kappa \rho \varphi
\epsilon \lambda % \varrho \chi
\varepsilon \mu \sigma \psi
\zeta \nu \varsigma \omega
\eta \xi
May
usculas
\Gamma \Lambda \Sigma \Psi
\Delta \Xi \Upsilon \Omega
\Theta \Pi \Phi
Pn R1
i=1 xi = 0 f $\sum_{i=1}^n x_i = \int_0^1 f $
( ( ) ) \uparrow
[ [ ] ] \downarrow
{ \{ } \} l \updownarrow
b \lfloor c \rfloor \Uparrow
d \lceil e \rceil \Downarrow
h \langle i \rangle m \Updownarrow
/ / \ \backslash
| | k \|
4.4.9. Matrices.
Ambiente array.
Se construyen con el ambiente array. Consideremos, por ejemplo:
a + b + c uv 27
a+b u+v 134
a 3u + vw 2.978
La primera columna esta alineada al centro (c, center); la segunda, a la izquierda (l, left); la
tercera, a la derecha (r, right). array tiene un argumento obligatorio, que consta de tantas
letras como columnas tenga la matriz, letras que pueden ser c, l o r seg un la alineacion
que queramos obtener. Elementos consecutivos de la misma lnea se separan con & y lneas
consecutivas se separan con \\. As, el ejemplo anterior se obtiene con:
\begin{array}{clr}
a+b+c & uv & 27 \\
a+b & u + v & 134 \\
a & 3u+vw & 2.978
\end{array}
Delimitadores.
Un delimitador es cualquier smbolo que actue como un parentesis, encerrando una ex-
presion, apareciendo a la izquierda y a la derecha de ella. La Tabla 4.10 muestra todos los
delimitadores posibles.
Para que los delimitadores tengan el tama
no correcto para encerrar la expresion correspon-
diente hay que anteponerles \left y \right. Podemos obtener as expresiones matriciales:
126 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
\left(\begin{array}{cc}
a b a&b\\
c d c&d
\end{array}\right)
v = \left(\begin{array}{c}
1 1\\
v= 2 2\\
3 3
\end{array}\right)
\Delta = \left|\begin{array}{cc}
a a
= 11 12 a_{11} & a_{12}\\
a21 a22
a_{21} & a_{22}
\end{array}\right|
\left y \right deben ir de a pares, pero los delimitadores no tienen por que ser los
mismos:
\left(\begin{array}{c}
a a\\
b b
\end{array}\right[
Tampoco es necesario que los delimitadores encierren matrices. Comparemos, por ejemplo:
~
(A ~ = ( dF )x=a
~ + B) (\vec A + \vec B) =
dx
( \frac{d \vec F}{dx} )_{x=a}
!
~+B
~ =
dF~
A \left(\vec A + \vec B\right) =
dx
x=a \left( \frac{d \vec F}{dx} \right)_{x=a}
El segundo ejemplo es mucho mas adecuado esteticamente.
Algunas expresiones requieren solo un delimitador, a la izquierda o a la derecha. Un punto
(.) representa un delimitador invisible. Los siguientes ejemplos son tpicos:
Z b
b
df
dx = f (x) \left. \int_a^b dx \frac{df}{dx} =
a dx a f(x) \right |_a^b
F
ormulas de m
as de una lnea.
a
\hat a a
\acute a a
\bar a a \dot a
a
\check a a
` \grave a ~a \vec a a
\ddot a
a
\breve a a
\tilde a
x = a+b+c+ \begin{eqnarray*}
d+e x& = & a + b + c +\\
&& d + e
\end{eqnarray*}
El asterisco impide que aparezcan n umeros en las ecuaciones. Si deseamos que numere
cada lnea como una ecuacion independiente, basta omitir el asterisco:
x = 5 (4.2) \begin{eqnarray}
a + b = 60 (4.3) x& = & 5 \\
a + b&= & 60
\end{eqnarray}
Si queremos que solamente algunas lneas aparezcan numeradas, usamos \nonumber:
x = a+b+c+ \begin{eqnarray}
d+e (4.4) x& = & a + b + c + \nonumber\\
&& d + e
\end{eqnarray}
El comando \eqnarray es suficiente para necesidades sencillas, pero cuando se requiere
escribir matematica de modo intensivo sus limitaciones comienzan a ser evidentes. Al agre-
gar al preambulo de nuestro documento la lnea \usepackage{amsmath} quedan disponibles
muchos comandos mucho mas u tiles para textos matematicos mas serios, como el ambiente
equation*, \split, \multline o \intertext. En la seccion 4.8.2 se encuentra una descrip-
cion de estos y otros comandos.
4.4.10. Acentos.
Dentro de una formula pueden aparecer una serie de acentos, analogos a los de texto
usual (Tabla 4.11).
Las letras i y j deben perder el punto cuando son acentuadas: ~i es incorrecto. Debe ser ~.
\imath y \jmath generan las versiones sin punto de estas letras:
~ + \vec \imath + \hat \jmath
Bastante mas optimo es utilizar el comando \text, disponible a traves de amsmath (secci
on
4.8.2).
\, espacio peque
no \: espacio medio
\! espacio peque
no (negativo) \; espacio grueso
4.4.13. Fonts.
Analogamente a los comandos para texto usual (Sec. 4.3.13), es posible cambiar los fonts dentro
del modo matematico:
(A, x) \mathrm{(A,x)}
(A, x) \mathnormal{(A,x)}
(A, B) \mathcal{(A,B)}
(A, x) \mathbf{(A,x)}
(A, x) \mathsf{(A,x)}
(A, x) \mathtt{(A,x)}
(A, x ) \mathit{(A,x)}
Como en todo ambiente matematico, los espacios entre caracteres son ignorados:
Hola \mathrm{H o l a}
Finalmente, observemos que \mathit corresponde al font italico, en tanto que \mathnormal al
font matematico usual, que es tambien italico. . . o casi:
different $\mathit{different}$
different \textit{different}
4.5. Tablas.
array nos permitio construir matrices en modo matematico. Para tablas de texto existe tabular,
que funciona de la misma manera. Puede ser usado tanto en modo matematico como fuera de el.
\begin{tabular}{lcl}
Nombre : Juan Perez Nombre&:&Juan P\erez\\
Edad : 26 Edad&:&26\\
Profesion : Estudiante Profesi\on&:&Estudiante
\end{tabular}
Si deseamos agregar lneas verticales y horizontales para ayudar a la lectura, lo hacemos inser-
tando | en los puntos apropiados del argumento de tabular, y \hline al final de cada lnea de la
tabla:
\begin{tabular}{|l|r|}\hline
Item Gastos Item&Gastos\\ \hline
Vasos $ 500 Vasos& \$ 500 \\
Botellas $ 1300 Botellas & \$ 1300 \\
Platos $ 500 Platos & \$ 500 \\ \hline
Total $ 2300 Total& \$ 2300 \\ \hline
\end{tabular}
\usepackage{<package>}
\usepackage{<package1>,<package2>}
\usepackage{<package1>}
\usepackage{<package2>}
Algunos paquetes aceptan opciones adicionales (del mismo modo que la clase article acepta
la opcion 12pt):
\usepackage[option1,option2]{<package1>}
4.8.1. babel
Permite el procesamiento de textos en idiomas distintos del ingles. Esto significa, entre otras
cosas, que se incorporan los patrones de silabacion correctos para dicho idioma, para cortar adecua-
damente las palabras al final de cada lnea. Ademas, palabras claves como Chapter, Index, List
of Figures, etc., y la fecha dada por \date, son cambiadas a sus equivalentes en el idioma escogido.
La variedad de idiomas disponibles es enorme, pero cada instalacion de LATEX tiene solo algunos de
ellos incorporados. (Esta es una decision que toma el administrador del sistema, de acuerdo a las
necesidades de los usuarios. Una configuracion usual puede ser habilitar la compilacion en ingles,
castellano, aleman y frances.)
Ya sabemos como usar babel para escribir en castellano: basta incluir en el preambulo la lnea
\usepackage[spanish]{babel}
132 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
4.8.2. AMS-LATEX
El paquete amsmath permite agregar comandos para escritura de textos matematicos profe-
sionales, desarrollados originalmente por la American Mathematical Society. Si un texto contiene
abundante matematica, entonces seguramente incluir la lnea correspondiente en el preambulo:
\usepackage{amsmath}
aliviara mucho la tarea. He aqu algunas de las caractersticas adicionales disponibles con AMS-
LATEX.
x = 2y 3 \begin{equation*}
x = 2y - 3
\end{equation*}
multline permite dividir una ecuacion muy larga en varias lneas, de modo que la primera lnea
quede alineada con el margen izquierdo, y la u
ltima con el margen derecho:
15
X \begin{multline}
= 1 + 2 + 3 + 4 + 5+ \sum_{i=1}^{15} = 1 +2+3+4+5+\\
i=1 6+7+8+9+10+\\
6 + 7 + 8 + 9 + 10+ 11+12+13+14+15
11 + 12 + 13 + 14 + 15 (4.6) \end{multline}
align permite reunir un grupo de ecuaciones consecutivas alineandolas (usando &, igual que la
alineacion vertical de tabular y array). gather hace lo mismo, pero centrando cada ecuacion en
la pagina independientemente.
a1 = b1 + c1 (4.7) \begin{align}
a2 = b2 + c2 d2 + e2 (4.8) a_1 &= b_1 + c_1 \\
a_2 &= b_2 + c_2 - d_2 + e_2
\end{align}
a1 = b1 + c1 (4.9) \begin{gather}
a2 = b2 + c2 d2 + e2 (4.10) a_1 = b_1 + c_1 \\
a_2 = b_2 + c_2 - d_2 + e_2
\end{gather}
Con multline*, align* y gather* se obtienen los mismos resultados, pero con ecuaciones no
numeradas.
split permite escribir una sola ecuacion separada en lneas (como multline), pero permite
alinear las lneas con & (como align). split debe ser usado dentro de un ambiente como equation,
align o gather (o sus equivalentes con asterisco):
4.8. ALGUNAS HERRAMIENTAS IMPORTANTES 133
a1 = b1 + c1 \begin{equation}
(4.11)
= b2 + c2 d2 + e2 \begin{split}
a_1& = b_1 + c_1 \\
& = b_2 + c_2 - d_2 + e_2
\end{split}
\end{equation}
Espacio horizontal
\quad y \qquad insertan espacio horizontal en ecuaciones:
x>y , x A \begin{gather*}
xz , z B x > y \ , \quad \forall\, x \in A \\
x \leq z \ , \qquad \forall\, z \in B
\end{gather*}
Texto en ecuaciones
Para agregar texto a una ecuacion, usamos \text:
\begin{equation*}
x = 2n 1 , con n entero x = 2^n - 1 \ , \quad \text{con $n$ entero}
\end{equation*}
\text se comporta como un buen objeto matematico, y por tanto se pueden agregar subndices
textuales mas facilmente que con \mbox (ver seccion 4.4.11):
Vcrtico $V_{\text{cr\{\i}tico}}$
Referencia a ecuaciones
\eqref es equivalente a \ref, salvo que agrega los parentesis automaticamente:
La ecuacion (4.5) era la de Eu- La ecuaci\on \eqref{euler} era la de Euler.
ler.
x1 = a + b + c , \begin{align*}
x2 = d + e , x_1 &= a + b + c \ , \\
x_2 &= d + e \ , \\
y por otra parte \intertext{y por otra parte}
x_3 &= f + g + h \ .
x3 = f + g + h . \end{align*}
\begin{pmatrix}
a b a&b\\
c d c&d
\end{pmatrix}
\Delta = \begin{vmatrix}
a11 a12
=
a_{11} & a_{12}\\
a21 a22 a_{21} & a_{22}
\end{vmatrix}
k
v= v = \binom{k}{2}
2
Podemos observar que el espaciado entre los parentesis y el resto de la formula es mas adecuado
que el de los ejemplos en la seccion 4.4.9.
Flechas extensibles
Las flechas en la tabla 4.6 vienen en ciertos tama
nos predefinidos. amsmath proporciona fle-
chas extensibles \xleftarrow y \xrightarrow, para ajustar sub o superndices demasiado anchos.
Ademas, tienen un argumento opcional y uno obligatorio, para colocar material sobre o bajo ellas:
n+1 ni1
A B C
D
T U
4.8.3. fontenc
Ocasionalmente, LATEX tiene problemas al separar una palabra en slabas. Tpicamente, eso
ocurre con palabras acentuadas, pues, debido a la estructura interna del programa, un caracter
como la a en matematicas no es tratado igual que los otros. Para solucionar el problema, y
poder cortar en slabas palabras que contengan letras acentuadas (ademas de acceder a algunos
caracteres adicionales), basta incluir el paquete fontenc:
4.8. ALGUNAS HERRAMIENTAS IMPORTANTES 135
\usepackage[T1]{fontenc}
Tecnicamente, lo que ocurre es que la codificacion antigua para fonts es la OT1, que no contiene
fonts acentuados, y que por lo tanto es u
til solo para textos en ingles. La codificacion T1 aumenta los
fonts disponibles, permitiendo que los caracteres acentuados sean tratados en igual pie que cualquier
otro.
4.8.4. enumerate
enumerate.sty define una muy conveniente extension al ambiente enumerate de LATEX. El
comando se usa igual que siempre (ver seccion 4.3.12), con un argumento opcional que determina
el tipo de etiqueta que se usara para la lista. Por ejemplo, si queremos que en vez de n
umeros se
usen letras mayusculas, basta usar \begin{enumerate}[A]:
A Primer tem.
B Segundo tem.
Si deseamos insertar un texto que no cambie de una etiqueta a otra, hay que encerrarlo entre
parentesis cursivos (\begin{enumerate}[{Caso} A:]):
4.8.5. Color.
A traves de PostScript es posible introducir color en documentos LATEX. Para ello, incluimos en
el preambulo el paquete color.sty:
\usepackage{color}
De este modo, esta disponible el comando \color, que permite especificar un color, ya sea por
nombre (en el caso de algunos colores predefinidos), por su codigo rgb (red-green-blue) o codigo
cmyk (cian-magenta-yellow-black). Por ejemplo:
Un texto en un
{\color[cmyk]{.3,.5,.75,0} tercer color}
Los colores mas frecuentes (azul, amarillo, rojo, etc.) se pueden dar por nombre, como en este
ejemplo. Si se da el codigo rgb, se deben especificar tres n
umeros entre 0 y 1, que indican la cantidad
136 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
de rojo, verde y azul que constituyen el color deseado. En el ejemplo, le dimos maxima cantidad de
rojo y azul, y nada de verde, con lo cual conseguimos un color violeta. Si se trata del codigo cmyk los
n
umeros a especificar son cuatro, indicando la cantidad de cian, magenta, amarillo y negro. En el
ejemplo anterior pusimos una cantidad arbitraria de cada color, y resulto un color cafe. Es evidente
que el uso de los codigos rgb y cmyk permite explorar infinidad de colores.
Observar que \color funciona de modo analogo a los comandos de cambio de font de la secci on
4.3.13, de modo que si se desea restringir el efecto a una porcion del texto, hay que encerrar dicho
texto entre parentesis cursivos. Analogamente al caso de los fonts, existe el comando \textcolor,
que permite dar el texto a colorear como argumento:
Un texto en un
\textcolor[cmyk]{.3,.5,.75,0}{tercer color}
4.9.1. Estilos de p
agina.
a) N
umeros de pagina.
Si se desea que los n
umeros de pagina sean arabicos (1, 2, 3. . . ):
\pagenumbering{arabic}
Para n
umeros romanos (i, ii, iii,. . . ):
\pagenumbering{roman}
arabic es el default.
b) Estilo de pagina.
El comando \pagestyle determina donde queremos que vayan los n
umeros de pagina:
\pagestyle{empty} Sin n
umeros de pagina.
4.9. MODIFICANDO EL ESTILO DE LA PAGINA. 137
4.9.2. Corte de p
aginas y lneas.
TEX tiene modos internos de decidir cuando cortar una pagina o una lnea. Al preparar la versi
on
final de nuestro documento, podemos desear coartar sus decisiones. En todo caso, no hay que hacer
esto antes de preparar la version verdaderamente final, porque agregar, modificar o quitar texto
puede alterar los puntos de corte de lneas y paginas, y los cortes inconvenientes pueden resolverse
solos.
Los comandos de esta seccion no van en el preambulo, sino en el interior del texto.
Corte de lneas.
En la pagina 119 ya vimos un ejemplo de induccion de un corte de lnea en un punto deseado
del texto, al dividir una palabra en slabas.
Cuando el problema no tiene relacion con slabas disponemos de dos comandos:
\newline Corta la lnea y pasa a la siguiente en el punto
indicado.
Observemos como en el segundo caso, en que se usa \linebreak, la separacion entre palabras
es alterada para permitir que el texto respete los margenes establecidos.
Corte de p
aginas.
Como para cortar lneas, existe un modo violento y uno sutil:
\newpage Cambia de pagina en el punto indicado. Analogo
a \newline.
\clearpage, sin embargo, no siempre tiene efectos visibles. Dependiendo de la cantidad y tipo
de texto que quede en la pagina, los espacios verticales pueden o no ser ajustados, y si no lo son,
el resultado termina siendo equivalente a un \newpage. TEX decide en u ltima instancia que es lo
optimo.
Adicionalmente, tenemos el comando:
\enlargethispage{<longitud>} Cambia el tama no de la pagina ac-
tual en la cantidad <longitud>.
138 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
cm centmetro
mm milmetro
in pulgada
pt punto (1/72 pulgadas)
em ancho de una M en el font actual
ex altura de una x en el font actual
b) Cambio de longitudes.
TEX almacena los valores de las longitudes relevantes al texto en comandos especiales:
\parindent Sangra.
Todas estas variables son modificables con los comandos \setlength, que le da a una variable
un valor dado, y \addtolength, que le suma a una variable la longitud especificada. Por
ejemplo:
Por default, el ancho y altura del texto, y los margenes izquierdo y superior, estan definidos
de modo que quede un espacio de una pulgada (' 2.56 cm) entre el borde del texto y el borde
de la pagina.
4.10. FIGURAS. 139
Un problema tpico es querer que el texto llene un mayor porcentaje de la pagina. Por ejem-
plo, para que el margen del texto en los cuatro costados sea la mitad del default, debemos
introducir los comandos:
\addtolength{\textwidth}{1in}
\addtolength{\textheight}{1in}
\addtolength{\oddsidemargin}{-.5in}
\addtolength{\topmargin}{-.5in}
Las dos primeras lneas aumentan el tama no horizontal y vertical del texto en 1 pulgada.
Si luego restamos media pulgada del margen izquierdo y el margen superior, es claro que la
distancia entre el texto y los bordes de la pagina sera de media pulgada, como deseabamos.
Algunos ejemplos:
Un primer parrafo de un pe- Un primer p\arrafo de un
que
no texto. peque\~no texto.
\vspace{1cm}
Y un segundo parrafo separa- Y un segundo p\arrafo
do del otro. separado del otro.
Si por casualidad el espacio vertical impuesto por \vspace debiese ser colocado al comienzo
de una pagina, TEX lo ignora. Sera molesto visualmente que en algunas paginas el texto
comenzara algunos centmetros mas abajo que en el resto. Lo mismo puede ocurrir si el
espacio horizontal de un \hspace queda al comienzo de una lnea.
Los comandos \vspace*{<longitud>} y \hspace*{<longitud>} permiten que el espacio en
blanco de la <longitud> especificada no sea ignorado. Ello es u til cuando invariablemente
queremos ese espacio vertical u horizontal, aunque sea al comienzo de una pagina o una lnea
por ejemplo, para insertar una figura.
4.10. Figuras.
Lo primero que hay que decir en esta seccion es que LATEX es un excelente procesador de texto,
tanto convencional como matematico. Las figuras, sin embargo, son un problema aparte.
LATEX provee un ambiente picture que permite realizar dibujos simples. Dentro de la estruc-
tura \begin{picture} y \end{picture} se pueden colocar una serie de comandos para dibujar
lneas, crculos, ovalos y flechas, as como para posicionar texto. Infortunadamente, el proceso de
140 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
ejecutar dibujos sobre un cierto umbral de complejidad puede ser muy tedioso para generarlo di-
rectamente. Existe software (por ejemplo, xfig) que permite superar este problema, pudiendose
dibujar con el mouse, exportando el resultado al formato picture de LATEX. Sin embargo, picture
tiene limitaciones (no se pueden hacer lneas de pendiente arbitraria), y por tanto no es una soluci
on
optima.
Para obtener figuras de buena calidad es imprescindible recurrir a lenguajes graficos externos, y
LATEX da la posibilidad de incluir esos formatos graficos en un documento. De este modo, tanto el
texto como las figuras seran de la mas alta calidad. Las dos mejores soluciones son utilizar Metafont
o PostScript. Metafont es un programa con un lenguaje de programacion grafico propio. De hecho,
los propios fonts de LATEX fueron creados usando Metafont, y sus capacidades permiten hacer dibujos
de complejidad arbitraria. Sin embargo, los dibujos resultantes no son trivialmente reescalables, y
exige aprender un lenguaje de programacion especfico.
Una solucion mucho mas versatil, y adoptada como el estandar en la comunidad de usuarios
de LATEX, es el uso de PostScript. Como se menciono brevemente en la seccion 1.12, al imprimir,
una maquina unix convierte el archivo a formato PostScript, y luego lo enva a la impresora. Pero
PostScript sirve mas que para imprimir, siendo un lenguaje de programacion grafico completo, con
el cual podemos generar imagenes de gran calidad, y reescalables sin perdida de resolucion. Adem as,
muchos programas graficos permiten exportar sus resultados en formato PostScript. Por lo tanto,
podemos generar nuestras figuras en alguno de estos programas (xfig es un excelente software, que
satisface la mayor parte de nuestras necesidades de dibujos simples; octave o gnuplot pueden ser
usados para generar figuras provenientes de calculos cientficos, etc.), lo cual creara un archivo con
extension .ps (PostScript) o .eps (PostScript encapsulado).4 Luego introducimos la figura en el
documento LATEX, a traves del paquete graphicx.
4.10.1. graphicx.sty
Si nuestra figura esta en un archivo figura.eps, la instruccion a utilizar es:
\documentclass[12pt]{article}
\usepackage{graphicx}
\begin{document}
... Texto ...
\includegraphics[width=w, height=h]{figura.eps}
...
\end{document}
Los parametros width y height son opcionales y puede omitirse uno para que el sistema escale
de acuerdo al parametro dado. Es posible variar la escala completa de la figura o rotarla usando
comandos disponibles en graphicx.
4
eps es el formato preferido, pues contiene informacion sobre las dimensiones de la figura, informacion
que es utilizada por LATEX para insertar esta adecuadamente en el texto.
4.10. FIGURAS. 141
\begin{center}
\includegraphics[height=3cm]{figura.eps}
\end{center}
\begin{figure}[h]
\begin{center}
\includegraphics[height=3cm]{figura.eps}
\end{center}
\caption{Un sujeto caminando.}
\label{caminando}
\end{figure}
da como resultado:
figure delimita lo que en TEX se denomina un objeto flotante, es decir, un objeto cuya posici on
no esta determinada a priori, y se ajusta para obtener los mejores resultados posibles. TEX considera
(de acuerdo con la tradicion), que la mejor posicion para colocar una figura es al principio o al final
142 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
de la pagina. Ademas, lo ideal es que cada pagina tenga un cierto n umero maximo de figuras,
que ninguna figura aparezca en el texto antes de que sea mencionada por primera vez, y que, por
supuesto, las figuras aparezcan en el orden en que son mencionadas. Estas y otras condiciones
determinan la posicion que un objeto flotante tenga al final de la compilacion. Uno puede forzar la
decision de LATEX con el argumento opcional de figure:
t (top) extremo superior de la pagina
b (bottom) extremo inferior de la pagina
h (here) aqu, en el punto donde esta el comando
p (page of floats) en una pagina separada al final del texto
El argumento adicional ! suprime, para ese objeto flotante especfico, cualquier restriccion que
exista sobre el n
umero maximo de objetos flotantes en una pagina y el porcentaje de texto mnimo
que debe haber en una pagina.
Varios de estos argumentos se pueden colocar simultanemente, su orden dictando la prioridad.
Por ejemplo,
\begin{figure}[htbp]
...
\end{figure}
indica que la figura se debe colocar como primera prioridad aqu mismo; si ello no es posible, al
comienzo de pagina (esta o la siguiente, dependiendo de los detalles de la compilacion), y as suce-
sivamente.
Ademas, figure numera automaticamente la figura, colocando el texto Figura N :, y \caption
permite colocar una leyenda, centrada en el texto, a la figura. Puesto que la numeracion es automati-
ca, las figuras pueden ser referidas simbolicamente con \label y \ref (seccion 4.6). Para que la
referencia sea correcta, \label debe estar dentro del argumento de \caption, o despues, como
aparece en el ejemplo de la Figura 4.1 (\ref{caminando}!).
Finalmente, notemos que la figura debio ser centrada explcitamente con center. figure no
hace nada mas que tratar la figura como un objeto flotante, proporcionar numeracion y leyenda. El
resto es responsabilidad del autor.
4.11. Cartas.
Para escribir cartas debemos emplear el estilo letter en vez del que hemos utilizado hasta
ahora, article. Comandos especiales permiten escribir una carta, poniendo en lugares adecuados
la direccion del remitente, la fecha, la firma, etc.
A modo de ejemplo, consideremos el siguiente input:
\documentclass[12pt]{letter}
\usepackage[spanish]{babel}
\begin{document}
\closing{Saludos,}
\cc{Arturo Prat \\ Luis Barrios}
\end{letter}
\end{document}
9 de Julio de 1998
Estimado Juan
A
un no tenemos novedades.
Parece increble, pero los recientes acontecimientos nos han superado, a pesar
de nuestros esfuerzos. Esperamos que mejores tiempos nos aguarden.
Saludos,
Pedro Perez
Secretario
Copia a: Arturo Prat
Luis Barrios
4.12. LATEX Y EL FORMATO PDF. 145
Observemos que el texto de la carta esta dentro de un ambiente letter, el cual tiene un argu-
mento obligatorio, donde aparece el destinatario de la carta (con su direccion opcionalmente).
Los comandos disponibles son:
\address{<direccion>} <direccion> del remitente.
\begin{letter}{<destinatario 1>}
\opening<apertura 1>
...
\end{letter}
\begin{letter}{<destinatario 2>}
\address{<direccion remitente 2>}
\signature{<firma 2>}
\opening<apertura 2>
...
\end{letter}
\begin{letter}{<destinatario 3>}
\opening<apertura 3>
...
\end{letter}
\end{document}
dara origen a tres cartas con la misma direccion de remitente y firma, salvo la segunda.
En todos estos comandos, lneas sucesivas son indicadas con \\.
archivo pdf con LATEX es necesario compilarlo con pdflatex. As, pdflatex <archivo> generara un
archivo <archivo>.pdf en vez del <archivo>.dvi generado por el compilador usual.
Si nuestro documento tiene figuras, solo es posible incluirlas en el documento si estan tambien
en formato pdf. Por tanto, si tenemos un documento con figuras en PostScript, debemos introducir
dos modificaciones antes de compilar con pdflatex:
b) Convertir las figuras PostScript a pdf (con epstopdf, por ejemplo). Si tenemos una figura en el
archivo <archivo_figura>.eps, entonces epstopdf <archivo_figura>.eps genera el archivo
correspondiente <archivo_figura>.pdf.
Observar que el mismo paquete graphicx descrito en la seccion 4.10 para incluir figuras
PostScript permite, sin modificaciones, incluir figuras en pdf.
4.13.1. Definici
on de nuevos comandos.
El comando \newcommand
Un nuevo comando se crea con:
\newcommand{<comando>}{<accion>}
El caso mas sencillo es cuando una estructura se repite frecuentemente en nuestro documento.
Por ejemplo, digamos que un sujeto llamado Cristobal no quiere escribir su nombre cada vez que
aparece en su documento:
con el primer caracter que no es letra. Por tanto, \nombre Loyola ignora el espacio al final de
\nombre, y el output sera CristobalLoyola.
Tambien es posible definir comandos que funcionen en modo matematico:
Como \vel contiene un comando matematico (\dot), \vel solo puede aparecer en modo ma-
tematico.
Podemos tambien incluir la apertura de modo matematico en la definicion de \vel:
\newcommand{\vel}{$\dot x$}. De este modo, \vel (no $\vel$) da como output directamen-
te x.
Sin embargo, esta solucion no es optima, porque la siguiente ocurrencia de \vel da un error.
En efecto, si \vel = $\dot x$, entonces $ \vel(t)>0$ = $ $\dot x$> 0$. En tal caso, LATEX
ve que un modo matematico se ha abierto y cerrado inmediatamente, conteniendo solo un espacio
entremedio, y luego, en modo texto, viene el comando \dot, que es matematico: LATEX acusa un
error y la compilacion se detiene.
La solucion a este problema es utilizar el comando \ensuremath, que asegura que haya modo
matematico, pero si ya hay uno abierto, no intenta volverlo a abrir:
Un caso especial de comando matematico es el de operadores tipo logaritmo (ver Tabla 4.9). Si
queremos definir una traduccion al castellano de \sin, debemos usar el comando \DeclareMathOperator
disponible via amsmath:
\newcommand{\be}{\begin{enumerate}}
1. El primer caso. \newcommand{\ee}{\end{enumerate}}
2. Ahora el segundo.
\be
3. Y el tercero. \item El primer caso.
\item Ahora el segundo.
\item Y el tercero.
\ee
148 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
Podemos tambien definir comandos que acepten argumentos. Si el sujeto anterior, Cristobal,
desea escribir cualquier nombre precedido de Nombre: en italica, entonces puede crear el siguiente
comando:
\nombre{Violeta}
Observemos que \newcommand tiene un argumento opcional, que indica el n umero de argumentos
que el nuevo comando va a aceptar. Esos argumentos se indican, dentro de la definicion del comando,
con #1, #2, etc. Por ejemplo, consideremos un comando que acepta dos argumentos:
\newcommand{\fn}[2]{f(#1,#2)}
\newcommand{\fn}[2][x]{f(#1,#2)}
Redefinici
on de comandos
Ocasionalmente no nos interesa definir un nuevo comando, sino redefinir la accion de un comando
preexistente. Esto se hace con \renewcommand:
P
arrafos y cambios de lnea dentro de comandos
Un ejemplo mas u til ocurre cuando queremos asegurar un cambio de parrafo, por ejemplo, para
colocar un ttulo de seccion:
Secci
on: Ejemplo Observemos en acci\on el comando:
\seccion{Ejemplo} Listo.
Listo.
Ademas de las lneas en blanco, los cambios de lnea pueden causar problemas dentro de la
definicion de un nuevo comando. El ejemplo anterior, con el comando \seccion, es un buen ejemplo:
notemos que cuando se definio, pusimos un cambio de lnea despues de \vspace{.5cm}. Ese cambio
de lnea es interpretado (como todos los cambios de lnea) como un espacio en blanco, y es posible
que, bajo ciertas circunstancias, ese espacio en blanco produzca un output no deseado. Para ello
basta utilizar sabiamente el caracter %, que permite ignorar todo el resto de la lnea, incluyendo el
cambio de lnea. Ilustremos lo anterior con los siguientes tres comandos, que subrayan (comando
\underline) una palabra, y difieren solo en el uso de % para borrar cambios de lnea:
\underline{\texto},
\underline{\textodos},
y
\underline{\textotres}.
\texto conserva espacios en blanco antes y despues del texto, \textodos solo el espacio en
150 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
blanco despues del texto, y \textotres no tiene espacios en blanco alrededor del texto.
Nuevos ambientes
Nuevos ambientes en LATEX se definen con \newenvironment:
Entonces, con
\begin{na}
Hola a todos. Es un placer saludarlos en este d\{\i}a tan especial.
Los nuevos ambientes tambien pueden ser definidos de modo que acepten argumentos. Como con
\newcommand, basta agregar como argumento opcional a \newenvironment un n umero que indique
cuantos argumentos se van a aceptar:
Dentro de <comienzo ambiente>, se alude a cada argumento como #1, #2, etc. Los argumentos
no pueden ser usados en los comandos de cierre del ambiente (<final ambiente>). Por ejemplo,
modifiquemos el ambiente na anterior, de modo que en vez de colocar una lnea horizontal al
comienzo, coloque lo que le indiquemos en el argumento:
4.13.2. Creaci
on de nuevos paquetes y clases
Si la cantidad de nuevos comandos y/o ambientes que necesitamos en nuestro documento es
suficientemente grande, debemos considerar crear un nuevo paquete o una nueva clase. Para ello
hay que tener clara la diferencia entre uno y otro. En general, se puede decir que si nuestros comandos
involucran alterar la apariencia general del documento, entonces corresponde crear una nueva clase
(.cls). Si, por el contrario, deseamos que nuestros comandos funcionen en un amplio rango de
circunstancias, para diversas apariencias del documento, entonces lo adecuado es un paquete (.sty).
Consideremos por ejemplo la experiencia de los autores de estos apuntes. Para crear estos apuntes
necesitamos basicamente la clase book, con ciertas modificaciones: margenes mas peque nos, inclusi
on
automatica de los paquetes amsmath, babel y graphicx, entre otros, y definicion de ciertos ambientes
especficos. Todo ello afecta la apariencia de este documento, cambiandola de manera apreciable,
pero a la vez de un modo que en general no deseamos en otro tipo de documento. Por ello lo hemos
compilado usando una clase adecuada, llamada mfm2.cls.
Por otro lado, uno de los autores ha necesitado escribir muchas tareas, pruebas y controles de
ayudanta en su vida, y se ha convencido de que su trabajo es mas facil creando una clase tarea.cls,
que sirve para esos tres propositos, definiendo comandos que le permiten especificar facilmente la
fecha de entrega de la tarea, o el tiempo disponible para una prueba, los nombres del profesor y el
ayudante, etc., una serie de comandos especficos para sus necesidades.
Sin embargo, tanto en este documento que usa mfm2.cls, como en las tareas y pruebas que
usan tarea.cls, se utilizan algunos comandos matematicos que no vienen con LATEX, pero que
son recurrentes, como \sen (la funcion seno en castellano), \modulo (el modulo de un vector), o
\TLaplace (la transformada de Laplace). Para que estos comandos esten disponibles en cualquier
tipo de documento, necesitamos reunirlos en un paquete, en este caso addmath.sty. De este modo,
mfm2.cls, tarea.cls o cualquier otra clase pueden llamar a este paquete y utilizar sus comandos.
Estructura b
asica.
La estructura basica de un paquete o una clase es:
a) Identificacion: Informacion general (nombre del paquete, fecha de creacion, etc.). (Obligatoria.)
c) Opciones: Comandos relacionados con el manejo de las opciones con las cuales el paquete o clase
pueden ser invocados. (Opcional.)
152 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
d) Mas declaraciones: Aqu van los comandos que constituyen el cuerpo de la clase o paquete.
(Obligatoria: si no hay ninguna declaracion, el paquete o clase no hace nada, naturalmente.)
La identificacion esta consituida por las siguientes dos lneas, que deben ir al comienzo del
archivo:
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{<paquete>}[<fecha> <otra informacion>]
La primera lnea indica a LATEX que este es un archivo para LATEX 2 . La segunda lnea especifica
que se trata de un paquete, indicando el nombre del mismo (es decir, el nombre del archivo sin
extension) y, opcionalmente, la fecha (en formato YYYY/MM/DD) y otra informacion relevante. Por
ejemplo, nuestro paquete addmath.sty comienza con las lneas:
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{addmath}[1998/09/30 Macros matematicos adicionales (VM)]
Si lo que estamos definiendo es una clase, usamos el comando \ProvidesClass. Para nuestra
clase mfm2.cls:
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mfm2}[2002/03/25 Estilo para apuntes MFM II (VM)]
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{addmath}[1998/09/30 Macros matematicos adicionales (VM)]
(x|y) \prodInt{x}{y}
hxi \promedio{x}
Z
dz f (z) \intii dz\, f(z)
ABC = 90 \angle\, ABC = 90\grados
2 F1 (a, b, c ; d) \Hipergeometrica{a}{b}{c}{d}
4.13. MODIFICANDO LATEX. 153
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{addmath}[1998/09/30 Macros matematicos adicionales (VM)]
\RequirePackage{amsmath}
\RequirePackage{amssymb}
\RequirePackage{euscript}
...
\newcommand{\norma}[1]{\ensuremath \left\lVert\, #1 \,\right\rVert}
\newcommand{\intC}{{\sideset{^*}{}\int}}
\DeclareMathOperator{\senh}{senh}
...
Por ejemplo:
kxk \norma{x}
Z
dz f (z) \intC dz \, f(z)
senh(2y) \senh (2y)
La posibilidad de basar un archivo .sty o .cls en otro es particularmente importante para
una clase, ya que contiene una gran cantidad de comandos y definiciones necesarias para compilar
el documento exitosamente. Sin embargo, un usuario normal, aun cuando desee definir una nueva
clase, estara interesado en modificar solo parte del comportamiento. Con \LoadClass, dicho usuario
puede cargar la clase sobre la cual se desea basar, y luego introducir las modificaciones necesarias,
facilitando enormemente la tarea.
Por ejemplo, al preparar este documento fue claro desde el comienzo que se necesitaba esencial-
mente la clase book, ya que sera un texto muy extenso, pero tambien era claro que se requeran
ciertas modificaciones. Entonces, en nuestra clase mfm2.cls lo primero que hacemos es cargar la
clase book, mas algunos paquetes necesarios (incluyendo nuestro addmath), y luego procedemos a
modificar o a nadir comandos:
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mfm2}[2002/03/25 Estilo para apuntes MFM II (VM)]
\LoadClass[12pt]{book}
\RequirePackage[spanish]{babel}
5
Estos comandos solo se pueden usar en un archivo .sty o .cls Para documentos normales, la manera
de cargar un paquete es \usepackage, y para cargar una clase es \documentclass.
154 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
\RequirePackage{enumerate}
\RequirePackage{addmath}
En un archivo .sty o un .cls se pueden cargar varios paquetes con \RequirePackage. \LoadClass,
en cambio, solo puede aparecer en un .cls, y solo es posible usarlo una vez (ya que normalmente
clases distintas son incompatibles entre s).
Manejo de opciones
En el u
ltimo ejemplo anterior, la clase mfm2 carga la clase book con la opcion 12pt. Esto significa
que si nuestro documento comienza con \documentclass{mfm2}, sera compilado de acuerdo a la
clase book, en 12 puntos. No es posible cambiar esto desde nuestro documento. Sera mejor que
pudieramos especificar el tama
no de letra fuera de la clase, de modo que \documentclass{mfm2}
de un documento en 10 puntos, y \documentclass[12pt]{mfm2} uno en 12 puntos. Para lograr
esto hay que poder pasar opciones desde la clase mfm2 a book.
El modo mas simple de hacerlo es con \LoadClassWithOptions. Si mfm2.cls ha sido llamada
con opciones <opcion1>,<opcion2>, etc., entonces book sera llamada con las mismas opciones.
Por tanto, basta modificar en mfm2.cls la lnea \LoadClass[12pt]{book} por:
\LoadClassWithOptions{book}
\RequirePackageWithOptions{<paquete_base>}
El ejemplo anterior puede ser suficiente en muchas ocasiones, pero en general uno podra llamar
a nuestra nueva clase, mfm2, con opciones que no tienen nada que ver con book. Por ejemplo,
podramos llamarla con opciones spanish,12pt. En tal caso, debera pasarle spanish a babel, y
12pt a book. Mas aun, podramos necesitar definir una nueva opcion, que no existe en ninguna de
las clases o paquetes cargados por book, para modificar el comportamiento de mfm2.cls de cierta
manera especfica no prevista. Estas dos tareas, discriminar entre opciones antes de pasarla a alg
un
paquete determinado, y crear nuevas opciones, constituyen un manejo mas avanzado de opciones.
A continuacion revisaremos un ejemplo combinado de ambas tareas, extraido de la clase con la cual
compilamos este texto, mfm2.cls.
La idea es poder llamar a mfm2 con una opcion adicional keys, que permita agregar al dvi
informacion sobre las etiquetas (dadas con \label) de ecuaciones, figuras, etc., que aparezcan en
el documento (veremos la utilidad y un ejemplo de esto mas adelante). Lo primero es declarar una
nueva opcion, con:
\DeclareOption{<opcion>}{<comando>}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mfm2}[2002/03/25 Estilo para apuntes MFM II (VM)]
...
\DeclareOption{keys}{...}
4.13. MODIFICANDO LATEX. 155
...
\ProcessOptions\relax
...
Observamos que despues de declarar la o las opciones (en este caso keys), hay que procesarlas,
con \ProcessOptions.6
Las lneas anteriores permiten que \documentclass{mfm2} y \documentclass[keys]{mfm2}
sean ambas validas, ejecutandose o no ciertos comandos dependiendo de la forma utilizada.
Si ahora queremos que \documentclass[keys,12pt]{mfm2} sea una lnea valida, de-
bemos procesar keys dentro de mfm2.cls, y pasarle a book.cls las opciones restantes. El
siguiente es el codigo definitivo:
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{mfm2}[2002/03/25 Estilo para apuntes MFM II (VM)]
\newif\ifkeys\keysfalse
\DeclareOption{keys}{\keystrue}
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{book}}
\ProcessOptions\relax
\LoadClass{book}
\RequirePackage[spanish]{babel}
\RequirePackage{amsmath}
\RequirePackage{theorem}
\RequirePackage{epsfig}
\RequirePackage{ifthen}
\RequirePackage{enumerate}
\RequirePackage{addmath}
\ifkeys\RequirePackage[notref,notcite]{showkeys}\fi
Sin entrar en demasiados detalles, digamos que la opcion keys tiene el efecto de hacer
que una cierta variable logica \ifkeys, sea verdadera (cuarta lnea del codigo). La siguien-
te lnea (\DeclareOption*...) hace que todas las opciones que no han sido procesadas
(12pt, por ejemplo) se pasen a la clase book. A continuacion se procesan las opciones con
\ProcessOptions, y finalmente se carga la clase book.
Las lneas siguientes cargan todos los paquetes necesarios, y finalmente se encuentran
todos los nuevos comandos y definiciones que queremos incluir en mfm2.cls.
Observemos que la forma particular en que se carga el paquete showkeys. Esa es pre-
cisamente la funcion de la opcion keys que definimos: showkeys.sty se carga con ciertas
opciones solo si se da la opcion keys.
Cual es su efecto? Consideremos el siguiente texto de ejemplo, en que mfm2 ha sido
llamada sin la opcion keys:
6
\relax es un comando de TEX que, esencialmente, no hace nada, ni siquiera introduce un espacio en
blanco, y es u
til incluirlo en puntos crticos de un documento, como en este ejemplo.
156 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
\documentclass[12pt]{mfm2}
\begin{document}
La opci\on \verb+keys+ resulta muy \util cuando tengo objetos numerados
autom\aticamente, como una ecuaci\on:
\begin{equation}
\label{newton}
\vec F = m \vec a \ .
\end{equation}
y luego quiero referirme a ella: Ec.\ \eqref{newton}.
En el primer caso, se ha compilado sin la opcion keys, y en el segundo con ella. El efecto
es que, si se usa un \label en cualquier parte del documento, aparece en el margen derecho
una caja con el nombre de dicha etiqueta (en este caso, newton). Esto es u til para cualquier
tipo de documentos, pero lo es especialmente en textos como estos apuntes, muy extensos y
con abundantes referencias. En tal caso, tener un modo visual, rapido, de saber los nombres
de las ecuaciones sin tener que revisar trabajosamente el archivo fuente es una gran ayuda.
As, versiones preliminares pueden ser compiladas con la opcion keys, y la version final sin
ella, para no confesar al lector nuestra mala memoria o nuestra comodidad.
4.13. MODIFICANDO LATEX. 157
Caso 1: \documentclass[12pt]{mfm2}
F~ = m~a . (1)
Caso 2: \documentclass[keys,12pt]{mfm2}
La primera lnea nos comunica que LATEX ha encontrado un error. A veces los errores
tienen que ver con procesos mas internos, y son encontrados por TEX. Esta lnea nos informa
quien encontro el error.
La tercera lnea comienza con un signo de exclamacion. Este es el indicador del error. Nos
dice de que error se trata.
Las dos lneas siguientes describen el error en terminos de comandos de bajo nivel.
La lnea 6 nos dice donde ocurrio el error: la lnea 140 en este caso. Ademas nos informa
del texto conflictivo: \begin{itemie}.
En realidad, el mensaje nos indica donde LATEX advirtio el error por primera vez, que no
es necesariamente el punto donde el error se cometio. Pero la gran mayora de las veces la
indicacion es precisa. De hecho, es facil darse cuenta, con la tercera lnea
(Environment itemie undefined)
y la sexta (\begin{itemie}) que el error consistio en escribir itemie en vez de itemize. La
informacion de LATEX es clara en este caso y nos dice correctamente que ocurrio y donde.
Luego viene un ?. LATEX esta esperando una respuesta de nosotros. Tenemos varias alter-
nativas. Comentaremos solo cuatro, tpicamente usadas:
(a) h <Enter>
Solicitamos ayuda. TEX nos explica brevemente en que cree el que consiste el error y/o
nos da alguna recomendacion.
(b) x <Enter>
Abortamos la compilacion. Deberemos volver al editor y corregir el texto. Es la opcion
mas tpica cuando uno tiene ya cierta experiencia, pues el mensaje basta para reconocer
el error.
(c) <Enter>
Ignoramos el error y continuamos la compilacion. TEX hace lo que puede. En algunos
casos esto no tiene consecuencias graves y podremos llegar hasta el final del archivo
sin mayores problemas. En otros casos, ignorar el error puede provocar que ulteriores
comandos perfectamente validos en principio no sean reconocidos y, as, acumular
4.14. ERRORES Y ADVERTENCIAS. 159
muchos errores mas. Podemos continuar con <Enter> sucesivos hasta llegar al final de
la compilacion.
(d) q <Enter>
La accion descrita en el punto anterior puede llegar a ser tediosa o infinita. q hace
ingresar a TEX en batchmode, modo en el cual la compilacion prosigue ignorando todos
los errores hasta el final del archivo, sin enviar mensajes a pantalla y por ende sin que
debamos darle infinitos <Enter>.
Las opciones (c) y (d) son u
tiles cuando no entendemos los mensajes de error. Como
TEX seguira compilando haciendo lo mejor posible, al mirar el dvi puede que veamos mas
claramente donde comenzaron a ir mal las cosas y, por tanto, por que.
Como dijimos, LATEX indica exactamente donde encontro el error, de modo que hemos de
ponerle atencion. Por ejemplo, si tenemos en nuestro documento la lnea:
... un error inesperado\fotnote{En cualquier punto.}
puede decidir...
generara el mensaje de error:
! Undefined control sequence.
Errores m
as comunes.
Los errores mas comunes son:
a) Comando mal escrito.
b) Parentesis cursivos no apareados.
c) Uso de uno de los caracteres especiales #, $, %, &, _, {, }, ~, ^, \ como texto ordinario.
d) Modo matematico abierto de una manera y cerrado de otra, o no cerrado.
e) Ambiente abierto con \begin... y cerrado con un \end... distinto.
f) Uso de un comando matematico fuera de modo matematico.
g) Ausencia de argumento en un comando que lo espera.
h) Lnea en blanco en ambiente matematico.
160 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
*
Falta \end{document}. (Dar Ctrl-C o escribir \end{document} para salir de la compilacion.)
! Missing $ inserted.
Errores c), d), f), h) de la Sec. 4.14.1.
! Missing { (o }) inserted.
Parentesis cursivos no apareados.
! Missing \begin{document}.
Falta \begin{document} o hay algo incorrecto en el preambulo.
4.14.2. Advertencias.
La estructura de una advertencia de LATEX es:
LaTeX warning. <mensaje>.
Algunos ejemplos:
Label ... multiply defined.
Dos \label tienen el mismo argumento.
Label(s) may have changed. Rerun to get cross-references right.
Los n
umeros impresos por \ref y \pageref pueden ser incorrectos, pues los valores corres-
pondientes cambiaron respecto al contenido del aux generado en la compilacion anterior.
Reference ... on page ... undefined.
El argumento de un \ref o un \pageref no fue definido por un \label.
TEX tambien enva advertencias. Se reconocen porque no comienzan con TeX warning.
Algunos ejemplos.
Overfull \hbox ...
TEX no encontro un buen lugar para cortar una lnea, y puso mas texto en ella que lo
conveniente.
Overfull \vbox ...
TEX no encontro un buen lugar para cortar una pagina, y puso mas texto en ella que lo
conveniente.
Underfull \hbox ...
TEX construyo una lnea con muy poco material, de modo que el espacio entre palabras puede
ser excesivo.
Underfull \vbox ...
TEX construyo una pagina con muy poco material, de modo que los espacios verticales (entre
parrafos) pueden ser excesivos.
Las advertencias de LATEX siempre deben ser atendidas. Una referencia doblemente defini-
da, o no compilar por segunda vez cuando LATEX lo sugiere, generara un resultado incorrecto
en el dvi. Una referencia no definida, por su parte, hace aparecer un signo ?? en el texto
final. Todos resultados no deseados, por cierto.
Las advertencias de TEX son menos decisivas. Un overfull o underfull puede redundar en
que alguna palabra se salga del margen derecho del texto, que el espaciado entre palabras en
una lnea sea excesivo, o que el espacio vertical entre parrafos sea demasiado. Los estandares
de calidad de TEX son altos, y por eso enva advertencias frecuentemente. Pero generalmente
los defectos en el resultado final son imperceptibles a simple vista, o por lo menos no son
suficientes para molestarnos realmente. A veces s, por supuesto, y hay que estar atentos.
Siempre conviene revisar el texto y prestar atencion a estos detalles, aunque ello solo tiene
sentido al preparar la version definitiva del documento.
162 CAPITULO 4. EL SISTEMA DE PREPARACION
DE DOCUMENTOS TEX .
Parte II
M
etodos Num
ericos.
163
Captulo 5
Preliminares.
on 3.03, 18 de Noviembre del 2003 1 .
versi
Primero consideremos la version en Octave del programa que llamaremos orthog.m. Las
primeras lneas de orthog son:
Las primeras dos lneas son comentarios; si tipeamos help orthog desde la lnea de comandos,
Octave desplegara estas lneas. El comando clear all en la tercera lnea borra la memoria.
Las proximas lneas del programa
Los vectores entran usando el comando input en estas lneas. Los comentarios que comienzan
con %* son aquellos que corresponden al bosquejo del programa que hicimos. En las lneas
siguientes se eval
ua el producto punto.
1
Este captulo est
a basado en el primer captulo del libro: Numerical Methods for Physics, second edition
de Alejandro L. Garcia, editorial Prentice Hall
165
166 CAPITULO 5. PRELIMINARES.
El ciclo for, usando el ndice i, recorre las componentes de los vectores. Una manera habil
de hacer lo mismo podra ser usar
En este caso, hemos usado la multiplicacion de matrices de Octave para calcular el producto
punto como el producto vectorial del vector fila a y el columna b (donde hemos usado el
operador Hermtico conjugado ). Las u
ltimas lneas del programa
De acuerdo al valor de adotb el programa despliega una de las dos posibles respuestas. A
continuacion la salida al ejecutar el help del programa
octave> orthog
Entre el primer vector: [1 1 1]
Entre el segundo vector: [1 -2 1]
Los vectores son ortogonales
5.1. PROGRAMAS Y FUNCIONES. 167
octave> orthog
Entre el primer vector: [1 1 1]
Entre el segundo vector: [2 2 2]
Los vectores no son ortogonales
Producto punto = 6
#ifndef _vector_3d_h
#define _vector_3d_h
//
// Clase basica de vectores 3d
//
#include <iostream>
class Vector{
private:
double c_x;
double c_y;
double c_z;
public:
Vector():c_x(0),c_y(0),c_z(0) {} ;
Vector(double x, double y, double z):c_x(x),c_y(y),c_z(z) {} ;
~Vector() {} ;
double x() const {return c_x;};
double y() const {return c_y;};
double z() const {return c_z;};
};
#endif
#include "vector3d.h"
}
istream & operator >> (istream & is, Vector & v) {
double x,y,z ;
is >> x >> y>>z ;
v= Vector(x,y,z) ;
return is;
}
Ahora estamos en condiciones de escribir el programa propiamente tal. Las primeras lneas
son
Las primeras lneas son comentarios que nos recuerdan lo que el programa hace. La lnea
siguiente incluye las definiciones de nuestra recien creada clase. Luego inclumos una lnea
dice que vamos a usar el namespace std. A continuacion comienza el programa
#include "vector3d.h"
int main()
{
Vector a, b;
cout << "Ingrese el primer vector : ";
cin >> a ;
cout << "Ingrese el segundo vector : ";
cin >> b ;
if(a*b==0) {
cout <<"Son ortogonales" << endl;
} else {
cout << "No son ortogonales"<< endl ;
}
return 0;
}
Declaramos dos objetos tipo Vector, a y b para almacenar los vectores que entran. La
instruccion de salida despliega sobre la pantalla:
if(a*b==0) {
cout <<"Son ortogonales" << endl;
} else {
cout << "No son ortogonales"<< endl ;
}
y despliega el resultados. Aqu los comandos de compilacion y una salida tpica del programa.
Programa de interpolaci
on en Octave.
Es bien sabido que dados tres pares (x, y), se puede encontrar una cuadratica que pasa
por los puntos deseados. Hay varias maneras de encontrar el polinomio y varias maneras de
escribirlo. La forma de Lagrange del polinomio es
donde (x1 , y1 ), (x2 , y2 ), (x3 , y3 ), son los tres puntos por los que queremos pasar. Com
unmente
tales polinomios son usados para interpolar entre los puntos dados. A continuacion el bosquejo
de un programa simple de interpolacion, que llamaremos interp
Inicializa los puntos (x1 , y1 ), (x2 , y2 ) y (x3 , y3 ) para ser ajustados por el polinomio.
Finalmente, podemos graficar la curva dada por (x , y ), y marcar los puntos originales
para comparar.
5
y
0
-3 -2 -1 0 1 2 3
x
y(i)=temp(2) ;
end
%* Establece el intervalo de interpolacion (desde x_min a x_max)
xr = input (Ingrese el intervalo de valores de x como [x_min x_max]: );
Aqu el programa lee los tres pares (x, y) y el intervalo de valores entre los cuales sera inter-
polado.
Los valores interpolados y = p(x ) son calculados por la funcion intrpf desde x = xmn
a x = xmax . Estos valores de y (yi) son calculados en el ciclo.
%* Encontrar yi para los valores deseados de interpolacion xi
% usando la funcion intrpf
nplot= 100; % Numero de puntos para la curva interpolada
for i=1:nplot
xi(i) = xr(1)+(xr(2)-xr(1))*(i-1)/(nplot-1);
yi(i) = intrpf(xi(i), x, y); % Usando intrpf para interpolar
end
Finalmente, los resultados son graficados usando las funciones graficas de Octave.
%* Grafica la curva dada por (xi,yi) y marca los puntos originales
xlabel(x);
ylabel(y);
title(Interpolacion de tres puntos);
gset nokey;
plot(x,y, *,xi,yi,-);
Los puntos de la interpolacion (x , y ) son graficados con lnea segmentada y los datos
originales con crculos, ver figura (5.1). El trabajo real es hecho por la funcion intrpf. Un
bosquejo de lo que queremos que haga esta funcion a continuacion.
5.1. PROGRAMAS Y FUNCIONES. 171
Salida: y .
Las funciones en Octave estan implementadas como en la mayora de los lenguajes, excepto
que aqu cada funcion tiene que ir en un archivo separado. El nombre del archivo debe
coincidir con el nombre de la funcion (la funcion intrpf esta en el archivo intrpf.m).
function yi=intrpf(xi,x,y)
% Funcion para interpolar entre puntos
% usando polinomio de Lagrange (cuadratico)
% Entradas
% x Vector de las coordenadas x de los puntos dados (3 valores)
% y Vector de las coordenadas y de los puntos dados (3 valores)
% Salida
% yi El polinomio de interpolacion evaluado en xi
La funcion intrpf tiene tres argumentos de entrada y uno de salida. El resto de la funcion
ua el polinomio definido en (5.1). El cuerpo de la funcion a continuacion
es directa, solo eval
yi = (xi-x(2))*(xi-x(3))/((x(1)-x(2))*(x(1)-x(3)))*y(1) ...
+ (xi-x(1))*(xi-x(3))/((x(2)-x(1))*(x(2)-x(3)))*y(2) ...
+ (xi-x(1))*(xi-x(2))/((x(3)-x(1))*(x(3)-x(2)))*y(3);
return;
Programa de interpolaci
on en C++.
Las primeras lneas de la version en C++ del programa interp son
Comentarios mas una instruccion para incluir el archivo de encabezamiento NumMeth.h, lis-
tado a continuacion
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdlib>
La declaracion double intrpf(..) afirma que el programa pretende llamar una funcion
intrpf, la cual tiene tres argumentos de tipo double y devuelve un double. Las proximas
lneas del programa
El programa pregunta por los puntos para ajustar el polinomio de Lagrange (5.1) y por el
intervalo de interpolacion. Lo siguiente, los arreglos xi y yi son declarados:
En el primer caso hay asignamiento dinamico de memoria, nplot podra ser una entrada
del programa. En el segundo caso nplot debe ser constante y para modificar el n
umero de
puntos debemos recompilar el programa, asignacion estatica.
Los valores interpolados son calculados en un for
Notemos que xi[1]=xmn , xi[nplot]=xmax , con valores equiespaciados entre ellos. Los va-
lores de yi (y = p(x )) son evaluados usando la ecuacion (5.1) en la funcion intrpf. La
salida del programa
5.1. PROGRAMAS Y FUNCIONES. 173
#!/usr/bin/octave
load x.txt; load y.txt; load xi.txt; load yi.txt;
%* Grafica la curva dada por (xi,yi) y marca los puntos originales
xlabel(x);
ylabel(y);
title(Interpolacion de tres puntos);
gset nokey;
plot(x,y, *,xi,yi,-);
pause
system( "grafica.m" ) ;
La u
ltima lnea del programa
Esta lnea no es absolutamente necesaria, por que al salir el programa liberara la memoria
de todas maneras. Sin embargo, se considera como buen estilo de programacion, limpiar uno
la memoria que requirio durante la ejecucion del programa.
La funcion intrpf, la cual eval
ua el polinomio de Lagrange, comienza por las siguientes
lneas
double yi = (xi-x[2])*(xi-x[3])/((x[1]-x[2])*(x[1]-x[3]))*y[1]
+ (xi-x[1])*(xi-x[3])/((x[2]-x[1])*(x[2]-x[3]))*y[2]
+ (xi-x[1])*(xi-x[2])/((x[3]-x[1])*(x[3]-x[2]))*y[3];
return yi ;
Estas lneas eval
uan el polinomio. Inicialmente pondremos esta funcion en el mismo archivo,
luego la podemos separar en otro archivo y escribir un Makefile que genere el ejecutable.
(me e2 2.34 1068 [kg C2 ]). La mejor solucion para lidiar con este tipo de dificultades de
intervalo es trabajar en un conjunto de unidades naturales al problema (e.g. para problemas
atomicos se trabaja en las distancias en Angstroms y la carga en unidades de la carga del
electron).
Algunas veces los problemas de intervalo no son causados por la eleccion de las unida-
des, sino porque los numeros en el problema son inherentemente grandes. Consideremos un
importante ejemplo, la funcion factorial. Usando la definicion
n! = n (n 1) (n 2) . . . 3 2 1 , (5.3)
es facil evaluar n! en C++ como
double nFactorial=1;
for(int i=1; i <=n; i++) nFactorial *=i ;
donde n es un n
umero dado.
En Octave, usando el operador dos puntos este calculo puede ser realizado como
nFactorial = prod(1:n);
donde prod(x) es el producto de los elementos del vector x y 1:n=[1,2. . . , n]. Infortunada-
mente, debido a problemas de intervalo, no podemos calcular n! para n > 170 usando estos
metodos directos de evaluacion (5.3).
Una solucion com un para trabajar con n umeros grandes es usar su logaritmo. Para el
factorial
log(n!) = log(n) + log(n 1) + . . . + log(3) + log(2) + log(1) . (5.4)
En Octave, esto puede ser evaluado como
log_nFactorial = sum( log(1:n) ) ;
donde sum(x) es la suma de los elementos del vector x. Sin embargo, este esquema es compu-
tacionalmente pesado si n es grande. Una mejor estrategia es combinar el uso de logaritmos
con la formula de Stirling2
n n 1 1
n! = 2nn e 1+ + + (5.5)
12n 288n2
o
1 1 1
log(n!) = log(2n) + n log(n) n + log 1 + + + . (5.6)
2 12n 288n2
Esta aproximacion puede ser usada cuando n es grande (n > 30), de otra manera es preferible
la definicion original.
Finalmente, si el valor de n! necesita ser impreso, podemos expresarlo como
n! = (mantisa) 10(exponente) , (5.7)
donde el exponente es la parte entera de log10 (n!), y la mantisa es 10a donde a es la parte
fraccionaria de log10 (n!). Recordemos que la conversion entre logaritmo natural y logaritmo
en base 10 es log10 (x) = log10 (e) log(x).
2
M. Abramowitz and I. Stegun, Handbook of Mathematical Functions ( New York: Dover 1972).
176 CAPITULO 5. PRELIMINARES.
0
10
2
10
4
(h)
10
6
10
8
10
10
10 20 16 12 8 4 0
10 10 10 10 10 10
h
Figura 5.2: Error absoluto (h), ecuacion (5.9), versus h para f (x) = x2 y x = 1.
La figura 5.2 ilustra la magnitud del error de redondeo en un calculo tpico de derivada.
Definimos el error absoluto
0 f (x + h) f (x)
(h) = f (x)
. (5.9)
h
5.2. ERRORES NUMERICOS. 177
Notemos que (h) decrece cuando h se hace mas peque no, lo cual es esperado, dado que
la ecuacion (5.8) es exacta cuando h 0. Por debajo de h = 1010 , el error comienza a
incrementarse debido a efectos de redondeo. En valores menores de h el error es tan grande
que la respuesta carece de sentido. Volveremos en el proximo captulo a la pregunta de como
mejorar el calculo de la derivada numericamente.
Para testear la tolerancia del redondeo, definimos como el mas peque no numero que,
cuando es sumado a uno, regresa un valor distinto de 1. En Octave, la funcion integrada
eps devuelve 2.22 1016 . En C++, el archivo de encabezamiento <cfloat> define
DBL_EPSILON (2.2204460492503131e-16) como para doble precision.
Debido a los errores de redondeo la mayora de los calculos cientficos usan doble precision.
Las desventajas de la doble precision son que requieren mas memoria y que algunas veces (no
siempre) es mas costosa computacionalmente. Los procesadores modernos estan construidos
para trabajar en doble precision, tanto que puede ser mas lento trabajar en precision simple.
Usar doble precision algunas veces solo desplaza las dificultades de redondeo. Por ejemplo, el
calculo de la inversa de una matriz trabaja bien en simple precision para matrices peque nas
de 50 50 elementos, pero falla por errores de redondeo para matrices mas grandes. La
doble precision nos permite trabajar con matrices de 100 100, pero si necesitamos resolver
sistemas aun mas grandes debemos usar un algoritmo diferente. La mejor manera de trabajar
es usar algoritmos robustos contra el error de redondeo.
178 CAPITULO 5. PRELIMINARES.
Captulo 6
En este captulo resolveremos uno de los primeros problemas considerados por un estu-
diante de fsica: el vuelo de un proyectil y, en particular, el de una pelota de baseball. Sin
la resistencia del aire el problema es facil de resolver. Sin embargo, incluyendo un arrastre
realista, nosotros necesitamos calcular la solucion numericamente. Para analizar este proble-
ma definiremos primero la diferenciacion numerica. De hecho antes de aprender Fsica uno
aprende calculo as que no debemos sorprendernos si este es nuestro punto de partida. En la
segunda mitad del captulo nos ocuparemos de otro viejo conocido, el pendulo simple, pero
sin la aproximacion a angulos pequenos. Los problemas oscilatorios, tales como el pendulo,
nos revelaran una falla fatal en algunos de los metodos numericos de resolver ecuaciones
diferenciales ordinarias.
179
180 CAPITULO 6. EDO: METODOS
BASICOS.
6.1.3. M
etodo de Euler.
Las ecuaciones de movimiento que nosotros deseamos resolver numericamente pueden ser
escritas como:
d~v d~r
= ~a(~r, ~v ) , = ~v , (6.12)
dt dt
donde ~a es la aceleracion. Notemos que esta es la forma mas general de las ecuaciones. En
el movimiento de proyectiles la aceleracion es solo funcion de ~v (debido al arrastre), en otros
problemas (e.g., orbitas de cometas) la aceleracion dependera de la posicion.
Usando la derivada adelantada (6.11), nuestras ecuaciones de movimiento son
~v (t + ) ~v (t)
+ O( ) = ~a(~r(t), ~v (t)) , (6.13)
~r(t + ) ~r(t)
+ O( ) = ~v (t) , (6.14)
o bien
fn = f (tn ) , tn = (n 1) , n = 1, 2, . . . (6.17)
tal que f1 = f (t = 0). Nuestras ecuaciones para el metodo de Euler (despreciando el termino
del error) ahora toma la forma
5. Vaya al paso 3 hasta que suficientes puntos de trayectoria hayan sido calculados.
El metodo calcula un conjunto de valores para ~rn y ~vn que nos da la trayectoria, al menos
en un conjunto discreto de valores. La figura 6.1 ilustra el calculo de la trayectoria para un
u
nico paso de tiempo.
6.1. MOVIMIENTO DE UN PROYECTIL. 183
vn x vn vn
an
an
vn+1
rn rn+1
6.1.4. M
etodos de Euler-Cromer y de Punto Medio.
Una simple (y por ahora injustificada) modificacion del metodo de Euler es usar las
siguientes ecuaciones:
sido el error local, el error cometido en un unico paso de tiempo. En un problema tpico
nosotros deseamos evaluar la trayectoria desde t = 0 a t = T . El n
umero de pasos de tiempo
es NT = T / ; notemos que si reducimos , debemos tomar mas pasos. Si el error local es
O( n ), entonces estimamos el error global como
Cuadro 6.1: Bosquejo del programa balle, el cual calcula la trayectoria de una pelota de
baseball usando el metodo de Euler.
Movimiento de Proyectil
Mtodo de Euler
Teora (sin aire)
6
4
Altura [m]
0 5 10 15 20 25
Alcance [m]
Figura 6.2: Salida del programa balle para una altura inicial de 0 [m], una velocidad inicial
de 15 [m/s], y un paso de tiempo =0.1 [s]. No hay resistencia del aire. La lnea continua es
la teorica y los puntos son los calculados, la diferencia se debe a errores de truncamiento.
jrogan@huelen:~/programas$ balle
Ingrese la altura inicial [m] : 0
Ingrese la velocidad inicial [m/s]: 15
Ingrese angulo inicial (grados): 45
186 CAPITULO 6. EDO: METODOS
BASICOS.
Movimiento de Proyectil
Mtodo de Euler
Teora (sin aire)
60
40
Altura [m]
20
0
0 50 100 150 200 250
Alcance [m]
Figura 6.3: Salida del programa balle para una altura inicial de 1 [m], una velocidad inicial
de 50 [m/s], y un paso de tiempo =0.1 [s]. Con resistencia del aire.
6.2. P
endulo simple.
6.2.1. Ecuaciones b
asicas.
El movimiento de los pendulos ha fascinado a fsicos desde que Galileo fue hipnotizado
por la lampara en la Catedral de Pisa. El problema es tratado en los textos de mecanica
basica pero antes de apresurarnos a calcular con el computador, revisemos algunos resultados
6.2. PENDULO SIMPLE. 187
basicos. Para un pendulo simple es mas conveniente describir la posicion en terminos del
desplazamiento angular, (t). La ecuacion de movimiento es
d2 g
2
= sen , (6.26)
dt L
donde L es la longitud del brazo y g es la aceleracion de gravedad. En la aproximacion para
no, sen , la ecuacion (6.26) se simplifica a
angulo peque
d2 g
2
= . (6.27)
dt L
Esta ecuacion diferencial ordinaria es facilmente resuelta para obtener
2t
(t) = C1 cos + C2 , (6.28)
Ts
donde las constantes C1 y C2 estan determinadas por los valores iniciales de y = d/dt.
El perodo para angulos peque
nos, Ts es
s
L
Ts = 2 . (6.29)
g
1
mL2 2 mgL cos = mgL cos m , (6.31)
2
o
2g
2 = (cos cos m ) . (6.32)
L
Ya que = d/dt,
d
dt = r . (6.33)
2g
(cos cos m )
L
En un perodo el pendulo se balancea de = m a = m y regresa a = m . As, en medio
perodo el pendulo se balancea desde = m a = m . Por u
ltimo, por el mismo argumento,
188 CAPITULO 6. EDO: METODOS
BASICOS.
usando el cambio de variable sen z = sen(/2)/ sen(m /2). Para valores peque
nos de m ,
podramos expandir K(x) para obtener
s
L 1 2
T = 2 1+ + ... . (6.38)
g 16 m
6.2.2. F
ormulas para la derivada centrada.
Antes de programar el problema del pendulo miremos un par de otros esquemas para
calcular el movimiento de un objeto. El metodo de Euler esta basado en la formulacion de la
derivada derecha para df /dt dado por (6.7). Una definicion equivalente para la derivada es
f (t + ) f (t )
f 0 (t) = lm . (6.39)
0 2
Esta formula se dice centrada en t. Mientras esta formula parece muy similar a la ecuacion
(6.7), hay una gran diferencia cuando es finito. Nuevamente, usando la expansion de Taylor,
1 1
f (t + ) = f (t) + f 0 (t) + 2 f 00 (t) + 3 f (3) (+ ) , (6.40)
2 6
0 1 2 00 1
f (t ) = f (t) f (t) + f (t) 3 f (3) ( ) , (6.41)
2 6
4
I.S. Gradshteyn and I.M. Ryzhik, Table of Integral, Series and Products (New York: Academic Press,
1965)
6.2. PENDULO SIMPLE. 189
donde f (3) es la tercera derivada de f (t) y es un valor ente t y t . Restando las dos
ecuaciones anteriores y reordenando tenemos,
f (t + ) f (t ) 1 2 (3)
f 0 (t) = f () , (6.42)
2 6
f (t + ) + f (t ) 2f (t) 1
f 00 (t) = 2
2 f (4) () , (6.43)
12
donde t t + . De nuevo, el error de truncamiento es cuadratico en . La mejor
manera de entender esta formula es pensar que la segunda derivada esta compuesta de una
derivada derecha y de una derivada izquierda, cada una con incrementos de /2.
Usted podra pensar que el proximo paso sera preparar formulas mas complicadas que
tengan errores de truncamiento a nos, quizas usando ambas f (t ) y f (t 2 ).
un mas peque
Aunque tales formulas existen y son ocasionalmente usadas, las ecuaciones (6.10), (6.42) y
(6.43) sirven como el caballo de trabajo para calcular las derivadas primera y segunda.
6.2.3. M
etodos del salto de la rana y de Verlet.
Para el pendulo, las posiciones y velocidades generalizadas son y , pero para mantener
la misma notacion anterior trabajaremos con ~r y ~v . Comenzaremos de las ecuaciones de
movimiento escritas como
d~v
= ~a(~r(t)) , (6.44)
dt
d~r
= ~v (t) . (6.45)
dt
Note que explcitamente escribimos la aceleracion dependiente solamente de la posicion. Dis-
cretizando la derivada temporal usando la aproximacion de derivada centrada da,
~v (t + ) ~v (t )
+ O( 2 ) = ~a(~r(t)) , (6.46)
2
para la ecuacion de la velocidad. Note que aunque los valores de velocidad son evaluados en
t + y t , la aceleracion es evaluada en el tiempo t.
Por razones que pronto seran claras, la discretizacion de la ecuacion de posicion estara cen-
trada entre t + 2 y t,
~r(t + 2 ) ~r(t)
+ O( 2 ) = ~v (t + ) . (6.47)
2
190 CAPITULO 6. EDO: METODOS
BASICOS.
Este es el metodo del salto de la rana (leap frog). Naturalmente, cuando el metodo es usado
en un programa, el termino O( 3 ) no va y por lo tanto constituye el error de truncamiento
para el metodo.
El nombre salto de la rana es usado ya que la solucion avanza en pasos de 2 , con la
posicion evaluada en valores impares (~r1 , ~r3 , ~r5 , . . . ), mientras que la velocidad esta calculada
en los valores pares (~v2 , ~v4 , ~v6 , . . . ). Este entrelazamiento es necesario ya que la aceleracion,
la cual es una funcion de la posicion, necesita ser evaluada en un tiempo que esta centrado
entre la velocidad nueva y la antigua. Algunas veces el esquema del salto de la rana es
formulado como
Estas ecuaciones, conocidas como el metodo de Verlet 5 , podran parecer extra nas a pri-
mera vista, pero ellas son faciles de usar. Suponga que conocemos ~r0 y ~r1 ; usando la ecuacion
(6.59), obtenemos ~r2 . Conociendo ~r1 y ~r2 podramos ahora calcular ~r3 , luego usando la ecua-
cion (6.58) obtenemos ~v2 , y as sucesivamente.
Los metodos del salto de la rana y de Verlet tienen la desventaja que no son autoini-
ciados. Usualmente tenemos las condiciones iniciales ~r1 = ~r(t = 0) y ~v1 = ~v (t = 0), pero no
~v0 = ~v (t = ) [necesitado por el salto de la rana en la ecuacion (6.50)] o ~r0 = ~r(t = )
[necesitado por Verlet en la ecuacion (6.59)]. Este es el precio que hay que pagar para los
esquemas centrados en el tiempo.
Para lograr que estos metodos partan, tenemos una variedad de opciones. El metodo de
Euler-Cromer, usando la ecuacion (6.53), toma ~v1/2 = ~v1 , lo cual es simple pero no muy
preciso. Una alternativa es usar otro esquema para lograr que las cosas partan, por ejemplo,
en el salto de la rana uno podra tomar un paso tipo Euler para atras, ~v0 = ~v1 ~a1 .
Algunas precauciones deberan ser tomadas en este primer paso para preservar la precision
del metodo; usando
2
~r0 = ~r1 ~v1 + ~a(~r1 ) , (6.60)
2
es una buena manera de comenzar el metodo de Verlet.
Ademas de su simplicidad, el metodo del salto de la rana a menudo tiene propiedades
favorables (e.g. conservacion de la energa) cuando resuelve ciertos problemas. El metodo de
Verlet tiene muchas ventajas. Primero, la ecuacion de posicion tiene un error de truncamiento
menor que otros metodos. Segundo, si la fuerza es solamente una funcion de la posicion y si
nos preocupamos solo de la trayectoria de la partcula y no de su velocidad (como en muchos
problemas de mecanica celeste), podemos saltarnos completamente el calculo de velocidad.
El metodo es popular para el calculo de las trayectorias en sistemas con muchas partculas,
por ejemplo, el estudio de fluidos a nivel microscopico.
6.2.4. Programa de p
endulo simple.
Las ecuaciones de movimiento para un pendulo simple son
d d
= () = , (6.61)
dt dt
donde la aceleracion angular () = g sen /L. El metodo de Euler para resolver estas
ecuaciones diferenciales ordinarias es iterar las ecuaciones:
n+1 = n + n , (6.62)
n+1 = n + n . (6.63)
Tomar un paso para atras para partir Verlet; ver ecuacion (6.60).
Iterar sobre el n
umero deseado de pasos con el paso de tiempo y metodo numerico dado.
Cuadro 6.2: Bosquejo del programa p endulo, el cual calcula el tiempo de evolucion de un
pendulo simple usando el metodo de Euler o Verlet.
En vez de usar las unidades SI, usaremos las unidades adimensionales naturales del pro-
blema. Hay solamente dos parametros en el problema, g y L y ellos siempre aparecen en la
razon g/L. Fijando esta razon a la unidad, el perodo para peque nas amplitudes Ts = 2.
En otras palabras, necesitamos solamente una unidad en el problema: una escala de tiempo.
Ajustamos nuestra unidad de tiempo tal que el perodo de peque nas amplitudes sea 2.
La tabla 6.2 presenta un bosquejo del programa pendulo, el cual calcula el movimiento
de un pendulo simple usando o el metodo de Euler o el de Verlet. El programa estima el
perodo por registrar cuando el angulo cambia de signo; esto es verificar si n y n+1 tienen
signos opuestos probando si n n+1 < 0. Cada cambio de signo da una estimacion para el
perodo, Tk = 2 (nk+1 nk ), donde nk es el paso de tiempo en el cual el k-esimo cambio de
signo ocurre. El perodo estimado de cada inversion de signo es registrado, y el valor medio
calculado como
M
D E 1 X
T = Tk , (6.65)
M k=1
menta, la desviacion estandar de la muestra tiende a una constante, mientras que la barra
de error estimado decrece.
Para comprobar el programa pendulo, primero tratamos con angulos iniciales peque nos,
m , ya que conocemos el perodo T 2. Tomando = 0.1 tendremos sobre 60 puntos
por oscilacion; tomando 300 pasos deberamos tener como cinco oscilaciones. Para m = 10 ,
el metodo de Euler calcula un perodo estimado de hTi = 6.375 0.025 sobre un 1.5 %
mayor que el esperado T = 2(1.002) dado por la ecuacion (6.38). Nuestro error estimado
para el perodo es entorno a en cada medida. Cinco oscilaciones son 9 medidas de T,
as que nuestro error estimado para el perodo debera ser ( /2)/ 9 0.02. Notemos que la
estimacion esta en buen acuerdo con los resultados obtenidos usando la desviacion estandar.
Hasta aqu todo parece razonable.
40
30
20
10
Angulo [grados]
10
20
30
40
50
0 5 10 15 20 25 30
Tiempo
Figura 6.4: Salida del programa p endulo usando el metodo de Euler. El angulo inicial es
m = 10 , el paso en el tiempo es = 0.1, y 300 iteraciones fueron calculadas.
Infortunadamente si miramos el grafico 6.4 nos muestra los problemas del metodo de Euler.
La amplitud de oscilacion crece con el tiempo. Ya que la energa es proporcional al angulo
maximo, esto significa que la energa total se incrementa en el tiempo. El error global de
truncamiento en el metodo de Euler se acumula en este caso. Para pasos de tiempos peque nos
= 0.05 e incrementos en el numero de pasos (600) podemos mejorar los resultados, ver figura
6.5, pero no eliminamos el error. El metodo del punto medio tiene la misma inestabilidad
numerica.
Usando el metodo de Verlet con m = 10 , el paso en el tiempo = 0.1 y 300 iteraciones
obtenemos los resultados graficados en 6.5. Estos resultados son mucho mejores; la amplitud
de oscilacion se mantiene cerca de los 10 y hTi = 6.275 0.037. Afortunadamente el metodo
de Verlet, el del salto de rana y el de Euler-Cromer no sufren de la inestabilidad numerica
encontrada al usar el metodo de Euler.
Para m = 90 , la primera correccion para la aproximacion de angulo pequeno, ecuacion
(6.38), da T = 7.252. Usando el metodo de Verlet, el programa da un perodo estimado de
hTi = 7.414 0.014, lo cual indica que (6.38) es una buena aproximacion (alrededor de un
194 CAPITULO 6. EDO: METODOS
BASICOS.
20
15
10
Angulo [grados]
0
10
15
20
25
0 5 10 15 20 25 30
Tiempo
Figura 6.5: Salida del programa p endulo usando el metodo de Euler. El angulo inicial es
m = 10 , el paso en el tiempo es = 0.05 y 600 iteraciones fueron calculadas.
15
10
Angulo [grados]
10
15
0 5 10 15 20 25 30
Tiempo
Figura 6.6: Salida del programa p endulo usando el metodo de Verlet. El angulo inicial es
m = 10 , el paso en el tiempo es = 0.1 y 300 iteraciones fueron calculadas.
150
100
Angulo [grados]
50
50
100
150
200
0 5 10 15 20 25 30
Tiempo
Figura 6.7: Salida del programa p endulo usando el metodo de Verlet. El angulo inicial es
m = 170 , el paso en el tiempo es = 0.1 y 300 iteraciones fueron calculadas.
int main()
{
const double Cd=0.35;
const double rho=1.293; // [kg/m^3]
const double radio=0.037; // [m]
double A= M_PI*radio*radio ;
double m=0.145; // [kg]
double g=9.8; // [m/s^2]
double a = -Cd*rho*A/(2.0e0*m) ;
int flagRA = 2 ;
while (flagRA!=0 && flagRA !=1) {
cout <<"Con resistencia del aire, Si= 1, No= 0: ";
cin >> flagRA;
}
cout <<"Ingrese el paso en el tiempo, tau en [s]: ";
cin >> tau ;
double vxn=v0*cos(M_PI*theta0/180.0) ;
double vyn=v0*sin(M_PI*theta0/180.0) ;
double xn=x0 ;
double yn=y0 ;
double tiempo = -tau;
while( yn >= y0) {
tiempo +=tau ;
salidaT << x0+v0*cos(M_PI*theta0/180.0) *tiempo <<" " ;
salidaT << y0+v0*sin(M_PI*theta0/180.0) *tiempo -g*tiempo*tiempo/2.0e0<< endl;
salida << xn << " " << yn << endl;
if(flagRA==0) a=0.0e0 ;
double v=sqrt(vxn*vxn+vyn*vyn) ;
double axn= a*v*vxn ;
double ayn= a*v*vyn -g ;
double xnp1 = xn + tau*vxn ;
double ynp1 = yn + tau*vyn ;
double vxnp1 = vxn + tau*axn;
double vynp1 = vyn + tau*ayn;
vxn=vxnp1;
vyn=vynp1;
xn=xnp1 ;
yn=ynp1 ;
}
cout << "Tiempo de vuelo: " << tiempo<< endl;
cout << "Alcance: " << xn<<endl;
salida.close();
return 0;
}
6.3.2. pendulo.cc
#include "NumMeth.h"
int main()
{
6.3. LISTADO DE LOS PROGRAMAS. 197
int respuesta=2 ;
while(respuesta != 0 && respuesta !=1 ) {
cout << "Eliga el metodo: Euler=0 y Verlet=1: " ;
cin >> respuesta ;
}
double theta1 ;
double omega1 = 0.0e0;
cout << "Ingrese el angulo inicial (grados): ";
cin >> theta1 ;
theta1*=M_PI/180.0e0 ;
double tau ;
cout << "Ingrese el paso de tiempo: ";
cin >> tau ;
int pasos ;
cout << "Ingrese el numero de pasos: ";
cin >> pasos ;
double thetaNm1=theta0 ;
double thetaN=theta1 ;
double omegaN=omega1;
int nK=1;
int M=0 ;
} else {
periodo[M++] = 2.0e0*tau*double(i-nK);
nK=i ;
}
}
thetaNm1=thetaN ;
thetaN=thetaNp1 ;
omegaN=omegaNp1 ;
}
double Tprom=0.0e0;
for (int i=1; i < M; i++) Tprom+=periodo[i] ;
Tprom/=double(M-1) ;
double ssr=0.0 ;
for (int i=1; i < M; i++) ssr+=(periodo[i]-Tprom)* (periodo[i]-Tprom);
ssr/=double(M-2);
double sigma =sqrt(ssr/double(M-1)) ;
cout <<" Periodo = "<< Tprom << "+/-"<< sigma << endl ;
salida.close() ;
delete [] periodo;
return 0;
}
Captulo 7
Ecuaciones Diferenciales
Ordinarias II: M
etodos Avanzados.
on 3.2 16 Diciembre 20031
versi
7.1.
Orbitas de cometas.
7.1.1. Ecuaciones b
asicas.
Considere el problema de Kepler en el cual un peque no satelite, tal como un cometa, orbita
el Sol. Usamos un sistema de coordenadas Copernicano y fijamos el Sol en el origen. Por ahora,
consideremos solamente la fuerza gravitacional entre el cometa y el Sol, y despreciemos todas
las otras fuerzas (e.g., fuerzas debidas a los planetas, viento solar). La fuerza sobre el cometa
es
GmM
F~ = ~r , (7.1)
| ~r |3
donde ~r es la posicion del cometa, m es su masa, M = 1.99 1030 [kg] es la masa del Sol, y
G = 6.67 1011 [m3 /kg s2 ] es la constante gravitacional.
Las unidades naturales de longitud y tiempo para este problema no son metros ni segun-
dos. Como unidad de distancia usaremos la unidad astronomica [AU], 1 AU=1.4961011 [m],
la cual es igual a la distancia media de la Tierra al Sol. La unidad de tiempo sera el [a
no]
AU (el perodo de una orbita circular de radio 1 [AU]). En estas unidades, el producto
GM = 4 2 [AU3 /a no2 ]. Tomaremos la masa del cometa, m, como la unidad; en unidades
MKS la masa tpica de un cometa es 10153 [kg].
Ahora tenemos suficiente para ensamblar nuestro programa, pero antes hagamos una
rapida revision de lo que sabemos de orbitas. Para un tratamiento completo podemos recurrir
1
Este captulo est
a basado en el tercer captulo del libro: Numerical Methods for Physics, second edition
de Alejandro L. Garcia, editorial Prentice Hall.
199
200 CAPITULO 7. EDO II: METODOS
AVANZADOS.
a algunos textos de mecanica estandar, tales como Symon2 o Landau y Lifshitz3 . La energa
total del satelite es
1 GM m
E = mv 2 , (7.2)
2 r
donde r = | ~r | y v = | ~v |. Esta energa total es conservada, tal como el momento angular,
~ = ~r (m~v ) .
L (7.3)
q
2b
r
x
Q
2a
Figura 7.1: Orbita elptica alrededor del Sol.
La excentricidad de la Tierra es e = 0.017, por lo tanto esta orbita esta muy cercana de ser
circular. La distancia del Sol al perihelio (punto de mayor aproximacion) es q = (1 e)a; la
distancia del Sol al afelio es Q = (1 + e)a.
La ecuacion (7.6) tambien se mantiene para una orbita elptica, si reemplazamos el radio
con el semieje mayor; por lo tanto la energa total es
GM m
E= . (7.8)
2a
Note que E 0. De las ecuaciones (7.2) y (7.8), encontramos que la velocidad orbital como
funcion de la distancia radial es
s
2 1
v = GM . (7.9)
r a
Iterar sobre el n
umero deseado de pasos usando el metodo numerico especificado.
Cuadro 7.2: Bosquejo del programa orbita, el cual calcula la trayectoria de un cometa usando
varios metodos numericos.
90 o
30
Energa Cintica
Energa Potencial
Energa [M AU*AU/ao*ao]
Energa Total
20
10
180o 0o
10
20
30
40
0 0.5 1 1.5 2 2.5 3 3.5 4
3 2 1 0 1 2 3
Figura 7.2: Grafico de la trayectoria y la energa desde el programa orbita usando el metodo
de Euler. La distancia radial inicial es 1 [AU] y la velocidad tangencial inicial es 2 [AU/a
no].
El paso en el tiempo es = 0.02 [a nos]; y 200 pasos son calculados. Los resultados estan en
desacuerdo con la prediccion teorica de una orbita circular con energa total constante.
energa llega a ser positiva; el satelite alcanza la velocidad de escape. Si bajamos el paso de
tiempo desde = 0.02 [a nos] a = 0.005 [a nos] obtenemos mejores resultados, como los
mostrados en la figura 7.5. Estos resultados no son del todo perfectos; la orbita puede ser
una elipse cerrada, pero todava tiene una notable deriva esp uria.
En este punto usted se podra estar preguntando, Por que estamos estudiando este
problema?, si la solucion analtica es bien conocida. Es verdad que hay problemas mecanicos
celestes mas interesantes (e.g., el efecto de perturbaciones sobre la orbita, problema de tres
cuerpos). Sin embargo, antes de hacer los casos complicados podramos, siempre, chequear
los algoritmos de problemas conocidos. Suponga que introducimos una peque na fuerza de
arrastre sobre el cometa. Podramos pecar de inocentes creyendo que la precision de la figura
7.5 fue un fenomeno fsico mas que un artefacto numerico.
90 o
30
Energa [M AU*AU/ao*ao]
20
Energa Cintica
10
Energa Potencial
Energa Total
0
180o 0o 10
20
30
40
50
1.5 1 0.5 0 0.5 1 1.5 0 0.5 1 1.5 2 2.5 3 3.5 4
Figura 7.3: Grafico de la trayectoria y la energa desde el programa orbita usando el metodo
de Euler-Cromer. Los parametros son los mismos que en la figura 7.2. Los resultados estan en
un acuerdo cualitativo al menos con la prediccion teorica de una orbita circular con energa
total constante.
90o
Energa Potencial
Energa Total
100
180 o 0o
0
100
200
270 o 0 1 2 3 4
30 20 10 0 10 20 30
Distancia [AU] Tiempo [aos]
Figura 7.4: Grafico de la trayectoria y la energa desde el programa orbita usando el metodo
de Euler-Cromer. La distancia radial inicial es 1 [AU] y la velocidad tangencial inicial es
[AU/a no]. El paso en el tiempo es = 0.02 [a nos]; y 200 pasos son calculados. Debido al
error numerico el cometa alcanza la velocidad de escape, la posicion final es 35 [AU] y la
energa total es positiva.
7.2. METODOS DE RUNGE-KUTTA. 205
90 o
300
Energa [M AU*AU/aos*aos]
Energa Cintica
200 Energa Potencial
Energa Total
100
180o 0o 0
100
200
300
270o
1 0.5 0 0.5 1 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1
Distancia [AU] Tiempo [aos]
Figura 7.5: Grafico de la trayectoria y la energa desde el programa orbita usando el metodo
de Euler-Cromer. Los parametros son los mismos que en la figura 7.4 excepto que el paso de
tiempo es mas peque no = 0.005 [a nos]. Los resultados son mejores, pero a
un presenta una
precesion esp
uria.
7.2. M
etodos de Runge-Kutta.
7.2.1. Runge-Kutta de segundo orden.
Ahora miremos uno de los metodos mas populares para resolver numericamente las ecua-
ciones diferenciales ordinarias: Runge-Kutta. Primero trabajaremos las formulas generales de
Runge-Kutta y luego las aplicaremos especficamente a nuestro problema del cometa. De esta
manera sera facil usar el metodo Runge-Kutta para otros sistemas fsicos. Nuestra ecuacion
diferencial ordinaria general toma la forma
d~x
= f~(~x(t), t) , (7.15)
dt
donde el vector de estado x(t) = [x1 (t), x2 (t), . . . xN (t)] es la solucion deseada. En el problema
de Kepler tenemos
~x(t) = [rx (t), ry (t), vx (t), vy (t)] , (7.16)
y
~ drx dry dvx dvy
f (~x(t), t) = , , , ,
dt dt dt dt (7.17)
= [vx (t), vy (t), Fx (t)/m, Fy (t)/m] ,
Nuestro punto de partida es el metodo simple de Euler; en forma vectorial podra ser
escrito como
~x(t + ) = ~x(t) + f~(~x, t) . (7.18)
Consideremos la primera formula de Runge-Kutta:
1 1
~x(t + ) = ~x(t) + f~ ~x t + , t + ,
(7.19)
2 2
donde
1 1
~x t + ~x(t) + f~(~x, t) .
(7.20)
2 2
Para ver de donde viene esta formula, consideremos por el momento el caso de una
variable. Sabemos que la expansion de Taylor
dx()
x(t + ) = x(t) + ,
dt (7.21)
= x(t) + f (x(), ) ,
es exacta para alg un valor de entre t y t + , como se vio en la ecuacion (6.10). La formula
de Euler toma = t; Euler-Cromer usa = t en la ecuacion de velocidad y = t + en la
ecuacion de posicion. Runge-Kutta usa = t+ 21 , lo cual pareciera ser una mejor estimacion.
Sin embargo, x t + 12 no es conocida,
podemos aproximarla de la manera simple: usando
un paso de Euler calculamos x t + 12 y usando esta como nuestra estimacion de x t + 21 .
7.2.2. F
ormulas generales de Runge-Kutta.
La formula discutida arriba no es la u
nica posible para un Runge-Kutta de segundo orden.
Aqu hay una alternativa:
1
~x(t + ) = ~x(t) + [f~(~x(t), t) + f~(~x (t + ), t + )] , (7.23)
2
donde
~x (t + ) ~x(t) + f~(~x(t), t) . (7.24)
Para entender este esquema, consideremos nuevamante el caso en una variable. En nuestra
formula original, estimamos que f (x(), ) como 21 [f (x, t) + f (x (t + ), t + )].
Estas expresiones pueden ser deducidas usando la expansion de Taylor con dos variables,
n
X 1
f (x + h, t + ) = h + f (x, t) , (7.25)
n=0
n! x t
donde todas las derivadas son evaluadas en (x, t). Para una formula general de Runge-Kutta
de segundo orden queremos obtener una expresion de la siguiente forma
x(t + ) = x(t) + w1 f (x(t), t) + w2 f (x , t + ) , (7.26)
donde
x x(t) + f (x(t), t) . (7.27)
Hay cuatro coeficientes no especificados: , , w1 y w2 . Note que cubrimos las ecuaciones
(7.19) y (7.20) eligiendo los valores
1 1
w1 = 0 , w2 = 1 = , = , (7.28)
2 2
y las ecuaciones (7.23) y (7.24) eligiendo
1 1
w1 = , w2 = , = 1 , = 1 . (7.29)
2 2
Deseamos seleccionar cuatro coeficientes tal que tengamos una precision de segundo orden;
esto es deseamos calzar la serie de Taylor a traves de los terminos de la segunda derivada.
Los detalles del calculo se proponen como un ejercicio, pero cualquier grupo de coeficientes
satisfacen las relaciones siguientes w1 + w2 = 1, w2 = 1/2 y = daran un esquema
Runge-Kutta de segundo orden. El error de truncamiento local es O( 3 ), pero la expresion
explcita no tiene una forma simple. No esta claro que un esquema sea superior al otro ya
que el error de truncamiento, siendo una funcion complicada de f (x, t), variara de problema
a problema.
donde
F~1 = f~(~x, t) ,
1 1
F~2 = f~ ~x + F~1 , t + ,
2 2
(7.31)
~ ~ 1 ~ 1
F3 = f ~x + F2 , t + ,
2 2
F~4 = f~(~x + F~3 , t + ) .
El siguiente extracto del Numerical Recipes4 resume mejor el estado que las formulas de
arriba tienen en el mundo del analisis numerico:
Para muchos usuarios cientficos, el metodo de Runge-Kutta de cuarto orden no es
solo la primera palabra en esquemas de integracion para ecuaciones diferenciales
ordinarias, si no que es la u
ltima tambien. De hecho, usted puede ir bastante lejos
con este viejo caballito de batalla, especialmente si los combina con un algortmo
de paso adaptativo. . . Bulirsch-Stoer o los metodos predictor-corrector pueden ser
mucho mas eficientes para problemas donde se require una alta precision. Estos
metodos son los finos caballos de carrera mientras que Runge-Kutta es el fiel
caballo de tiro.
Usted se preguntara, por que formulas de cuarto orden y no de orden superior? Bien, los
metodos de orden superior tienen un error de truncamiento mejor, pero tambien requieren
mas calculo, esto es, mas evaluaciones de f (x, t). Hay dos opciones, hacer mas pasos con un
peque no usando un metodo de orden inferior o hacer pocos pasos con un mas grande usando
un metodo de orden superior. Ya que los metodos de Runge-Kutta de ordenes superiores son
muy complicados, el esquema de cuarto orden dado anteriormente es muy conveniente. Entre
parentesis, el error de truncamiento local para Runge-Kutta de cuarto orden es O( 5 ).
Salidas: ~x(t + ).
Para implementar metodos de cuarto orden para nuestro problema de la orbita, usaremos
la funcion rk4 (tabla 7.3). Esta funcion toma como datos: el estado actual del sistema, ~x(t); el
4
W. Press, B. Flannery, S. Tukolsky and W. Vetterling, Numerical Recipes in fortran, 2nd ed. (Cam-
bridge: Cambridge University Press 1992).
7.2. METODOS DE RUNGE-KUTTA. 209
Salidas: d~x(t)/dt.
ua la aceleracion ~a = (GM~r/ | ~r |3 ).
Eval
Cuadro 7.4: Bosquejo de la funcion gravrk, la cual es usada por la funcion Runge-Kutta para
evaluar las ecuaciones de movimiento para el problema de Kepler.
paso de tiempo para ser usado, ; el tiempo actual, t; la funcion f~(~x(t), t; ); donde es una
lista de parametros usados por f~. La salida es el nuevo estado del sistema, ~x(t + ), calculado
por el metodo de Runge-Kutta. Usando Runge-Kutta de cuarto orden da los resultados
mostrados en la figura 7.6, la cual es mucho mejor que las obtenidas usando el metodo de
Euler-Cromer (figura 7.5).
90 o
300
Energa Cintica
Energa [M AU*AU/aos*aos]
Energa Potencial
Energa Total
200
100
180o 0o 0
100
200
300
1 0.5 0 0.5 1 0 0.2 0.4 0.6 0.8 1.0
Distancia [AU] o Tiempo [aos]
270
Figura 7.6: Grafico de la trayectoria y la energa desde el programa orbita usando el metodo
de Runge-Kutta. La distancia radial inicial es 1 [AU] y la velocidad tangencial inicial es
[AU/a no]. El paso en el tiempo es = 0.005 [a nos]; y 200 pasos son calculados. Comparemos
con la figura 7.5.
Cuando es llamado por orbita, esta funcion recibe un puntero a gravrk en la variable
derivsRK. Dentro de rk4, la sentencia
(*derivsRK)( x, t, param, F1 ) ;
es equivalente a
gravrk( x, t, param, F1 ) ;
7.3. M
etodos adaptativos
7.3.1. Programas con paso de tiempo adaptativo.
Ya que el metodo de Runge-Kutta de cuarto orden es mas preciso (errores de truncamiento
peque nos), hace un mejor trabajo dentro de una orbita altamemente elptica. A un para una
distancia inicial al afelio de 1 [AU] y una velocidad inicial en el afelio de /2 [AU/a no] usando
1
un paso tiempo tan peque no como = 0.0005 [a nos] ( 4 2 [hrs]), la energa total vara sobre
el 7 % por orbita. Si pensamos la fsica, llegamos a que realizar una integracion con un paso
peque no es solo necesaria cuando el cometa haga su acercamiento mas proximo, punto en el
cual su velocidad es maxima. Cualquier error peque no en la trayectoria cuando rodea al Sol
causa una gran desviacion en la energa potencial.
La idea ahora es disenar un programa que use un paso de tiempo peque no cuando el come-
ta esta cerca del Sol y pasos de tiempo grande cuando esta lejos. Tal como esta, normalmente
tenemos solo una idea aproximada de lo que pudiera ser; ahora tenemos que seleccionar un
mn y un max y una manera de intercambiar entre ellos. Si tenemos que hacer esto por prueba
y error manual, podra ser peor que haciendolo por la fuerza bruta calculando con un paso
de tiempo peque no toda la trayectoria. Idealmente, deseamos estar completamente liberados
de tener que especificar un paso de tiempo. Deseamos tener una trayectoria calculada de la
7.3. METODOS ADAPTATIVOS 211
paso grande
x b(t+ )
x (t)
x (t+/2) x s (t+ )
paso pequeo paso pequeo
La diferencia entre las dos respuestas, ~xb (t+ ) y ~xs (t+ ), estima el error de truncamiento
local. Si el error es tolerable, el valor calculado es aceptado y un valor mayor de es usado
en la proxima iteracion. Por otra parte, si el error es muy grande, la respuesta es rebotada, el
paso de tiempo es reducido y el procedimiento es repetido hasta que se obtenga una respuesta
aceptable. El error de truncamiento estimado para el actual paso de tiempo puede guiarnos
en seleccionar en nuevo paso de tiempo para la proxima iteracion.
7.3.2. Funci
on adaptativa de Runge-Kutta.
Aqu mostramos como una iteracion adaptativa puede ser implementada para un esquema
de Runge-Kutta de cuarto orden: llamemos al error de truncamiento; sabemos que 5
para un esquema Runge-Kutta de cuarto orden. Supongamos que el paso de tiempo actual
ant da un error de c = | ~xb ~xs |; esta es nuestra estimacion para el error de truncamiento.
Dado que deseamos que el error sea menor o igual que el error ideal especificado por el
usuario, le llamamos i ; luego, el nuevo paso de tiempo estimado es
i 1/5
est =
. (7.32)
c
Ya que esto es solo una estimacion, el nuevo paso de tiempo es nuevo = S1 est , donde S1 < 1.
Esto nos hace sobreestimar el cambio cuando disminuimos y subestimar el cambio cuan-
do lo aumentamos. Malogramos los esfuerzos computacionales cada vez que rebotamos una
respuesta y necesitamos reducir el paso de tiempo, por lo tanto es mejor ajustar nuevo < est .
Podramos poner un segundo factor de seguridad, S2 < 1, para asegurarse que el programa
no sea demasiado entusiasta en aumentar o disminuir precipitadamente el paso de tiempo.
Con ambas precauciones, el nuevo paso de tiempo es
S2 ant
si S1 est > S2 ant
nuevo = /S2 si S1 est < ant /S2 . (7.33)
S1 est en otro caso
212 CAPITULO 7. EDO II: METODOS
AVANZADOS.
Iterar sobre el n
umero deseado de intentos para satisfacer el error lmite.
Esto obliga a asegurar que nuestro nueva estimacion para nunca aumente o decrezca
por mas que un factor S2 . Por supuesto, este nuevo podra ser insuficientemente peque
no,
y tendramos que continuar reduciendo el paso de tiempo; pero al menos sabramos que no
ocurrira de un modo incontrolado.
Este procedimiento no es a prueba de balas, los errores de redondeo llegan a ser signi-
ficativos en pasos de tiempos muy peque nos. Por esta razon la iteracion adaptativa podra
fallar para encontrar un paso de tiempo que de la precision deseada. Debemos mantener esta
limitacion en mente cuando especifiquemos el error aceptable. Una funcion de Runge-Kutta
adaptativa, llamada rka, es esbozada en la tabla 7.5. Note que los datos de entrada en la
secuencia de llamada son los mismos que para rk4, excepto por la suma de i , el error ideal
especificado. Las salidas del rka son el nuevo estado del sistema, ~x(t0 ); el tiempo nuevo, t0 y
el nuevo paso de tiempo, nuevo, el cual podra ser usado la proxima vez que sea llamada
la rka.
Usando el metodo de Runge-Kutta adaptativo, el programa orbita da los resultados en
la figura 7.7 para una orbita altamente elptica. Notemos que el programa toma muchos mas
pasos en el perihelio que en el afelio. Podemos comparar con los resultados usando el metodo
de Runge-Kutta no adaptativo (figura 7.6) en el cual los pasos en el perihelio son ampliamente
espaciados. Una grafica de los pasos de tiempo versus la distancia radial (figura 7.8) muestra
que vara casi tres ordenes de magnitud.Interesantemente esta grafica revela una relacion
exponencial aproximada de la forma r3 . Por supuesto esta dependencia nos recuerda
la tercera ley de Kepler, ecuacion (7.10). Esperamos alguna dispersion en los puntos, ya que
nuestra rutina adaptada solamente estima el paso de tiempo optimo.
7.4. LISTADOS DEL PROGRAMA. 213
90 o 1500
Energa [M AU*AU/aos*aos]
Energa Cintica
Energa Potencial
Energa Total
1000
500
o 0o 0
180
500
1000
1500
o 0 0.05 0.1 0.15 0.2 0.25
270
1 0.5 0 0.5 1
Figura 7.7: Grafico de la trayectoria y la energa desde el programa orbita usando el metodo
de Runge-Kutta adaptativo. La distancia radial inicial es 1 [AU] y la velocidad tangencial
inicial es /2 [AU/a no]. El paso inicial en el tiempo es = 0.1 [a nos]; y 40 pasos son
calculados.
0.1
0.01
Tau [aos]
0.001
0.0001
0.01 0.1 1
Distancia [Au]
Figura 7.8: Paso de tiempo como funcion de la distancia radial desde el programa orbita
usando el metodo de Runge-Kutta adaptativo. Los parametros son los mismos de la figura
7.7.
// Evaluemos F1=f(x,t)
(*derivsRK) (x, t, param, F1) ;
// Retornamos x(t+tau)
void rka ( double * x, int nX, double & t, double & tau, double erro,
void(*derivsRK)(double *, double, double, double *),
double param)
{
7.4. LISTADOS DEL PROGRAMA. 215
double tSave = t ;
double safe1 = 0.9, safe2 = 4.0 ; //factores de seguridad
double gm=param ;
double rX=x[0], rY=x[1];
double vX=x[2], vY=x[3] ;
double mod_r= sqrt(rX*rX+rY*rY) ;
double aX= -gm*rX/(mod_r*mod_r*mod_r) ;
double aY= -gm*rY/(mod_r*mod_r*mod_r) ;
// Retorna la derivada
deriv[0] = vX;
deriv[1] = vY;
deriv[2] = aX;
deriv[3] = aY;
}
int main()
{
ofstream salidaO ("Orbita.txt") ;
ofstream salidaE ("Energia.txt") ;
ofstream salidaT ("Tau.txt") ;
double r0 ;
cout << "Ingrese la distancia radial inicial [AU]: " ;
cin >> r0 ;
double vT ;
cout << "Ingrese la velocidad tangencial inicial [AU/a{\~n}os]: " ;
cin >> vT ;
double x0=r0 ;
double y0=0.0e0;
double vx0=0.0e0 ;
double vy0=vT;
//
// Suponemos angulo inicial nulo
//
int metodo = 0 ;
while( metodo < 1|| metodo > 4 ) {
cout << "Ingrese el m{\e}todo num{\e}rico a usar :" << endl ;
cout << "\t Metodo de Euler \t\t\t[1]" << endl;
cout << "\t Metodo de Euler-Cromer \t\t[2]" << endl;
cout << "\t Metodo de Runge-Kutta 4 orden \t\t[3]" << endl;
cout << "\t Metodo de Runge-Kutta adaptativo \t[4]" << endl;
cout << "elija: " ;
cin >> metodo ;
}
double tau ;
7.4. LISTADOS DEL PROGRAMA. 217
double param=GM ;
const int dimX= 4;
double * x = new double[dimX] ;
double Ep = -GM*masaCometa/r ;
double Ek = masaCometa*v2/2.0e0 ;
double ET= Ep+Ek ;
salidaE<< tiempo << " " << Ek<< " " << Ep<<" " << ET << endl ;
f~(~x ) = 0 , (8.2)
o
fi (x1 , x2 , . . . , xN ) = 0 , para todo i, (8.3)
1
Este captulo est
a basado en el cuarto captulo del libro: Numerical Methods for Physics, second edition
de Alejandro L. Garcia, editorial Prentice Hall.
2
R. Seydel, From Equilibrium to Chaos, Practical Bifurcation and Stability Analysis (New York: Elsevier,
1988).
219
220 CAPITULO 8. RESOLVIENDO SISTEMAS DE ECUACIONES.
ya que esto implica que d~x /dt = 0. Localizar los estados estacionarios se reduce al problema
de resolver N ecuaciones con N incognitas xi . Este problema es tambien llamado encontrar
las raices de f (x).
Como un ejemplo, consideremos el pendulo simple; el estado esta descrito por el angulo
y la velocidad angular . Los estados estacionarios se encuentran al resolver las ecuaciones
no lineales
g
sen = 0 , = 0 . (8.4)
L
Las raices son = 0, , 2, . . . y = 0. Por supuesto que no todos los sistemas son tan
faciles de resolver.
Debera ser claro que encontrar raices tiene muchas mas aplicaciones que calcular los
estados estacionario. En este captulo consideraremos una variedad de maneras para resolver
ambos sistemas lineales y sistemas no lineales. En esta seccion y en la proxima consideraremos
sistemas lineales, dejando los sistemas no lineales para la parte final del captulo.
8.1.2. Eliminaci
on Gaussiana.
El problema de resolver fi ({xj }) = 0 se divide en dos importantes clases. En esta seccion
consideramos el caso facil cuando fi ({xj }) es una funcion lineal. El problema en ese caso se
reduce a resolver un sistema de N ecuaciones con N incognitas.
a11 x1 + a12 x2 + . . . + a1N xN b1 = 0
a21 x1 + a22 x2 + . . . + a2N xN b2 = 0
.. .. .. .. (8.5)
. . . .
aN 1 x 1 + aN 2 x 2 + . . . + aN N x N b N = 0 ,
o en forma matricial
A ~x ~b = 0 , (8.6)
donde
a11 a12 . . . x1 b1
A = a21 a22 . . . ,
x2
~x = , ~b = b2
. (8.7)
.. .. . . .. ..
. . . . .
Sabemos como resolver este conjunto de ecuaciones. Combinando las ecuaciones para
eliminar variables hasta que tengamos una sola ecuacion con una sola incognita. Hagamos
un ejemplo simple para revisar como el procedimiento trabaja. Tomemos las ecuaciones
x1 + x2 + x3 = 6 ,
x1 + 2x2 = 3, (8.8)
2x1 + x3 = 5 .
Deseamos eliminar x1 de la segunda y de la tercera ecuacion. Para llevar a cabo esto, primero
sumamos la primera y la segunda y despues restamos dos veces la primera a la tercera. Esto
nos da
x1 + x2 + x3 = 6,
3x2 + x3 = 9, (8.9)
2x2 x3 = 7 .
8.1. SISTEMAS DE ECUACIONES LINEALES. 221
x1 + x2 + x3 = 6,
3x2 + x3 = 9, (8.10)
13 x3 = 1 .
8.1.3. Pivoteando.
La eliminacion Gaussiana es un procedimiento simple, sin embargo, se debe estar conciente
de sus riesgos. Para ilustrar la primera fuente de problemas, consideremos el conjunto de
ecuaciones
x1 + x2 + x3 = 5 ,
x1 + x2 = 3, (8.11)
x1 + x3 = 4 .
En el lmite 0 la solucion es x1 = 1, x2 = 2, x3 = 3. Para estas ecuaciones, el primer
paso de la eliminacion hacia adelante podra partir por multiplicar la primera ecuacion por
(1/) y sustrayendola de la segunda y tercera ecuaciones, lo que da
x1 + x2 + x3 = 5,
(1 1/)x2 (1/)x3 = 3 5/ , (8.12)
(1/)x2 + (1 1/)x3 = 4 5/ .
un si 6= 0,
Por supuesto, si = 0 tenemos grandes problemas, ya que el factor 1/ estalla. A
pero es peque
no, vamos a tener serios problemas de redondeo. Supongamos que 1/ es tan
3
G.E. Forsythe and C.B. Moler, Computer Solution of Linear Algebraic System (Upper Saddle River, N.J.:
Prentice-Hall, 1967).
4
sparse
222 CAPITULO 8. RESOLVIENDO SISTEMAS DE ECUACIONES.
grande que (C 1/) 1/, donde C es del orden de la unidad. Nuestras ecuaciones,
despues del redondeo, llegan a ser
x1 + x2 + x3 = 5,
(1/)x2 (1/)x3 = 5/ , (8.13)
(1/)x2 (1/)x3 = 5/ .
En este punto esta claro que no podemos proceder ya que la segunda y la tercera ecuacion en
(8.13) son ahora identicas; no tenemos mas que tres ecuaciones independientes. El proximo
paso de eliminacion sera transformar la tercera ecuacion en (4.13) en la tautologa 0 = 0.
Afortunadamente, hay una solucion simple: intercambiar el orden de las ecuaciones antes
de realizar la eliminacion. Cambiando las ecuaciones primera y segunda en (8.11),
x1 + x2 = 3,
x1 + x2 + x3 = 5 , (8.14)
x1 + x3 = 4 .
x1 + x2 = 3,
(1 )x2 + x3 = 5 3 , (8.15)
x2 + x3 = 4 3 .
x1 + x2 = 3,
x2 + x3 = 5 , (8.16)
x2 + x3 = 1 .
x1 + x2 = 3,
x2 + x3 = 5 , (8.17)
2x3 = 6 .
8.1.4. Determinantes.
Es facil obtener el determinante de una matriz usando la eliminacion Gaussiana. Despues
de completar la eliminacion hacia adelante, uno simplemente calcula el producto de los coe-
ficientes de los elementos diagonales. Tomamos nuestro ejemplo original, ecuacion (8.8). La
matriz es
1 1 1
A = 1 2 0 . (8.18)
2 0 1
Completada la eliminacion hacia adelante, ecuacion (8.10), el producto de los coeficientes de
los elementos diagonales es (1)(3)( 13 ) = 1, el cual, usted puede comprobar, es el determi-
Este metodo es sutlmente mas complicado cuando se usa el pivoteo. Si el n
nante de A. umero
de pivoteos es impar, el determinante es el producto negativo de los coeficientes de los elemen-
tos de la diagonal. Ahora debera ser obvio que la regla de Cramer es computacionalmente
una manera ineficiente para resolver el conjunto de ecuaciones lineales.
8.1.5. Eliminaci
on Gaussiana en Octave.
No necesitamos escribir un programa en Octave para realizar la eliminacion Gaussiana
con pivoteo. En vez de esto nosotros podemos usar las capacidades de manipulacion de
matrices que viene con Octave. En Octave, la eliminacion Gaussiana es una rutina primitiva,
tal como las funciones seno o raz cuadrada. Como con cualquier rutina enlatada, usted
debera entender, en general, como trabaja y reconocer posibles problemas, especialmente los
computacionales (e.g., poner sqrt(-1) retorna un n umero imaginario o un error?).
Octave implementa la eliminacion de Gauss usando los operadores slash / y backslash \.
El sistema de ecuaciones lineales ~x A = ~b donde ~x y ~b son vectores fila, se resuelve usando
el operador slash como ~x = ~b/A. El sistema de ecuaciones lineales A ~x = ~b donde ~x y ~b son
vectores columna, se resuelve usando el operador backslash como ~x = ~b\A. Como un ejemplo,
tomemos la ecuacion (8.11) con = 0, escrito en forma matricial
0 1 1 x1 5
1 1 0 x2 = 3 (8.19)
1 0 1 x3 4
int M, N
. . . // Se fijan valores a M y N
double * * A = new double * [M] ; // asignacion de un vector de punteros
for(int i=0;i<M;i++) {
A[i] = new double [N] ; // asignacion de memoria para cada fila
}
para un reserva dinamica (no olvide desasignar cada fila con un delete[]). Una asignacion
estatica es simple pero rgida, ya que las dimensiones son constantes fijas. Cuando el arreglo
estatico es pasado a una funcion, esta funcion debera declarar alg un arreglo con el mismo
numero de columnas de acuerdo al arreglo a ser indexado apropiadamente. Una asignacion
dinamica es flexible pero es difcil de manejar, aunque los detalles pueden ser escondidos
dentro de funciones separadas. Accesar elementos fuera de los contornos del arreglo es un
error de programacion com un (bug) el cual es difcil de rastrear con arreglos dinamicos.
C++ nos permite corregir estas deficiencias creando nuestros propios tipos de variables.
Estas variables definidas por el usuario son llamadas clases de objetos. De aqu en adelante
usaremos la clase Matrix para declarar arreglos de una o dos dimensiones de n umeros de punto
flotante. Esta clase esta enteramente declarada dentro del archivo de cabecera Matrix.h e
implementada dentro de Matrix.cc. Algunos ejemplos de declaracion de objetos de Matrix
son
Aunque esto se parece a una asignacion de arreglo estatico, note que las dimensiones no son
constantes fijas. Tanto vectores unidimensionales como matrices bidimensionales pueden ser
declarados; las anteriores son tratadas como matrices de una sola columna. Los valores en
estas variables pueden ser fijados por la declaracion de asignamiento
El formato para el objeto Matrix es A(i, j) en vez de A[i][j], para distinguirlos de los arreglos
C++ convencionales.
Un objeto Matrix conoce sus dimensiones, y usted puede obtenerlas usando las funciones
miembros nRow() y nCol(). Por ejemplo:
8.1. SISTEMAS DE ECUACIONES LINEALES. 225
~b.
Entradas: A,
Salidas: ~x, det A.
Cuadro 8.1: Bosquejo de la funcion ge, la cual resuelve un sistema de ecuaciones lineales
A ~x = ~b por eliminacion Gaussiana. La funcion tambien devuelve el determinante de A.
A ~x = ~b , (8.20)
como
~x = A1 ~b , (8.21)
donde A1 es la matriz inversa de A. No nos debera sorprender que el calculo de la matriz
inversa este relacionada al algoritmo para resolver un conjunto de ecuaciones lineales. Usual-
mente la inversa de una matriz es calculada por aplicaciones repetidas de eliminaciones de
Gauss (o una variante de descomposicion llamada LU).
La inversa de una matriz esta definida por la ecuacion
A A1 = I , (8.22)
podramos escribir la matriz identidad como una vector fila de los vectores columna
I = e1 e2 . . . eN .
(8.25)
A ~x1 = e1 . (8.26)
A x1 x2 . . . xN = e1 e2 . . . eN .
(8.27)
8.2. MATRIZ INVERSA. 227
Entradas: A.
Salidas: A1 , det A.
Cuadro 8.2: Bosquejo de la funcion inv, la cual calcula el inverso de una matriz y su deter-
minante.
(~x1 )1 (~x2 )1 . . . (~xN )1
(~x1 )2 (~x2 )2 . . . (~xN )2
A1
x1 x2 . . . xN = .. (8.28)
.. ... ..
. . .
(~x1 )N (~x2 )N . . . (~xN )N
1 1 a22 a12
A = . (8.29)
a11 a22 a12 a21 a21 a11
Para matrices mayores las formulas rapidamente llegan a ser muy desordenadas.
228 CAPITULO 8. RESOLVIENDO SISTEMAS DE ECUACIONES.
Note que realmente no tenemos dos ecuaciones independientes, ya que la segunda es solo el
doble de la primera. Estas ecuaciones no tienen una solucion u
nica. Si tratamos de hacer una
eliminacion hacia adelante, obtenemos
x1 + x2 = 1
, (8.31)
0 = 0
no tiene inversa. Una matriz sin inversa se dice que es singular. Una matriz singular tam-
bien tiene un determinante nulo. Las matrices singulares no siempre son evidentes. Podra
adivinar si esta matriz
1 2 3
4 5 6
7 8 9
es singular?
Aqu esta lo que pasa en Octave cuando tratamos de resolver (8.30)
donde es un n umero muy peque no. A una matriz se le dice patol ogica cuando esta muy
cerca de ser singular.
Si usted sospecha que esta tratrando con ~
una matriz patologica cuando resuelve A~x = b,
entonces calcule el error absoluto, A~x ~b / ~b para comprobar si ~x es una solucion precisa.
8.2. MATRIZ INVERSA. 229
x2
x1
Figura 8.1: Sistema de bloques acoplados por resortes anclados entre paredes.
Despreciamos el termino O(x2 ) (este sera nuestro error de truncamiento) y usamos la ex-
presion resultante de x para corregir nuestra estimacion inicial. La nueva estimacion es
f (x1 )
x2 = x1 x = x1 . (8.40)
f 0 (x1 )
Este procedimiento podra ser iterado como
f (xn )
xn+1 = xn , (8.41)
f 0 (xn )
para mejorar nuestra estimacion hasta obtener la precision deseada.
El procedimiento iterativo descrito mas arriba puede entenderse mejor graficamente (fi-
gura 8.2). Note que en cada paso usamos la derivada de f (x) para dibujar la lnea tangente a
7
F.S. Acton, Numerical Methods that Work (New York: Harper&Row, 1970).
8.3. SISTEMAS DE ECUACIONES NO LINEALES. 231
f(x)
x2 x* x
x1 x3
la funcion. Donde esta lnea tangente intersecta el eje x es nuestra siguiente estimacion de la
raz. Efectivamente, estamos linealizando f (x) y resolviendo el problema lineal. Si la funcion
es bien comportada, pronto sera aproximadamente lineal en alguna vecindad cerca de la raz
x .
Unas pocas notas acerca del metodo de Newton: primero, cuando converge, encuentra una
raz muy rapidamente; pero, desafortunadamente, algunas veces diverge (e.g., f 0 (xn ) 0) y
falla. Para funciones bien comportadas, este metodo es garantizado que converger si estamos
suficientemente cerca de la raz. Por esta razon algunas veces esta combinada con un algoritmo
mas lento pero que asegura encontrar la raz, tal como la biseccion. Segundo, si hay varias
raices, la raz a la cual el metodo converge depende de la estimacion inicial (que podra no
ser la raz deseada). Hay procedimientos (e.g., deflation) para encontrar m ultiples raices
usando el metodo de Newton. Finalmente, el metodo es mas lento cuando se encuentran
raices tangentes, tales como para f (x) = x2 .
8.3.2. M
etodo de Newton multivariable.
No es difcil generalizar el metodo de Newton a problemas de N variables. Ahora nuestra
incognita ~x = [x1 , x2 , . . . , xN ] es un vector fila, y deseamos encontrar los ceros (raices) de
la funcion vector fila
f~(~x) = [f1 (~x) , f2 (~x) , . . . , fN (~x)] . (8.42)
De nuevo, hacemos una estimacion inicial para ubicar la raz, llamamos a esta estimacion ~x1 .
Nuestro error podra ser esrito como ~x = ~x1 ~x o ~x = ~x1 ~x. Usando la expansion de
Taylor de f~(~x1 ),
fj (~x)
Dij (~x) = . (8.44)
xi
232 CAPITULO 8. RESOLVIENDO SISTEMAS DE ECUACIONES.
Ya que ~x es la raz, f~(~x ) = 0, como antes podramos resolverla para ~x. Despreciando el
termino de error, podemos escribir la ecuacion (8.43) como
f~(~x1 ) = ~x D(~
x1 ) , (8.45)
o
~x = f~(~x1 ) D
1 (~x1 ) . (8.46)
Nuestra nueva estimacion es
Este procedimiento puede ser iterado para mejorar nuestra estimacion hasta que sea obtenida
la precision deseada. Ya que D cambia en cada iteracion, podra ser desgastador calcular su
inversa. En cambio, usamos la eliminacion Gaussiana sobre la ecuacion (8.45) para resolver
para ~x, y calcular la nueva estimacion como ~x2 = ~x1 ~x.
Itera sobre el n
umero de pasos deseados.
Cuadro 8.3: Descripcion del programa newtn, el cual encuentra una raz para un conjunto de
ecuaciones.
Para r = 28,
= 10 y b = 8/3, las tres races son [x, y, z] = [0, 0, 0], [6 2, 6 2, 27] y
[6 2, 6 2, 27].
Unejemplo
de la salida de newtn esta dada mas abajo; note que el programa obtiene la
raz [6 2, 6 2, 27].
octave:1> newtn
newtn is the file: ~/cursos/MFM1.apuntes2/programas/newtn.m
8.3.4. Continuaci
on.
La primera dificultad con el metodo de Newton es la necesidad de dar una buena estima-
cion inicial para la raz. A menudo nuestro problema es de la forma
f~(~x ; ) = 0 , (8.50)
donde es algun parametro en el problema. Supongamos que conocemos una raz ~x0 para el
valor 0 pero necesitamos encontrar una raz para un valor diferente de a . Intuitivamente,
si a 0 , entonces ~x0 debera ser una buena estimacion inicial para encontrar ~xa usando
234 CAPITULO 8. RESOLVIENDO SISTEMAS DE ECUACIONES.
Salidas: f~, D.
Cuadro 8.4: Descripcion de la funcion fnewt, la cual es usada por newtn para encontrar los
estados estables de la ecuacion de Lorenz.
el metodo de Newton. Pero si a 6 0 , hay alguna manera para hacer uso de nuestra raz
conocida?
La respuesta es s y la tecnica es conocida como continuaci
on. La idea es acercarse poco
a poco a a definiendo la siguiente secuencia de :
i
i = 0 + (a 0 ) , (8.51)
N
para i = 1, . . . . . . ., N . Usando el metodo de Newton, resolvemos f (~x1 ; 1 ) = 0 con ~x0
como la estimacion inicial. Si N es suficientemente grande, entonces 1 0 y el metodo
podra converger rapidamente. Luego usamos ~x1 como una estimacion inicial para resolver
f (~x2 ; 2 ) = 0; la secuencia contin
ua hasta alcanzar nuestro valor deseado en a . La tecnica
de continuacion tiene un beneficio adicional que podemos usar cuando estamos interesados
en conocer no solo una raz simple, sino conocer como ~x vara con .
8.4. LISTADOS DEL PROGRAMA. 235
8.4.1. Definici
on de la clase Matrix.
//
// Clase de Matrices doubles
//
#ifndef _Matrix_h
#define _Matrix_h
#include <iostream>
#include <string>
class Matrix {
private:
int nFilP ;
int nColP ;
int dimP ;
double * dataP ;
void copy(const Matrix &) ;
public:
Matrix() ;
Matrix( int, int = 1, double = 0.0e0) ;
Matrix( const Matrix &) ;
~Matrix() ;
Matrix & operator = (const Matrix &) ;
double & operator () (int, int =0) ;
int nRow () const;
int nCol () const ;
void set(double) ;
double maximoF(int) const ;
void pivot(int,int) ;
void multi(double, int, int ) ;
};
#endif
236 CAPITULO 8. RESOLVIENDO SISTEMAS DE ECUACIONES.
8.4.2. Implementaci
on de la clase Matrix.
//
// Implementacion de la clase Matrix
#include "Matrix.h"
#include <cassert>
#include <cstdlib>
// Constructor de copia
Matrix::Matrix( const Matrix & mat) {
this->copy(mat) ;
// this permite acceder a la misma vartiable como un todo
// *this representa la variable, y this un puntero a ella
// -> nos permite elegir miembros de la clase pero cuando tenemos el puntero
// a la variable y no su valor
}
// Destructor
8.4. LISTADOS DEL PROGRAMA. 237
Matrix::~Matrix() {
delete [] dataP ; // Libera la memoria
}
// operador Parentesis
// Permite accesar los valores de una matriz via el par (i,j)
// Ejemplo a(1,1)=2*b(2,3)
// Si no se especifica la columna la toma igual a 0
double & Matrix::operator() (int indF, int indC) {
error(indF>-1 && indF< nFilP, "Indice de fila fuera de los limites") ;
error(indC>-1 && indC<nColP, "Indice de columna fuera de los limites" ) ;
return dataP[indC+nColP*indF] ;
}
if(indF1==indF2) return ;
double paso ;
int ind1, ind2 ;
for (int i = 0; i < nColP; i++ ) {
ind1 = nColP*indF1+i ;
ind2 = nColP*indF2+i ;
paso = dataP[ind1] ;
dataP[ind1] = dataP[ind2] ;
dataP[ind2] = paso ;
}
}
//
// IOSTREAM <<
//
ostream & operator << (ostream & os, Matrix mat ) {
for(int indF=0; indF < mat.nRow(); indF++) {
os << "| " ;
for(int indC=0; indC<mat.nCol(); indC++) {
os << mat(indF,indC) << " ";
}
os << "|"<<endl ;
}
return os ;
}
8.4.3. Funci
on de eliminaci
on Gaussiana ge.
//
// Eliminacion Gaussiana.
//
#include "NumMeth.h"
#include "Matrix.h"
return determinante*determ ;
}
8.4.4. Funci
on para inversi
on de matrices inv.
//
// Invierte una matriz
//
#include "NumMeth.h"
#include "Matrix.h"
nStep =10;
242 CAPITULO 8. RESOLVIENDO SISTEMAS DE ECUACIONES.
for iStep=1:nStep
[f D] = fnewt(x,a) ;
dx=D\f ;
x=x-dx;
end
fprintf(Despues de %g iteraciones la raiz es \n, nStep);
disp(x);
Funci
on fnewt en Octave.
function [f,D] = fnewt(x,a)
f(1)=a(2)*(x(2)-x(1));
f(2)= a(1)*x(1)-x(2)-x(1)*x(3);
f(3)=x(1)*x(2)-a(3)*x(3) ;
D(1,1)=-a(2);
D(2,1)=a(1)-x(3);
D(3,1)=x(2);
D(1,2)=a(2);
D(2,2)=-1;
D(3,2)=x(1);
D(1,3)=0;
D(2,3)=-x(1);
D(3,3)=-a(3);
return
8.4. LISTADOS DEL PROGRAMA. 243
#include <iostream>
#include "NumMeth.h"
#include "Matrix.h"
void fnewt( Matrix & f, Matrix & D, Matrix xN, Matrix lambda )
{
double r= lambda(0) ;
double s= lambda(1) ;
double b=lambda(2) ;
double x=xN(0) ;
double y=xN(1) ;
double z=xN(2) ;
f(0) = s*(y-x) ;
f(1) = r*x-y-x*z ;
f(2) = x*y-b*z ;
D(0,0) = -s ;
D(1,0) = r-z ;
D(2,0) = y ;
D(0,1) = s ;
D(1,1)= -1.0e0 ;
D(2,1) = x ;
D(0,2)=0.0e0 ;
D(1,2)= -x ;
D(2,2) =-b ;
}
}
if(indicePivot != indC) {
A.pivot(indC, indicePivot) ;
b.pivot(indC, indicePivot) ;
determinante *= -1.0e0 ;
}
double Ad= A(indC,indC) ;
for (int indF=indC+1; indF< nFil; indF++ ) {
double factor = - A(indF, indC)/Ad ;
A.multi(factor, indC, indF);
b.multi(factor, indC, indF);
}
}
for (int indF= nFil-1; indF >=0; indF--) {
double sum =0.0e0 ;
for (int i = indF+1; i < nCol; i++) sum += A(indF, i)*x(i) ;
x(indF) = b(indF)/A(indF, indF) - sum /A(indF, indF);
}
double determ = 1.0e0 ;
for (int i = 0; i < nCol; i++) determ *= A(i,i) ;
return determinante*determ ;
}
int main()
{
Matrix D(3,3) ;
Matrix f(3) ;
Matrix lambda(3), xN(3), xNp1(3), dx(3) ;
int iteraciones ;
cout << "Ingrese numero de iteraciones : " ;
cin >> iteraciones ;
ge(D, f, dx) ;
xNp1=xN-dx ;
xN=xNp1 ;
cout << xN(0)<< " " << xN(1) << " " << xN(2) << endl ;
}
cout << xN <<endl ;
return 0;
}
246 CAPITULO 8. RESOLVIENDO SISTEMAS DE ECUACIONES.
Captulo 9
An
alisis de datos.
on 3.0, 02 de Diciembre 20031
versi
A menudo se destaca que los sistemas fsicos simulados sobre un computador son similares
al trabajo experimental. La razon de esta analoga es hecha ya que la simulacion computacio-
nal produce datos en muchas maneras similares a los experimentos de laboratorio. Sabemos
que en el trabajo experimental uno a menudo necesita analizar los resultados y esto es lo
mismo que con la simulacion numerica. Este captulo cubre parcialmente algunos topicos en
el analisis de datos.
247
248 CAPITULO 9. ANALISIS
DE DATOS.
355
350
CO2 (ppm)
345
340
335
1982 1984 1986 1988 1990
Ao
Figura 9.1: Dioxido de carbono (en partes por millon) medida en Mauna Loa, Hawai desde
1981 a 1990. Barra de error estimada es 0 = 0.16 [p.p.m.] .
Nuestro criterio de ajuste para la curva sera que la suma de los cuadrados de los errores
sea un mnimo; esto es, necesitamos encontrar {aj } que minimice la funcion
N
X N
X
D({aj }) = 2i = [Y (xi ; {aj}) yi ]2 . (9.2)
i=1 i=1
9.1. AJUSTE DE CURVAS. 249
i Y(x;{aj })
yi
i
xi
Figura 9.2: Ajuste de datos a una curva.
9.1.3. Regresi
on lineal.
Primero consideremos ajustar el conjunto de datos con una lnea recta,
Este tipo de ajuste de curva es tambien conocido como regresion lineal. Deseamos determinar
a1 y a2 tal que
N
X 1
2 (a1 , a2 ) = 2
(a1 + a2 xi yi )2 , (9.5)
i=1
i
a1 S + a2 x y = 0 (9.8)
a1 x + a2 x2 xy = 0 , (9.9)
donde
N N N
X 1 X xi X yi
S , x , y ,
2
i=1 i
2
i=1 i
2
i=1 i
N N N
(9.10)
X x2 i
X yi2 X xi yi
x2 , 2
y , xy .
i=1
i2 2
i=1 i i=1
i2
Puesto que las sumas pueden ser calculadas directamente de los datos, ellas son constantes
conocidas. De este modo tenemos un conjunto lineal de dos ecuaciones simultaneas en las
incognitas a1 y a2 . Estas ecuaciones son faciles de resolver:
Note que si i es una constante, esto es, si el error es el mismo para todos los datos, los se
cancelan en las ecuaciones (9.11). En este caso, los parametros, a1 y a2 , son independientes de
la barra de error. Es com
un que un conjunto de datos no incluya las barras de error asociadas.
Todava podramos usar las ecuaciones (9.11) para ajustar los datos si tenemos que los i
son constantes (i =1 siendo la eleccion mas simple).
Lo siguiente es obtener una barra de error asociado, aj , para el parametro aj de la curva
de ajuste. Usando la ley de la propagacion de errores,3
N
X aj
a2j = i2 , (9.12)
i=1
yi
3
P. Bevington, Data Reduction an Error Analysis for the Physical Sciences 2d ed. (New York: McGraw-
Hill, 1992).
9.1. AJUSTE DE CURVAS. 251
Note que aj es independiente de yi . Si las barras de error de los datos son constantes
(i = 0 ), el error en los parametros es
s s
0 hx2 i 0 1
a1 = , a2 = , (9.14)
N hx2 i hxi2 N hx2 i hxi2
donde
N N
1 X 2 1 X 2
hxi = xi , hx i = x . (9.15)
N i=1 N i=1 i
N
1 X
02 s2 = [yi (a1 + a2 xi )]2 , (9.16)
N 2 i=1
donde s es la desviacion estandar de la muestra. Note que esta varianza muestral esta nor-
malizada por N 2, puesto que hemos extrado dos parametros a1 y a2 , de los datos.
Muchos problemas de ajuste de curva no lineales, pueden ser transformados en problemas
lineales por un simple cambio de variable. Por ejemplo,
Z(x; {, }) = ex , (9.17)
podra ser reescrita como las ecuaciones (9.4) usando el cambio de variable
ln Z = Y , ln = a1 , = a2 . (9.18)
Z(t; {, }) = t , (9.19)
ln Z = Y , ln t = x , ln = a1 , = a2 . (9.20)
Estas transformaciones deberan ser familiares debido a que se usan para graficar datos en
escala semi logartmica o escalas log-log.
252 CAPITULO 9. ANALISIS
DE DATOS.
Para encontrar los optimos parametros procedemos como antes encontrando el mnimo de
2 ,
N
(M )2
2
X 1 X
= ak Yk (x) yi =0, (9.22)
aj aj i=1 i2 k=1
o (M )
N
X 1 X
Yj (xi ) ak Yk (x) yi = 0 , (9.23)
2
i=1 i k=1
por lo tanto
N X
M N
X Yj (xi )Yk (xi ) X Yj (xi )yi
ak = , (9.24)
i=1 k=1
i2 i=1
i2
para j = 1, . . . , M . Este conjunto de ecuaciones es conocida como las ecuaciones normales
del problema de los mnimos cuadrados.
Las ecuaciones normales son mas faciles de trabajar en forma matricial. Primero, defina-
mos la matriz de dise como
no A,
Y1 (xi )/1 Y2 (xi )/1 . . .
Yj (xi )
A = Y1 (xi )/2 Y2 (xi )/2 . . . , Aij = . (9.25)
.. .. .. i
. . .
Note que la matriz de dise no no depende de yi , los valores de datos, pero depende de xi , esto
es, sobre el dise
no del experimento (donde las mediciones son tomadas). Usando la matriz de
diseno, podemos escribir (9.24) como
N X
M N
X X yi
Aij Aik ak = Aij , (9.26)
i=1 k=1 i=1
i2
o en forma matricial,
a = AT~b ,
(AT A)~ (9.27)
donde el vector ~b esta definido como bi = yi /i y AT es la traspuesta de la matriz de dise
no.
Esta ecuacion es facil de resolver para el parametro vector ~a,
1 AT~b .
~a = (AT A) (9.28)
donde C = (AT A)
1 .
Una aplicacion comun de esta formulacion general lineal de ajuste de mnimos cuadrados
es el ajuste de los datos polinomiales,
| yi Y (xi ) | i . (9.31)
Integraci
on num
erica b
asica
versi
on 3.0, 04 de Diciembre del 2003
En este captulo veremos algunos metodos basicos para realizar cuadraturas (evaluar
integrales numericamente).
10.1. Definiciones
Consideremos la integral
Z b
I= f (x) dx . (10.1)
a
Nuestra estrategia para estimar I es evaluar f (x) en unos cuantos puntos, y ajustar una curva
simple a traves de estos puntos. Primero, subdividamos el intervalo [a, b] en N subintervalos.
Definamos los puntos xi como
f(x)
x0=a x1 x2 xi xN=b
Figura 10.1: Subintervalos.
255
256 CAPITULO 10. INTEGRACION
NUMERICA
BASICA
fi
f(x)
fi+1
Ti
xi xi+1 x
1
Ti = (xi+1 xi )(fi+1 + fi ) .
2
I ' IT = T0 + T1 + + TN 1 .
Las expresiones son mas simples si tomamos puntos equidistantes. En este caso el espa-
ciado entre cada par de puntos es
ba
h= ,
N
de modo que xi = a + ih. El area de un trapezoide es entonces
1
Ti = h(fi+1 + fi ) ,
2
1 1
IT (h) = hf0 + hf1 + hf2 + + hfN 1 + hfN
2 2
N 1
1 X
= h(f0 + fN ) + h fi (10.2)
2 i=1
CON DATOS EQUIDISTANTES.
10.3. INTERPOLACION 257
10.3. Interpolaci
on con datos equidistantes.
Para el caso de puntos xi = a + ih que estan igualmente espaciados podemos plantear
un formalismo mas general. Primero que todo, ajustemos un polinomio de grado N a un
conjunto de N + 1 datos xi , fi , no necesariamente equidistantes, de la forma:
PN (x) = b0 + b1 (x x0 ) + + bN (x x0 )(x x1 ) (x xN 1 ) . (10.3)
Determinemos los coeficientes usando los datos:
b0 = f0 = f (x0 )
f1 f0
b1 = f [x1 , x0 ]
x1 x0
f2 f1 f1 f0 f [x2 , x1 ] f [x1 , x0 ]
b2 = /(x2 x0 ) = f [x2 , x1 , x0 ]
x2 x1 x1 x0 x2 x0
..
.
bN = f [xN , xN 1 , xN 2 , . . . , x1 , x0 ] ,
donde hemos usado la definicion recurrente
f [xN , xN 1 , xN 2 , . . . , x1 ] f [xN 1 , xN 2 , . . . , x1 , x0 ]
f [xN , xN 1 , xN 2 , . . . , x1 , x0 ] .
xN x0
La expresion anterior es conocida como la n-esima diferencia dividida finita. Usando estas
definiciones podemos escribir el polinomio de interpolacion (10.3) de la siguiente manera:
PN (x) = f0 + f [x1 , x0 ](x x0 ) + f [x2 , x1 , x0 ](x x1 )(x x0 ) +
+f [xN , xN 1 , xN 2 , . . . , x1 , x0 ](x x0 )(x x1 ) (x xN 1 ) ,
Este polinomio es conocido como el polinomio de interpolaci on por diferencias divididas de
Newton. Analicemos estos f [. . .] para el caso equiespaciado,
f1 f0 f0
f [x1 , x0 ] = = .
x1 x0 1!h
El segundo
f2 f1 f1 f0
x x1 x1 x0 f (x2 ) 2f (x1 ) + f (x0 ) 2 f0
f [x2 , x1 , x0 ] = 2 = = .
x2 x0 2h2 2!h2
En general tenemos (puede probarse por induccion) que
n f0
f [xN , xN 1 , xN 2 , . . . , x1 , x0 ] =
.
n!hn
Luego podemos escribir la llamada f ormula hacia adelante de Newton-Gregory, definiendo
= (x x0 )/h de la siguiente manera
2 f (x0 ) n f (x0 )
fN (x) = f (x0 ) + f (x0 ) + ( 1) + + ( 1) ( n + 1) + RN ,
2! n!
(10.4)
258 CAPITULO 10. INTEGRACION
NUMERICA
BASICA
f (n+1) () n+1
RN = h ( 1)( 2) ( n) ,
(n + 1)!
un [a, b].
para alg
usando que f (xi ) = f (xi+1 ) f (xi ) podemos dar una expresion para la integral
f (xi+1 ) + f (xi )
Ii (h) h. (10.5)
2
integrando obtenemos
usando la expresion para f (xi ) = f (xi+1 )f (xi ) y para 2 f (xi ) = f (xi+2 )2f (xi+1 )+f (xi )
tenemos
h
Ii (h) (f (xi ) + 4f (xi+1 ) + f (xi+2 )) . (10.6)
3
Se puede continuar encontrando expresiones usando aproximaciones de orden mayor, sin
embargo, las formulas (10.5) y (10.6) son, sin duda, las mas usadas.
A continuacion, para evaluar la integral finita (10.1) debemos sumar las integrales par-
ciales para ambos casos. Partamos sumando (10.5)
b N 1 Z xi+1 N 1
f (xi+1 ) f (xi )
Z X X
I= f (x) dx = f (x) dx h IT (h) ,
a i=0 xi i=0
2
La cual es conocida como la regla de Simpson. Notemos que se necesita un n umero impar de
puntos equiespaciados para aplicar esta regla.
Se puede estimar el error cometido en cada caso integrando el termino (10.3) que corres-
ponde al error de truncamiento de la expansion. Evaluemos el error para el caso trapezoidal
en que cortamos la expansion a primer orden, por lo tanto el error corresponde
Z xi+1 2
d f () h2 (x xi ) (x xi h)
T (h) = dx ,
xi dx2 2! h h
1 d2 f () h
3
h3 1 d2 f () h3 d2 f ()
Z
h
T (h) = u(u h) du = =
2 dx2 0 3 2 2 dx2 12 dx2
260 CAPITULO 10. INTEGRACION
NUMERICA
BASICA
este es el error en cada integral entre xi y xi+1 , para obtener el error total en la integral entre
a y b tenemos que multiplicar por el n umero de intervalos (N ),
h3 d2 f () (b a)h2 d2 f () h2 0
I IT (h) = N T (h) = N = = (f (b) f 0 (a)) .
12 dx2 12 dx2 12
La expresion para el error en el metodo trapezoidal nos queda
1 2 0
I IT (h) = h [f (b) f 0 (a)] + O(h4 ) . (10.9)
12
Vemos que el error es proporcional a h2 , y que la regla trapezoidal tendra problemas
Rb cuando
la derivada diverge en los extremos del intervalo. Por ejemplo, la integral 0 x dx es pro-
blematica. En el caso de la integral de Simpson se puede probar que el error es proporcional
a h4 .
Como ejemplo, consideremos la funcion error
Z x
2 2
erf(x) = ey dy . (10.10)
0
Para x = 1, erf(1) ' 0.842701. La regla trapezoidal con N = 5 da 0.83837, que es correcto
en los dos primeros decimales. La regla de Simpson, con los mismos 5 puntos, da 0.84274,
con cuatro decimales correctos . Por supuesto, el integrando en este ejemplo es muy suave y
bien comportado lo cual asegura que los metodos funcionaran bien.
10.5. Integraci
on de Romberg
Una pregunta usual es cuantas subdivisiones del intervalo realizar. Un modo de decidir es
repetir el calculo con un intervalo mas pequeno. Si la respuesta no cambia apreciablemente,
la aceptamos como correcta (sin embargo, esto no evita que podamos ser enga nados por fun-
ciones patologicas o escenarios inusuales). Con la regla trapezoidal, si el n
umero de paneles es
una potencia de dos, podemos dividir el tama no del intervalo por dos sin tener que recalcular
todos los puntos.
Definamos la secuencia de tama nos de intervalo,
1 1
h1 = (b a) , h2 = (b a) , . . . , hn = n1 (b a) . (10.11)
2 2
Para n = 1 solo hay un panel, luego
1 1
IT (h1 ) = (b a)[f (a) + f (b)] = h1 [f (a) + f (b)] .
2 2
Para n = 2 se a
nade un punto interior, luego
1
IT (h2 ) = h2 [f (a) + f (b)] + h2 f (a + h2 )
2
1
= IT (h1 ) + h2 f (a + h2 ) .
2
DE ROMBERG
10.5. INTEGRACION 261
El segundo termino del lado derecho da la contribucion de los puntos interiores que se han
agregado cuando el tama no del intervalo es reducido a la mitad.
Usando el metodo recursivo descrito, podemos agregar paneles hasta que la respuesta
parezca converger. Sin embargo, podemos mejorar notablemente este proceso usando un
metodo llamado integracion de Romberg. Primero veamos la mecanica, y despues explicaremos
por que funciona. El metodo calcula los elementos de una matriz triangular:
R1,1
R2,1 R2,2
R=R (10.13)
3,1 R3,2 R3,3
.. .. .. ..
. . . .
0.771743 0 0
0.825263 0.843103 0
0.838368 0.842736 0.842712
R3,3 da el resultado exacto con 4 decimales, usando los mismos 4 paneles que antes usamos
con la regla trapezoidal (y que ahora reobtenemos en el elemento R3,1 ).
Es util que el programa entregue toda la tabla y no solo el u
ltimo termino, para tener
una estimacion del error. Como en otros contextos, usar una tabla demasiado grande puede
no ser conveniente pues errores de redondeo pueden comenzar a degradar la respuesta.
Para entender por que el esquema de Romberg funciona, consideremos el error para la
regla trapezoidal, ET (hn ) = I IT (hn ). Usando (10.9),
1 2 0
ET (hn ) = h [f (b) f 0 (a)] + O(h4n ) .
12 n
Como hn+1 = hn /2,
1 2 0
ET (hn+1 ) = hn [f (b) f 0 (a)] + O(h4n ) .
48
262 CAPITULO 10. INTEGRACION
NUMERICA
BASICA
Notemos como el termino h2n se cancela, dejando un error de truncamiento de orden h4n . La
siguiente columna (la tercera) de la tabla de Romberg cancela este termino, y as sucesiva-
mente.
aqu los xi son un conjunto de puntos elegidos de manera inteligente tal que disminuyan el
error y los wi son sus pesos respectivos, no necesariamente iguales unos con otros.
Figura 10.4: (a) Ilustracion de la regla trapezoidal que une los dos puntos extremos por una
recta. (B) Estimacion mejorada al elegir inteligentemente los puntos.
El nombre que reciben esta clase de tecnicas es Cuadratura de Gauss, la mas com un de
ellas es la conocida como de Gauss-Legendre, y es u til para un intervalo finito, el cual es
mapeado mediante un cambio de variables al intervalo [1, 1]. R Existen otras cuadraturas
como la de Gauss-Laguerre optima para integrales de la forma 0 ex f (x) dx.
10.7. BIBLIOGRAFIA 263
xi wi xi wi
N=2 N=8
0.57735 02692 1.00000 00000 0.18343 46425 0.36268 37834
N=3 0.52553 24099 0.31370 66459
0.00000 00000 0.88888 88889 0.79666 64774 0.22238 10345
0.77459 66692 0.55555 55556 0.96028 98565 0.10122 85363
N=4 N=12
0.33998 10436 0.65214 51549 0.12523 34085 0.24914 70458
0.86113 63116 0.34785 48451 0.36783 14990 0.23349 25365
N=5 0.58731 79543 0.20316 74267
0.00000 00000 0.56888 88889 0.76990 26742 0.16007 83285
0.53846 93101 0.47862 86705 0.90411 72564 0.10693 93260
0.90617 98459 0.23692 68850 0.98156 06342 0.04717 53364
Para evaluar (10.1), debemos mapear el intervalo [a, b] en el intervalo [1, 1] mediante el
cambio de variable x = 12 (b + a) + 21 (b a)z, quedandonos
Z b
ba 1
Z
f (x) dx = f (z) dz , (10.17)
a 2 1
esta u
ltima integral puede ser evaluada usando diferentes conjuntos de puntos y pesos,
Z 1
f (z) dz w1 f (x1 ) + . . . + wN f (xn ) . (10.18)
1
10.7. Bibliografa
Numerical Methods for Physics, second edition de Alejandro L. Garcia, editorial Pren-
tice Hall.
Metodos Numericos Aplicados en Ingeniera de Jean-Marie Ledanois, Aura Lopez de
Ramos, Jose Antonio Pimentel M. y Filipo F. Pironti Lubrano, editorial Mc Graw
Hill.
Metodos Numericos para Ingenieros Steven C. Chapra y Raymond P. Canale, editorial
Mc Graw Hill.
264 CAPITULO 10. INTEGRACION
NUMERICA
BASICA
double integrando(double);
int main(){
double a=0, b=1,x;
int N;
double h;
double I, suma=0;
cout << "Regla trapezoidal para erf(1)" << endl;
cout << "Numero de puntos: " ;
cin >> N;
h = (b-a)/(N-1);
for (int i=2;i<N;i++){
x = a+(i-1)*h;
suma+=integrando(x);
}
I = h*((integrando(a)+integrando(b))/2.0 + suma);
cout << "Valor aproximado: erf(1) ~= " << I << endl;
cout << "Valor exacto: erf(1) = 0.842701" << endl;
}
10.8.2. romberg.cc
#include "NumMeth.h"
#include <iomanip.h>
double integrando(double);
int main(){
double a=0, b=1,x;
int N,np;
double h;
double I, suma=0;
cout << "Integracion de Romberg para erf(1)" << endl;
10.8. LISTADOS DEL PROGRAMA. 265
if (i==0){
R[0][0] = h*(integrando(a)+integrando(b))/2.0;
}
else {
suma = 0;
for (int j=1;j<=np-1;j+=2){
x = a+j*h;
suma += integrando(x);
}
R[i][0] = R[i-1][0]/2.0 + h*suma;
}
}
int m = 1;
for (int j=1;j<N;j++){
m *= 4;
for (int i=j;i<N;i++){
R[i][j] = R[i][j-1] + (R[i][j-1]-R[i-1][j-1])/(m-1);
}
}
266 CAPITULO 10. INTEGRACION
NUMERICA
BASICA
Ap
endices.
267
Captulo 11
11.1. Introducci
on
Octave es un poderoso software para analisis numerico y visualizacion. Muchos de sus
comandos son compatibles con Matlab. En estos apuntes revisaremos algunas caractersticas
de estos programas. En realidad, el autor de este captulo ha sido usuario durante algunos a
nos
de Matlab, de modo que estos apuntes se han basado en ese conocimiento, considerando los
comandos que le son mas familiares de Matlab. En la mayora de las ocasiones he verificado
que los comandos descritos son tambien compatibles con Octave, pero ocasionalmente se
puede haber omitido algo. . . .
Matlab es una abreviacion de Matrix Laboratory. Los elementos basicos con los que se
trabaja con matrices. Todos los otros tipos de variables (vectores, texto, polinomios, etc.),
son tratados como matrices. Esto permite escribir rutinas optimizadas para el trabajo con
matrices, y extender su uso a todos los otros tipos de variables facilmente.
a=3;
a
269
270 CAPITULO 11. UNA BREVE INTRODUCCION
A OCTAVE/MATLAB
a=5
a
a=3
a=5
a=5
Un numero sin punto decimal es tratado como un entero exacto. Un n umero con punto
decimal es tratado como un n umero en doble precision. Esto puede no ser evidente
en el output. Por default, 8.4 es escrito en pantalla como 8.4000. Tras la instruccion
format long, sin embargo, es escrito como 8.40000000000000. Para volver al formato
original, basta la instruccion format.
11.3.2. Matrices
Este tipo de variable corresponde a escalares, vectores fila o columna, y matrices conven-
cionales.
Construcci
on
Las instrucciones:
a = [1 2 ; 3 4]
11.3. TIPOS DE VARIABLES 271
o
a = [1, 2; 3, 4]
1 2
definen la matriz . Las comas (opcionales) separan elementos de columnas distintas,
3 4
y los punto y coma separan elementos de filas distintas. El vector fila (1 2) es
b = [1 2]
1
y el vector columna es
2
c = [1;2]
Un n
umero se define simplemente como d = [3] o d = 3.
Nota importante: Muchas funciones de Octave/Matlab en las paginas siguientes acep-
tan indistintamente escalares, vectores filas, vectores columnas, o matrices, y su output es
un escalar, vector o matriz, respectivamente. Por ejemplo, log(a) es un vector fila si a es un
vector fila (donde cada elemento es el logaritmo natural del elemento correspondiente en a),
y un vector columna si a es un vector columna. En el resto de este manual no se advertira
este hecho, y se pondran ejemplos con un solo tipo de variable, en el entendido que el lector
esta conciente de esta nota.
Acceso y modificaci
on de elementos individuales
Accesamos los elementos de cada matriz usando los ndices de filas y columnas, que parten
de uno. Usando la matriz a antes definida, a(1,2) es 2. Para modificar
un elemento, basta
1 2
escribir, por ejemplo, a(2,2) = 5. Esto convierte a la matriz en . En el caso especial
3 5
de vectores filas o columnas, basta un ndice. (En los ejemplos anteriores, b(2) = c(2) = 2.)
Una caracterstica muy importante del programa es que toda matriz es redimensionada
automaticamente cuando se intenta modificar un elemento que sobrepasa las dimensiones
actuales de la matriz, llenando con ceros los lugares necesarios. Por ejemplo, si b = [1 2],
y en seguida intentamos la asignacion b(5) = 8, b es automaticamente convertido al vector
fila de 5 elementos [1 2 0 0 8].
Concatenacion de matrices
1 2 7
Si a = ,b= 5 6 ,c= , entonces
3 4 8
d = [a c]
1 2 7
d=
3 4 8
d = [a; b]
1 2
d = 3 4
5 6
272 CAPITULO 11. UNA BREVE INTRODUCCION
A OCTAVE/MATLAB
d = [a [0; 0] c]
1 2 0 7
d=
3 4 0 8
11.3.3. Strings
Las cadenas de texto son casos particulares de vectores fila, y se construyen y modifican
de modo identico.
Construcci
on
Las instrucciones
Acceso y modificaci
on de elementos individuales
r = t(4)
r = b
t(9) = s
Concatenaci
on
t = un buen texto;
t1 = [t es necesario]
11.3.4. Estructuras
Las estructuras son extensiones de los tipos de variables anteriores. Una estructura consta
de distintos campos, y cada campo puede ser una matriz (es decir, un escalar, un vector o
una matriz), o una string.
Construcci
on
Las lneas
persona.nombre = Eduardo
persona.edad = 30
persona.matriz_favorita = [2 8;10 15];
11.4. OPERADORES BASICOS 273
definen una estructura con tres campos, uno de los cuales es un string, otro un escalar, y otro
una matriz:
persona =
{
nombre = Eduardo;
edad = 30;
matriz_favorita = [2 8; 10 15];
}
Acceso y modificaci
on de elementos individuales
s = persona.nombre
s = Eduardo
persona.nombre = Claudio
persona.matriz_favorita(2,1) = 8
persona =
{
nombre = Claudio;
edad = 30;
matriz_favorita = [2 8; 8 15];
}
11.4. Operadores b
asicos
11.4.1. Operadores aritm
eticos
Los operadores +, -, * corresponden a la suma, resta y multiplicacion convencional de
matrices. Ambas matrices deben tener la misma dimension, a menos que una sea un escalar.
Un escalar puede ser sumado, restado o multiplicado de una matriz de cualquier dimension.
.* y ./ permiten multiplicar y dividir elemento por elemento. Por ejemplo, si
1 2 5 6
a= b=
3 4 7 8
entonces
c = a.*b
5 12
c=
21 32
c = a./b
0.2 0.3333
c=
0.42857 0.5
274 CAPITULO 11. UNA BREVE INTRODUCCION
A OCTAVE/MATLAB
a = [1 2 3];
b = [4 2 1];
c = (a<3);
d = (a>=b);
c = (1, 1, 0)
d = (0, 1, 1)
11.4.3. Operadores l
ogicos
Los siguientes smbolos corresponden a los operadores AND, OR y NOT:
& | ~
El resultado de estas operaciones es 1 (verdadero) o 0 (falso).
11.4.4. El operador :
Es uno de los operadores fundamentales. Permite crear vectores y extraer submatrices.
11.6. Comandos
En esta seccion revisaremos diversos comandos de uso frecuente en Octave/Matlab. Esta
lista no pretende ser exhaustiva (se puede consultar la documentacion para mayores detalles),
y esta determinada por mi propio uso del programa y lo que yo considero mas frecuente
debido a esa experiencia. Insistimos en que ni la lista de comandos es exhaustiva, ni la lista
de ejemplos o usos de cada comando lo es. Esto pretende ser solo una descripcion de los
aspectos que me parecen mas importantes o de uso mas recurrente.
for
n=3; a=[1 4 9]
for i=1:n
a(i)=i^2;
end
Para Octave el vector resultante es columna en vez de fila.
Observar el uso del operador : para generar el vector [1 2 3]. Cualquier vector se puede
utilizar en su lugar: for i=[2 8 9 -3], for i=10:-2:1 (equivalente a [10 8 6 4 2]), etc.
son validas. El ciclo for anterior se podra haber escrito en una sola lnea as:
for i=1:n, a(i)=i^2; end
11.6. COMANDOS 277
b) if a==[3 8 9 10]
b = a(1:3);
end
c) if a>3
clear a;
elseif a<0
save a;
else
disp(Valor de a no considerado);
end
while s
comandos
end
Mientras s es 1, se ejecutan los comandos entre while y end. s puede ser cualquier
expresion que de por resultado 1 (verdadero) o 0 (falso).
break
Interrumpe ejecucion de ciclos for o while. En loops anidados, break sale del mas interno
solamente.
Funciones l
ogicas
Ademas de expresiones construidas con los operadores relacionales ==, <=, etc., y los
operadores logicos &, | y ~, los comandos de control de flujo anteriores admiten cualquier
funcion cuyo resultado sea 1 (verdadero) o 0 (falso). Particularmente u
tiles son funciones
como las siguientes:
all(a) 1 si todos los elementos de a son no nulos, y 0 si alguno es
cero
any(a) 1 si alguno de los elementos de a es no nulo
isempty(a) 1 si a es matriz vaca (a=[])
278 CAPITULO 11. UNA BREVE INTRODUCCION
A OCTAVE/MATLAB
Otras funciones entregan matrices de la misma dimension que el argumento, con unos o
ceros en los lugares en que la condicion es verdadera o falsa, respectivamente:
finite(a) 1 donde a es finito (no inf ni NaN)
isinf(a) 1 donde a es infinito
isnan(a) 1 donde a es un NaN
Por ejemplo, luego de ejecutar las lneas
x = [-2 -1 0 1 2];
y = 1./x;
a = finite(y);
b = isinf(y);
c = isnan(y);
se tiene
a = [1 1 0 1 1]
b = [0 0 1 0 0]
c = [0 0 0 0 0]
Otra funcion logica muy importante es find:
find(a) Encuentra los ndices de los elementos no nulos de a.
Por ejemplo, si ejecutamos las lneas
x=[11 0 33 0 55];
z1=find(x);
z2=find(x>0 & x<40);
obtendremos
z1 = [1 3 5]
z2 = [1 3]
find tambien puede dar dos resultados de salida simultaneamente (mas sobre esta posi-
bilidad en la seccion 11.6.2), en cuyo caso el resultado son los pares de ndices (ndices de fila
y columna) para cada elemento no nulo de una matriz
y=[1 2 3 4 5;6 7 8 9 10];
[z3,z4]=find(y>8);
da como resultado
z3 = [2;2];
z4 = [4;5];
z3 contiene los ndice de fila y z4 los de columna para los elementos no nulos
de la matriz
2 4
y>8. Esto permite construir, por ejemplo, la matriz z5=[z3 z4] = , en la cual cada
2 5
fila es la posicion de y tal que la condicion y>8 es verdadera (en este caso, es verdadera para
los elementos y(2,4) e y(2,5)).
11.6. COMANDOS 279
Matrices u
tiles para construir ejes o mallas para graficar
Por ejemplo:
x = [1 2 3];
y = [4 5];
[X,Y] = meshgrid(x,y);
da
1 2 3 4 4 4
X= , Y = .
1 2 3 5 5 5
Notemos que al tomar sucesivamente los pares ordenados (X(1,1),Y(1,1)), (X(1,2),Y(1,2)),
(X(1,3),Y(1,3)), etc., se obtienen todos los pares ordenados posibles tales que el primer ele-
mento esta en x y el segundo esta en y. Esta caracterstica hace particularmente u til el
comando meshgrid en el contexto de graficos de funciones de dos variables (ver secciones
11.6.7, 11.6.7).
Constantes especiales
Octave/Matlab proporciona algunos n umeros especiales, algunos de los cuales ya mencio-
namos en la seccion 11.3.1.
i, j Unidad imaginaria ( 1 )
inf Infinito
NaN Not-A-Number
pi El n umero (= 3.1415926535897 . . .)
Funciones elementales
Desde luego, Octave/Matlab proporciona todas las funciones matematicas basicas. Por
ejemplo:
11.6. COMANDOS 281
a) Funciones sobre n
umeros reales/complejos
Funciones especiales
Ademas, Octave/Matlab proporciona diversas funciones matematicas especiales. Algunos
ejemplos:
bessel Funcion de Bessel
besselh Funcion de Hankel
beta Funcion beta
ellipke Funcion elptica
erf Funcion error
gamma Funcion gamma
As, por ejemplo, bessel(alpha,X) eval
ua la funcion de Bessel de orden alpha, J (x),
para cada elemento de la matriz X.
11.6.4. Polinomios
Octave/Matlab representa los polinomios como vectores fila. El polinomio
p = cn xn + + c1 x + c0
11.6.5.
Algebra lineal (matrices cuadradas)
Unos pocos ejemplos, entre los comandos de uso mas habitual:
det Determinante
rank N
umero de filas o columnas linealmente independientes
trace Traza
inv Matriz inversa
eig Autovalores y autovectores
poly Polinomio caracterstico
Notar que poly es la misma funcion de la seccion 11.6.4 que construye un polinomio de
races dadas. En el fondo, construir el polinomio caracterstico de una matriz es lo mismo,
y por tanto tiene sentido asignarles la misma funcion. Y no hay confusion, pues una opera
sobre vectores y la otra sobre matrices cuadradas.
El uso de todos estos comandos son autoexplicativos, salvo eig, que se puede emplear de
dos modos:
d = eig(a)
[V,D] = eig(a)
La primera forma deja en d un vector con los autovalores de a. La segunda, deja en D una
matriz diagonal con los autovalores, y en V una matiz cuyas columnas son los autovalores, de
modo que A*V = V*D. Por ejemplo, si a =[1 2; 3 4], entonces
5.37228
d=
0.37228
y
5.37228 . . . 0 0.41597 . . . 0.82456 . . .
D= , V = .
0 0.37228 . . . 0.90938 . . . 0.56577 . . .
La primera columna de V es el autovector de a asociado al primer autovalor, 5.37228 . . ..
11.6.6. An
alisis de datos y transformada de Fourier
En Octave/Matlab estan disponibles diversas herramientas para el analisis de series de
datos (estadstica, correlaciones, convolucion, etc.). Algunas de las operaciones basicas son:
a) Maximos y mnimos
Si a es un vector, max(a) es el mayor elemento de a. Si es una matriz, max(a) es un vector
fila, que contiene el maximo elemento para cada columna.
11.6. COMANDOS 283
a = [1 6 7; 2 8 3; 0 4 1]
b = max(a) b = (2 8 7)
Se sigue que el mayor elemento de la matriz se obtiene con max(max(a)).
min opera de modo analogo, entregando los mnimos.
b) Estadstica basica
Las siguientes funciones, como min y max, operan sobre vectores del modo usual, y sobre
matrices entregando vectores fila, con cada elemento representando a cada columna de la
matriz.
c) Orden
sort(a) ordena los elementos de a en orden ascendente si a es un vector. Si es una matriz,
ordena cada columna.
1 3 0
b = sort([1 3 9; 8 2 1; 4 -3 0]); b = 4 2 1
8 3 9
d) Transformada de Fourier
Por u
ltimo, es posible efectuar transformadas de Fourier directas e inversas, en una o dos
dimensiones. Por ejemplo, fft y ifft dan la transformada de Fourier y la transformada
inversa de x, usando un algoritmo de fast Fourier transform (FFT). Especficamente, si
X=fft(x) y x=ifft(X), y los vectores son de largo N:
N
X (j1)(k1)
X(k) = x(j)N ,
j=1
N
1 X (j1)(k1)
x(j) = X(k)N ,
N k=1
donde N = e2i/N .
11.6.7. Gr
aficos
Una de las caractersticas mas importantes de Matlab son sus amplias posibilidades grafi-
cas. Algunas de esas caractersticas se encuentran tambien en Octave. En esta seccion revi-
saremos el caso de graficos en dos dimensiones, en la siguiente el caso de tres dimensiones, y
luego examinaremos algunas posibilidades de manipulacion de graficos.
284 CAPITULO 11. UNA BREVE INTRODUCCION
A OCTAVE/MATLAB
Gr
aficos bidimensionales
Para graficar en dos dimensiones se usa el comando plot. plot(x,y) grafica la ordenada
y versus la abscisa x. plot(y) asume abscisa [1,2,...n], donde n es la longitud de y.
Ejemplo: Si x=[2 8 9], y=[6 3 2], entonces
plot(x,y)
Por default, Octave utiliza gnuplot para los graficos. Por default, los puntos se conectan
con una lnea roja en este caso. El aspecto de la lnea o de los puntos puede ser modificado.
Por ejemplo, plot(x,y,ob) hace que los puntos sean indicados con crculos (o) azules
(b, blue). Otros modificadores posibles son:
- lnea (default) r red
. puntos g green
@ otro estilo de puntos b blue
+ signo mas m magenta
* asteriscos c cyan
o crculos w white
x cruces
Dos o mas graficos se pueden incluir en el mismo output agregando mas argumentos a
plot. Por ejemplo: plot(x1,y1,x,x2,y2,og,x3,y3,.c).
Los mapas de contorno son un tipo especial de grafico. Dada una funcion z = f (x, y),
nos interesa graficar los puntos (x, y) tales que f = c, con c alguna constante. Por ejemplo,
consideremos
2 2
z = xex y , x [2, 2], y [2, 3] .
Para obtener el grafico de contorno de z, mostrando los niveles z = .3, z = .1, z = 0,
z = .1 y z = .3, podemos usar las instrucciones:
x = -2:.2:2;
y = -2:.2:3;
[X,Y] = meshgrid(x,y);
11.6. COMANDOS 285
Z = X.*exp(-X.^2-Y.^2);
contour(Z.,[-.3 -.1 0 .1 .3],x,y); # Octave por default (gnuplot)
contour(x, y, Z.,[-.3 -.1 0 .1 .3]); # Octave con plplot y Matlab
Las dos primeras lneas definen los puntos sobre los ejes x e y en los cuales la funcion
sera evaluada. En este caso, escojimos una grilla en que puntos contiguos estan separados por
.2. Para un mapa de contorno, necesitamos evaluar la funcion en todos los pares ordenados
(x, y) posibles al escoger x en x e y en y. Para eso usamos meshgrid (introducida sin mayores
explicaciones en la seccion 11.6.3). Luego evaluamos la funcion [Z es una matriz, donde cada
elemento es el valor de la funcion en un par ordenado (x, y)], y finalmente construimos el
mapa de contorno para los niveles deseados.
Gr
aficos tridimensionales
Tambien es posible realizar graficos tridimensionales. Por ejemplo, la misma doble gaus-
siana de la seccion anterior se puede graficar en tres dimensiones, para mostrarla como una
superficie z(x, y). Basta reemplazar la u ltima instruccion, que llama a contour, por la si-
guiente:
mesh(X,Y,Z)
Observar que, mientras contour acepta argumentos dos de los cuales son vectores, y el
tercero una matriz, en mesh los tres argumentos son matrices de la misma dimension (usamos
X, Y, en vez de x, y).
Nota importante: Otro modo de hacer graficos bi y tridimensionales es con gplot
y gsplot (instrucciones asociadas realmente no a Octave sino a gnuplot, y por tanto no
equivalentes a instrucciones en Matlab). Se recomienda consultar la documentacion de Octave
para los detalles.
286 CAPITULO 11. UNA BREVE INTRODUCCION
A OCTAVE/MATLAB
Manipulaci
on de gr
aficos
Los siguientes comandos estan disponibles para modificar graficos construidos con Octa-
ve/Matlab:
a) Ejes
axis([x1 y1 x2 y2]) Cambia el eje x al rango (x1, x2), y el eje y al rango (y1, y2).
b) Ttulos
c) Grillas
x = linspace(1,10,30);
y = x.^3;
plot(x,y);
gset term postscript color
gset output xcubo.ps
replot
gset term x11
Las tres primeras lneas son los comandos de Octave/Matlab convencionales para graficar.
Luego se resetea el terminal a un terminal postscript en colores (gset term postscript si
no deseamos los colores), para que el output sucesivo vaya en formato postscript y no a
la pantalla. La siguiente lnea indica que la salida es al archivo xcubo.ps. Finalmente, se
redibuja el grafico (con lo cual el archivo xcubo.ps es realmente generado), y se vuelve al
terminal XWindows para continuar trabajando con salida a la pantalla.
Debemos hacer notar que no necesariamente el grafico exportado a Postscript se vera igual
al resultado que gnuplot muestra en pantalla. Durante la preparacion de este manual, nos
dimos cuenta de ello al intentar cambiar los estilos de lnea de plot. Queda entonces advertido
el lector.
11.6.8. Strings
Para manipular una cadena de texto, disponemos de los siguientes comandos:
lower Convierte a min
usculas
upper Convierte a may
usculas
As, lower(Texto) da texto, y upper(Texto) da TEXTO.
Para comparar dos matrices entre s, usamos strcmp:
strcmp(a,b) 1 si a y b son identicas, 0 en caso contrario
Podemos convertir n
umeros enteros o reales en strings, y strings en n
umeros, con los
comandos:
int2str Convierte entero en string
num2str Convierte n
umero en string
str2num Convierte string en n
umero
288 CAPITULO 11. UNA BREVE INTRODUCCION
A OCTAVE/MATLAB
Por ejemplo, podemos usar esto para construir un ttulo para un grafico:
archivo = fopen(archivo.dat,w);
Esto abre el archivo archivo.dat para escritura (w), y le asigna a este archivo un n
umero
que queda alojado en la variable archivo para futura referencia.
Los modos de apertura posibles son:
r Abre para lectura
w Abre para escritura, descartando contenidos anteriores si los
hay
a Abre o crea archivo para escritura, agregando datos al final
del archivo si ya existe
r+ Abre para lectura y escritura
w+ Crea archivo para lectura y escritura
a+ Abre o crea archivo para lectura y escritura, agregando datos
al final del archivo si ya existe
En un archivo se puede escribir en modo binario:
fread Lee datos binarios
fwrite Escribe datos binarios
o en modo texto
fgetl Lee una lnea del archivo, descarta cambio de lnea
fgets Lee una lnea del archivo, preserva cambio de lnea
fprintf Escribe datos siguiendo un formato
fscanf Lee datos siguiendo un formato
Referimos al lector a la ayuda que proporciona Octave/Matlab para interiorizarse del
uso de estos comandos. Solo expondremos el uso de fprintf, pues el formato es algo que
habitualmente se necesita tanto para escribir en archivos como en pantalla, y fprintf se
puede usar en ambos casos.
La instruccion
fprintf(archivo,formato,A,B,...)
11.6. COMANDOS 289
imprime en el archivo asociado con el identificador archivo (asociado al mismo al usar fopen,
ver mas arriba), las variables A, B, etc., usando el formato formato. archivo=1 corresponde
a la pantalla; si archivo se omite, el default es 1, es decir, fprintf imprime en pantalla si
archivo=1 o si se omite el primer argumento.
formato es una string, que puede contener caracters normales, caracteres de escape o
especificadores de conversion. Los caracteres de escape son:
\n New line
\t Horizontal tab
\b Backspace
\r Carriage return
\f Form feed
\\ Backslash
\ Single quote
Por ejemplo, la lnea
da como resultado
Una tabulacion y un original cambio de linea
aqui
Es importante notar que por default, el cambio de lnea al final de un fprintf no existe,
de modo que, si queremos evitar salidas a pantalla o a archivo poco esteticas, siempre hay
que terminar con un \n.
Los especificadores de conversion permiten dar formato adecuado a las variables numericas
A, B, etc. que se desean imprimir. Constan del caracter %, seguido de indicadores de ancho
(opcionales), y caracteres de conversion. Por ejemplo, si deseamos imprimir el numero con
5 decimales, la instruccion es:
fprintf(Numero pi = %.5f\n,pi)
El resultado:
Numero pi = 3.14159
Los caracteres de conversion pueden ser
%e Notacion exponencial (Ej.: 2.4e-5)
%f Notacion con punto decimal fijo (Ej.: 0.000024)
%g %e o %f, dependiendo de cual sea mas corto (los ceros no
significativos no se imprimen)
Entre % y e, f, o g segun corresponda, se pueden agregar uno o mas de los siguientes
caracteres, en este orden:
Un n
umero entero para especificar un ancho mnimo del campo.
Un n
umero indicando la precision (n
umero de dgitos a la derecha del punto decimal).
En el siguiente ejemplo veremos distintos casos posibles. El output fue generado con las
siguientes instrucciones, contenidas en un script:
a = .04395;
fprintf(123456789012345\n);
fprintf(a = %.3f.\n,a);
fprintf(a = %10.2f.\n,a);
fprintf(a = %-10.2f.\n,a);
fprintf(a = %4f.\n,a);
fprintf(a = %5.3e.\n,a);
fprintf(a = %f.\n,a);
fprintf(a = %e.\n,a);
fprintf(a = %g.\n,a);
El resultado:
12345678901234567890
a = 0.044.
a = 0.04.
a = 0.04 .
a = 0.043950.
a = 4.395e-02.
a = 0.043950.
a = 4.395000e-02.
a = 0.04395.
En la primera lnea, se imprimen tres decimales. En la segunda, dos, pero el ancho mnimo
es 10 caracteres, de modo que se alnea a la derecha el output y se completa con blancos. En
la tercera lnea es lo mismo, pero alineado a la izquierda. En la cuarta lnea se ha especificado
un ancho mnimo de 4 caracteres; como el tama no del n
umero es mayor, esto no tiene efecto
y se imprime el n umero completo. En la quinta lnea se usa notacion exponencial, con tres
decimal (nuevamente, el ancho mnimo especificado, 5, es menor que el ancho del output,
luego no tiene efecto). Las u ltimas tres lneas comparan el output de %f, %e y %g, sin otras
especificaciones.
Si se desean imprimir mas de un n umero, basta agregar las conversiones adecuadas y los
argumentos en fprintf. As, la lnea
da por resultado
x = 1:5;
y1 = exp(x);
y2 = log(x);
a = [x; y1; y2];
fprintf = (%g %8g %8.3f\n,a);
da el output
1 2.71828 0.000
2 7.38906 0.693
3 20.0855 1.099
4 54.5982 1.386
5 148.413 1.609