Introducción a MATLAB

Anuncio
Prácticas de Ampliación de Métodos Numéricos. Una
Introducción a MATLAB
Ion Zaballa
1.
Introducción
Aunque desarrollado con mi propio lenguaje y motivación, el contenido e ideas de esta Introducción a MATLAB está sacadas de los Capı́tulos 1 de los excelentes libros de Cleve Moler [1]
y Charle van Loan [2]. El primero está disponible por capı́tulos separados totalmente gratis en
la dirección:
http://www.mathworks.com/moler
Esta introducción a MATLAB tiene como objetivo que el/la estudiante se familiarice rápidamente con algunas de las muchas posibilidades que ofrece MATLAB para trabajar las matemáticas.
La idea es presentar varios problemas que investigan algunos problemas elementales y al mismo
tiempo, espero que, interesantes de matemáticas. Quienes tengan experiencia en otros lenguajes
de programación enseguida apreciarán la potencia y sencillez de manejo de MATLAB estudiando estos ejemplos. Para todos, iniciados o no iniciados, se ha confeccionado una Guı́a básica de
MATLAB para el Curso de Análisis Matricial, disponible en la misma página web en la que
está esta introducción. Pero para quienes ésta sea la primera vez que tienen contacto con un lenguaje de programación, hay multitud de manuales “on-line” y MATLAB, propiamente, dispone
de una guı́a de ayuda para empezar a trabajar:
Ejercicio 1 Pinchando en Help en el menú principal y seleccionando Product Help aparecerá una nueva ventana con toda la ayuda de MATLAB. En la parte izquierda aparece un
menú que se puede desplegar pinchando en el sı́mbolo
. Utilizando esta técnica tómate unos
minutos para familiarizarte con este sistema de ayuda. Por ejemplo, despliega los siguientes
menús: MATLAB → Getting Started → Matrices and Arrays → Matrices and Magic Squares y lee los documentos que aparecen allı́: About Matrices, Entering Matrices,
sum,transpose and diag, Subscripts, The Colon Operator y The magic Function.
Están ordenados, de forma que se entiende mejor su contenido si se leen en el orden especificado.
Ejercicio 2 Tómate otros pocos minutos para ver una de las “demos” que vienen con MATLAB.
Se accede a ellas a través del menú Help que aparece en el menú principal tanto de la ventana de
comandos como de la de ayuda. Una demostración recomendable es Basic Matrix Operations
que aparece al seleccionar Mathematics en el menú principal.
1
Ejercicio 3 .- Utiliza helpwin para echar un vistazo a las funciones matemáticas elementales
de MATLAB.
φ
1
φ−1
1
Figura 1: El rectángulo áureo.
2.
La razón áurea
Para ir aprendiendo algunos comandos de MATLAB vamos a tomar como disculpa la razón
áurea. Se trata de una práctica dirigida en la que debes ir haciendo lo que se indica para
familiarizarte con algunos comandos básicos de MATLAB.
La razón áurea aparece en muchas partes de la matemática y aquı́ veremos unas pocas. La
razón áurea toma su nombre del reactángulo áureo que se muestra en la Figura 1. Éste tiene
la propiedad caracterı́stica siguiente: al suprimir un cuadrado unidad se obtiene un rectángulo
menor con las mismas proporciones que el original. Es decir,
1
φ−1
=
.
φ
1
La razón áurea es el lado de tal rectángulo. Debe ser entonces la raı́z cuadrada positiva de la
siguiente ecuación de segundo grado
φ2 − φ − 1 = 0.
Las dos soluciones de esta ecuación son
√
1± 5
φ=
2
Ejercicio 4 Asigna el valor positivo a la variable phi y calcula el valor en formato short y
long.(Indicación: Puedes utilizar el comando help format para consultar la ayuda sobre los
posibles formatos en que se presentan los números).
2
Se puede usar MATLAB para hallar las raı́ces de un polinomio. MATLAB representa los polinomios como un vector: el de sus coeficientes. Ası́, el vector
>> p=[1 -1 -1]
representa el polinomio
p(x) = x2 − x − 1
Las raı́ces se calculan mediante la función roots:
>> r=roots(p)
produce
r =
-0.61803398874989
1.61803398874989
Ejercicio 5 Compruébalo.
Hay muchas formas de calcular la razón áurea con MATLAB. Una de ellas es definir la función
f (x) =
1
− (x − 1)
x
y calcular sus ceros. Para definir una función a partir de la versión 7 de MATLAB se puede
utilizar el siguiente código
>> f=@(x)1/x-(x-1)
Ası́ queda definida f como función de x. Se pueden definir funciones de varias variables. Por
ejemplo
>> f=@(x,y)y/x-(x-y)
definirı́a f como función de las variables x, y. Y
>>f(2,1)
devuelve el valor de f en el punto (2,1).
Ejercicio 6 Escribe los comandos anteriores y comprueba los resultados.
3
Supongamos que tenemos definida la función f (x) = x1 − (x − 1). Queremos calcular las raı́ces
de esta función. Para ello necesitamos una estimación de donde pueden estar aproximadamente.
Una forma de obtener esta aproximación es dibujar la gráfica de esta función. El comando ezplot
lo hace
>> ezplot(f,0,4)
1/x−(x−1)
7
6
5
4
3
2
1
0
−1
−2
−3
0
0.5
1
1.5
2
x
2.5
3
Figura 2: Gráfica de la fucnión f (x) =
3.5
1
x
4
− (x − 1).
produciendo la Figura 2 sin el cı́rculito que marca el cero de la función f . Los argumentos 0 y
4 especifican el intervalo (0, 4) en el que se dibuja la gráfica. Nótese que f tiene una ası́ntota
vertical en x = 0.
En la gráfica se aprecia que f tiene un cero entre 1 y 2. Poniendo
>> phi=fzero(f,1.5)
se obtiene
phi =
1.61803398874989
que es una aproximación a la razón áurea tan buena como se podrı́a desear. Los comandos
>> hold on
>> plot(phi,0,’o’)
sirven para colocar un circulito en en la posición (φ, 0) en la misma figura donde se habı́a
dibujado la curva (ver la Figura 2).
4
Ejercicio 7 Escribe los comandos anteriores y comprueba los resultados. Usa la ayuda (help
hold, help plot) para saber lo que hacen dichas órdenes.
A continuación escribiremos el programa de MATLAB que produce la Figura 1. Pero antes de
hacerlo conviene tener en cuenta lo siguiente: un programa de MATLAB es un fichero con la
extensión .m que contiene varias lı́neas de comandos válidos de MATLAB y que se ejecutan
sucesivamente. Enseguida veremos un ejemplo. La distribución de MATLAB instalada en el
ordenador tiene cientos o miles de tales programas. El Capı́tulo 4 de la Guı́a está dedicado a la
programación en MATLAB y el objetivo de las prácticas de este curso es llegar a confeccionar
algunos programas interesantes en el lenguaje de MATLAB. En el Capı́tulo 3 se explican algunos
conceptos previos necesarios para que MATLAB interactúe correctamente con los programas que
vayas creando. Esto es un pequeño resumen.
MATLAB necesita conocer de antemano los directorios donde se encuentran los programas que
quieres ejecutar. Si los programas vienen en la distribución, no hay problema, ya sabe donde
buscarlos. Pero no tiene por qué saber donde se encuentran los programas confeccionados por
cada usuario; ası́ que éste tiene tres opciones:
(a) ponerlos en la carpeta que utiliza MATLAB por defecto. Esto puede cambiar de una
versión a otra y de un sistema operativo a otro. En el momento actual Windows guarda,
por defecto, los ficheros de los usuarios en la carpeta MATLAB de Mis Documentos.
(b) colocarlos en una carpeta personal (incluyendo un “lápiz de memoria” o disquete) y añadir
esta carpeta personal al MATLAB search path, y
(c) colocarlos en una carpeta personal y cambiar el directorio de trabajo (ventana superior
izquierda) a dicha carpeta personal.
En tu propio ordenador personal cualquiera de las tres opciones es buena, pero en los ordenadores
de la Facultad, en los que muchas personas diferentes pueden usar MATLAB, no tienes garantı́as
de que un programa dejado en una carpeta del ordenador vaya a encontrarse allı́ la siguiente
vez que lo necesites. Es conveniente, por lo tanto, que cada cual venga provisto de un disquete
o “lápiz de memoria” para almacenar allı́ tus programas.
Por el momento comprueba que estás en la capeta MATLAB de Mis Documentos, y si no, cambia
a ella. Si no sabes cómo hacerlo pregúntalo.
En la ventana de comandos de MATLAB escribe (es muy importante que no te olvides de la
extensión .m porque es la forma en que MATLAB sabe que se trata de un fichero ejecutable):
>> edit rectaureo.m
Se abrirá, en otra ventana, el editor de MATLAB. Escribe en él las siguientes lı́neas:
%RECTAUREO Rectángulo áureo
% RECTAUREO dibuja el rectángulo áureo.
5
phi = (1+sqrt(5))/2;
x = [0 phi phi 0 0];
y = [0 0 1 1 0];
u = [1 1];
v = [0 1];
plot(x,y,’b’,u,v,’b--’);
text(phi/2,1.05,’\phi’);
text((1+phi)/2,-.05,’\phi - 1’);
text(-.05,.5,’1’);
text(.5,-.05,’1’);
axis equal;
axis off;
set(gcf,’color’,’white’);
A continuación sálvalo. En el directorio de trabajo debe aparecer ahora el fichero rectaureo.m.
Este es un ejemplo tı́pico de lo que en MATLAB se llama un script (guión, en traducción literal
al castellano). Los script son ficheros con la extensión .m que contienen una serie de comandos de
MATLAB. Cuando escribimos el nombre del fichero (sin extensión) en la ventana de comandos
se ejecutan sucesivamente las lı́neas del fichero. Observa que después de cada comando en el
fichero rectaureo.m hemos puesto ; porque no queremos que los resultados aparezcan en la
ventana de comandos; sólo queremos que aparezca la figura.
Ahora, en la ventana de comandos de MATLAB escribe:
>> rectaureo
MATLAB ejecutará todos los comandos escritos en el fichero y aparecerá la Figura 1 en una
nueva ventana.
Ejercicio 8 Trata de adivinar lo que hace cada una de las lı́neas del programa y, una vez que
lo hayas conseguido (usando la ayuda o preguntando, si es necesario), responde a las siguientes
cuestiones: En los paı́ses europeos la medida estándar del papel es DIN A4. Sus dimensiones son:
210 mm de ancho y 297 mm de largo. La razón entre estas dos cantidades no es la razón áurea
pero es próxima a otro número irracional. ¿Cuál?. Si divides por la mitad una hoja DIN A4 ¿cuál
es la razón entre las dimensiones de cada una de las mitades? Modifica el fichero rectaureo.m
para ilustrar esta propiedad.
Ejercicio 9 Escribe un programa que se llame circunferencia.m que produzca la Figura 3.
La razón áurea φ se puede obtener como una fracción continua; i.e. una expresión de la forma
a0 +
1
a1 +
6
1
a2 + a
1
3 +···
.
0.8
0.6
u
0.4
0.2
60o
1
0
−0.2
v
−0.4
−0.6
−0.8
−1
−0.5
0
0.5
1
Figura 3: Circunferencia de radio 1
En efecto, resulta que si todos los ai son iguales a 1 obtenemos φ:
φ=1+
1
1+
1
.
1
1+ 1+···
Esto permite confeccionar una función de MATLAB que genera y evalúa la fracción continua
truncada al número de fracciones que se desee. Abre un editor y escribe lo que viene a continuación. Una vez escrito, guárdalo con el nombre fracaurea.m.
function fracaurea(n)
%FRACAUREA Fraccion continua para la razon aurea.
% FRACAUREA(n) presenta n terminos de la fraccion continua
% y varias formas de evaluar la razon aurea.
p = ’1’;
for k = 1:n
p = [’1+1/(’ p ’)’];%Se debe dejar un espacio enter ’ y p y entre p y ’
end
p
p = 1;
q = 1;
for k = 1:n
s = p;
p = p + q;
q = s;
end
p = sprintf(’%d/%d’,p,q)
format long
7
p = eval(p)
format short
err = (1+sqrt(5))/2 - p
Uno de los objetivos de este curso es llegar a escribir algunas funciones y scripts en el lenguaje
de programación de MATLAB. Es importante que leas atentamente el Capı́tulo 4 de la Guı́a;
en particular, la sección 4.2. En cualquier caso vamos a analizar un poco esta función.
Todas las funciones de MATLAB son ficheros con la extensión .m y empiezan con la palabra
function. Esta es una de las diferencias con los scripts. Otra diferencia es que, suelen recibir
valores (en este caso n) y, aunque no es el caso de esta función, también suelen devolver valores
(enseguida veremos un ejemplo de función que cumple estos dos requisitos). Y una tercera
diferencia muy importante es que las variables de las funciones son locales mientras que las
de los scripts son globales. Es decir, las variables en las funciones se almacenan en la memoria
mientras se ejecuta la función; una vez terminada ésta desaparecen de la memoria del ordenador.
Para los scripts sin embargo, las variables se mantienen en la memoria con el valor que toman
en el script hasta que es sustituı́do por otro valor o se cierra MATLAB. Es decir, las variables
de los scripts actúan como si se ejecutaran en la ventana de comandos.
Analicemos esta función un poco. En primer lugar escribimos
>> fracaurea(6)
en la ventana de comandos de MATLAB. La respuesta es
p =
1+1/(1+1/(1+1/(1+1/(1+1/(1+1/(1))))))
p =
21/13
p =
1.61538461538462
err =
0.0026
Las tres ps son diferentes formas de representar la misma aproximación a φ.
8
La primera p es la fracción continua truncada a 6 términos. Se produce de la siguiente forma:
se le asigna a la variable p el valor ’1’. Las tildes son importantes. Es la forma de decirle a
MATLAB que se trata de una variable de tipo string, cadena de caracteres. De esta forma, al
principio p es el string ’1’. Luego entramos en un bucle for ...end que repetidamente inserta
los strings ’1+1/(’ y ’)’ por delante y por detrás, respectivamente, del string almacenado en p.
Independientemente de lo largo que este string llegue a ser, es una expresión válida en MATLAB.
Finalmente, el comando p (sin ;) muestra el valor de p al salir del bucle.
El segundo p es la fracción ordinaria que produce el truncamiento de la fracción continua después
de 6 términos. Puede no parecerlo, pero si observamos que
1+
1
p
q
=
p+q
p
enseguida nos daremos cuenta de que empezando con los valores p = q = 1 (i.e., con la fracción
1
1 ) y reemplazando la fracción
p
q
por
p+q
p
obtenemos el valor de la fracción continua truncada al término deseado. Finalmente el comando
p = sprintf(’%d/%d’,p,q)
escribe la fracción obtenida en la forma p/q con p y q en formato de número decimal (aunque en
este caso sean enteros). Debe notarse que después de p = sprintf(’ %d/ %d’,p,q), la variable
p vuelve a ser un string.
El tercer p es el valor numérico del segundo p obtenido usando el comando eval. Esta función
devuelve el valor numérico de un string formado por una operación válida para MATLAB. Por
ejemplo, los comandos
>> A=rand(2);
>> s=’det(A)’;
>> eval(s)
producirı́an el valor del det(A) (aunque, claro, ésta es una forma muy tonta de calcularlo).
En el caso que estamos considerando, el segundo p es el string ’21/13’. Al hacer eval(p) se
calcula el valor de la fracción 21
13 y se escribe como número decimal.
Todo lo anterior nos ha servido para aprender algunas funciones de MATLAB pero se podrı́a
haber obtenido el mismo resultado de forma más rápida. El código
p = sprintf(’%d/%d’,p,q)
format long
p = eval(p)
9
se podrı́a haber sustituı́do por
format rat
p=p/q
format long
p
De esta forma p serı́a siempre una variable numérica, primero en formato racional, y después,
en formato decimal.
Finalmente la cantidad err es la diferencia entre p y φ; es decir, el error absoluto de la estimación.
Con 6 términos, la aproximación tiene menos de 3 dı́gitos de precisión.
Ejercicio 10 ¿Cuántos términos se necesitarı́an para conseguir una precisión de 10 dı́gitos? ¿Y
para que el error sea cero? ¿Qué pasa, entonces, (teóricamente y en la práctica) si aumentas el
número de términos?
3.
Números de Fibonacci
La razón áurea aparece en muchos lugares de forma que podrı́a considerarse misteriosa. Un
ejemplo son los números de Fibonacci. En un libro publicado en 1202, Liber Abaci, Leonardo
Pisano Fibonacci propuso el siguiente problema:
Un hombre coloca un par de conejos en un lugar rodeado por un muro de forma que
queden completamente aislados. Este par de conejos y los sucesivos que vayan naciendo engendran un nuevo par cada mes a partir del segundo mes de vida. ¿Cuántos
conejos habrá al cabo de un año?
Si no se pusiera la condición de que los conejos no son productivos hasta el segundo mes,
la respuesta serı́a sencilla y no habrı́a habido números de Fibonacci. Si cada par de conejos
engendrara otro par cada mes, el número de éstos se duplicarı́a cada mes; y al cabo de n meses
habrı́a 2n conejos. Pero la condición de que sólo se pueden producir nuevos pares de conejos a
partir del segundo mes de vida, hace que el problema sea más interesante.
Si fn representa el número de pares de conejos después de n meses, este número debe ser igual
al número de conejos en el mes anterior fn−1 más el de conejos que ha producido una nueva
pareja (que son los que habı́a un mes antes, fn−2 ). Ası́
fn = fn−1 + fn−2
Los dos primeros meses habrá f1 = 1 y f2 = 2 pares de conejos, respectivamente.
Con estos datos podemos producir una función de MATLAB que nos proporcione la secuencia
de Fibonacci con tantos términos como queramos. Usa el editor para escribirla y salvarla con el
nombre de fibonacci.m
10
function f = fibonacci(n)
%FIBONACCI secuencia de Fibonacci
%
f = FIBONACCI(n) genera los primeros n números de Fibonacci.
f = zeros(n,1);
f(1) = 1;
f(2) = 2;
for k = 3:n
f(k) = f(k-1) + f(k-2);
end
Esta ya es una función tı́pica de MATLAB. Es conveniente y altamente aconsejable que el
nombre del fichero que usas para escribir esta función (en este caso fibonacci.m) coincida con
el nombre de la función. Debes tener en cuenta que si llamas a la función escribiendo su nombre
en la lı́nea de comandos, MATLAB buscará un fichero con ese nombre. Por lo tanto, si el nombre
de la función y del fichero no coinciden, no obtendrás el resultado que deseas.
fibonacci es una verdadera función de MATLAB, sencilla, pero con todos los ingredientes:
empieza con la palabra function, admite datos de entrada: n, y produce una salida: f, que
es un vector. La función define primero un vector (matriz) de tamaño n × 1 con todas sus
componentes iguales a 0. A continuación cambia la primera componente a 1 y la segunda a 2
iniciando la secuencia de Fibonacci. Después entramos en un bucle para sustituir las restantes
componentes del vector f .
Entre el nombre de la función y los comandos que la componen hay dos (o más) lı́neas que
comienzan por el sı́mbolo %. Son lı́neas de comentarios que sirven para orientar a quien use la
función sobre lo que ésta realiza. Si una vez escrita la función y salvado el fichero escribimos
>> help fibonacci
en la ventana de comandos, obtendremos
FIBONACCI secuencia de Fibonacci
f = FIBONACCI(n) genera los primeros n números de Fibonacci.
Esta información es muy útil para los posibles usuarios de la función. Es muy buena costumbre
colocar un par de lı́neas de comentarios para ayudarnos a nosotros mismos y a los demás.
Veamos ahora la salida que produce la función. Si escribimos
>> g=fibonacci(12)
obtendremos
g =
11
1
2
3
5
8
13
21
34
55
89
144
233
La salida de la función, que es un vector, se ha almacenado en la variable g, que ahora contiene
los 12 primero términos de la sucesión de Fibonacci.
Por lo general, no necesitaremos todos los datos del vector, quizá sólo unos pocos, o ni tan
siquiera eso: quizá sólo queramos tener el vector con los datos para usarlo posteriormente. Por
ejemplo, si hacemos
>> g=fibonacci(12);
No hay respuesta visible por parte de MATLAB, pero en g está el vector con los 12 primeros
números de la sucesión de Fibonacci. Aunque no lo parezca éstos están relacionados con φ, la
razón áurea. Veamos, escribamos
>> format rat
>> g(7)/g(6)
La respuesta es
ans =
21/13
Este número nos resulta familiar: es el número que producı́a fracaurea(6). ¿Es una casualidad?.
Ejercicio 11 Comprueba para varios valores de n (no mayores que 40, ¿por qué?) que la fracción
que se obtiene como resultado de fracaurea(n) coincide con el valor de f(n+1)/f(n) donde f
es el vector que devuelve fibonacci(n+1).
Esto hace plausible el siguiente resultado que es, en efecto, verdadero
fn+1
= φ.
n→∞ fn
lı́m
12
4.
Cuadrados Mágicos
Aunque en la actualidad MATLAB puede considerarse un software de propósito general, nació con el objetivo de proporcionar un entorno de trabajo para el cálculo numérico con vectores
y matrices. De ahı́ su nombre que proviene de Matrix Laboratory. Los cuadrados mágicos proporcionan un conjunto interesante de ejemplos de matrices. Si escribimos
>> help magic
obtenemos
MAGIC Magic square.
MAGIC(N) is an N-by-N matrix constructed from the integers
1 through N^2 with equal row, column, and diagonal sums.
Produces valid magic squares for all N > 0 except N = 2.
Los cuadrados mágicos eran conocidos en China 2000 años antes de nuestra era, y el cuadrado
mágico de orden 3 se conoce con el nombre de Lo Shu. Cuenta la leyenda que fué descubierto en
el caparazón de una tortuga en el rı́o Lo en el siglo 23 antes de Cristo. Hay cantidad de mitologı́a
y esoterismo asociado a los cuadrados mágicos. Una rápida consulta en Google proporciona un
sin fin de páginas relacionadas con los cuadrados mágicos. Tal y como dice la ayuda de magic este
comando proporciona un cuadrado mágico de cualquier orden, salvo de orden 2. Por ejemplo,
Lo Shu se consigue de la siguiente forma:
>>A=magic(3)
que produce
A =
8
3
4
1
5
9
6
7
2
El comando
>> sum(A)
devuelve un vector cuya i-ésima componente es la sumas de los elementos de la i-ésima columna:
ans =
15
15
15
Para obtener la suma de los elementos en cada fila podemos usar el mismo comando sobre la
transpuesta:
13
>> sum(A’)’
ans =
15
15
15
Para sumar los elementos de la diagonal principal (elementos en la posición (i, i)):
>> sum(diag(A))
ans =
15
El comando flipup pasa la primera fila a la última, la segunda a la penúltima y ası́ sucesivamente. Si queremos comprobar que la contradiagonal (elementos en la posición (i, n − i + 1))
también suman lo mismo podemos utilizar el comando
>> sum(diag(flipud(A)))
ans =
15
El mismo efecto habrı́amos conseguido con el comando fliplr que hace lo mismo que flipud
pero por columnas.
Todo lo anterior certifica que A es un cuadrado mágico. Pero ¿por qué la suma es 15?. El
comando
>> sum(1:9)
ans =
45
nos permite observar que la suma de los primeros 9 números enteros positivos es 45. Como éstos
están colocados en A de tres en tres y sumando siempre lo mismo, la suma de cada fila, columna,
etc. debe ser 15.
Hay 8 formas posibles de colocar una transparencia en un retroproyector (no olvidemos que
una transparencia se puede leer por delante y por detrás). De la misma forma hay 8 maneras
posibles de escribir el mismo cuadrado mágico de orden 3 que corresponden a las posibles formas
de rotar y reflejar el cuadrado. Se pueden obtener mediante los siguientes simples comandos que
se explican por sı́ solos:
>> for k=0:3
rot90(A,k)
rot90(A’,k)
end
14
Ahora un poco de álgebra lineal:
>> det(A)
ans =
-360
nos da el determinante,
>> X=inv(A)
X =
0.1472
-0.0611
-0.0194
-0.1444
0.0222
0.1889
0.0639
0.1056
-0.1028
nos da la inversa, aunque se aprecia mejor si usamos el formato racional
>> format rat
>> X
X =
53/360
-11/180
-7/360
-13/90
1/45
17/90
23/360
19/180
-37/360
Volvemos al formato decimal para calcular la norma espectral, los valores propios y los valores
singulares de A:
>> format short
>> r=norm(A),e=eig(A),s=svd(A)
r =
15
e =
15.0000
4.8990
-4.8990
s =
15.0000
6.9282
3.4641
La suma “mágica”, 15, aparece en los tres casos porque el vector (1, 1, 1) es vector propio y
vector singular a izquierda y derecha de A.
En el grabado La Melancolı́a de Albrecht Durero aparece, entre otros objetos matemáticos, un
cuadrado mágico de orden 4. La distribución de MATLAB contiene una copia electrónica de
este cuadro. Se encuentra en el fichero durer.mat. Carguemos los datos del fichero:
15
>> load durer
Ahora veamos las variables que contiene. El comando whos devuelve las variables que han sido
definidas en una sesión. Es posible que tengas otras variables, aparte de las definidas al cargar
el fichero durer.mat, de modo que lo que aparece a continuación puede ser sólo parte de lo que
se muestra en tu ventana de comandos.
>> whos
Name
X
caption
map
Size
Bytes
648x509
2x28
128x3
2638656
112
3072
Class
Attributes
double
char
double
Hay libros especializados en cómo MATLAB maneja los colores y las imágenes, pero no estudiaremos este asunto aquı́. Como curiosidad veamos cómo conseguir el grabado La Melancolı́a.
Los tres siguientes comandos lo proporcionan:
>> image(X)
>> colormap(map)
>> axis image
Puedes teclearlo uno a uno para ver lo que vas obteniendo.
Hay una lupa en la barra de herramientas, utilı́zala para agrandar un cuadrado que se aprecia
debajo de la campana. Observarás una matriz 4 × 4. Quizá no la distingas muy bien. MATLAB
tiene otro fichero, detail.mat, en el que están los datos de ese detalle del grabado con mucha
mejor resolución. Los siguientes comandos te proporcionan la imagen:
>> load detail
>> image(X);colormap(map);axis image;
Se trata de un cuadrado mágico, pero no el que produce MATLAB con el comando magic(4):
>> A=magic(4)
A =
16
2
5
11
9
7
4
14
3
10
6
15
13
8
12
1
El de Durero se obtiene de éste permutando las columnas segunda y tercera:
>> A=A(:,[1 3 2 4])
16
A =
16
5
9
4
3
10
6
15
2
11
7
14
13
8
12
1
Al permutar dos filas o dos columnas se puede destruir la “magia” del cuadrado, pero casualmente en este caso no. En efecto, las diagonales siguen sumando 34 (la sumas de filas y columnas, por
supuesto, no se modifican). Probablemente Durero escogió este cuadrado mágico porque juntado
las cifras de los dos números que están en el centro de la última fila se consigue el número 1514,
que fué el año en que Durero hizo el grabado.
Hemos visto dos cuadrados mágicos diferentes de orden 4; hay 880. Y de orden 5, 275305224.
No se sabe cuántos hay de orden 6 o más.
Curiosamente, o no, para nuestros cuadrados mágicos de orden 4 tenemos que det(A) = 0. Y si
intentamos calcular la inversa obtenemos
>> inv(A)
Warning: Matrix is close to singular or badly scaled.
Results may be inaccurate. RCOND = 9.796086e-18.
ans =
1.0e+15 *
0.1251
-0.3753
0.3753
-0.1251
0.3753
-1.1259
1.1259
-0.3753
-0.3753
1.1259
-1.1259
0.3753
-0.1251
0.3753
-0.3753
0.1251
Ya veremos el significado del mensaje obtenido. En cualquier caso, esto nos indica que hay
cuadrados mágicos que son matrices singulares (no invertibles) ¿cuáles?. El siguiente código
produce una tabla de dos columnas, en la primera se coloca el orden del cuadrado mágico
producido por MATLAB y en la segunda su rango:
>> for n=1:24; r(n)=rank(magic(n));end; [(1:24)’ r’]
ans =
1
1
2
2
3
3
4
3
5
5
6
5
7
7
8
3
9
9
10
7
17
11
12
13
14
15
16
17
18
19
20
21
22
23
24
11
3
13
9
15
3
17
11
19
3
21
13
23
3
Observa cuidadosamente esta tabla, ignorando el caso n = 2 que no es un cuadrado mágico.¿Observas alguna regla?. Quizá un diagrama de barras puede ayudarte(Figura 4):
>> bar(r); title(’Rango de los cuadrados magicos’)
25
Rango de los cuadrados magicos
20
15
10
5
0
0
5
10
15
20
25
Figura 4: Rango de los cuadrados mágicos producidos por MATLAB
Ejercicio 12 A=magic(4) es singular; i.e., sus columnas son linealmente dependientes. Los siguientes comandos te informan sobre cómo es esa dependencia: null(A), null(A,’r’), rref(A).
¿Qué información te proporcionan?
Ejercicio 13 Sea A=magic(n) para n=3,4,5. ¿qué efecto producen los comandos
>> p=randperm(n);q=randperm(n);A=A(p,q);
sobre sum(A),sum(A’)’,sum(diag(A)),sum(diag(flipud(A))),rank(A)?
18
5.
Procesos Aleatorios
Muchas simulaciones que se realizan para predecir el comportamiento de objetos involucran
procesos aleatorios. El ejemplo que veremos más abajo es el siguiente: Supongamos que queremos
obtener una estimación del número π. Podrı́amos idear un proceso aleatorio cuya probabilidad
esté relacionada con el número π. Una posibilidad es la siguiente: ¿Cuál es la probabilidad de
que al lanzar un dardo, sin apuntar, a una diana redonda inscrita en un cuadrado (Figura 5)
acertemos en la diana y no en la superficie del cuadrado exterior a la misma? Sencillamente la
1.5
1
0.5
0
−0.5
−1
−1.5
−1.5
−1
−0.5
0
0.5
1
1.5
Figura 5: Una diana.
relación entre las áreas de ambas figuras geométricas. Si el cuadrado lo pensamos centrado en
el punto (0, 0) y de lado 2, la circunferencia tendrá radio 1 y tal probabilidad es
π
.
4
Con un ordenador podemos simular el lanzamiento de un dardo a la diana: cada lanzamiento
es asociado a la elección aleatoria de un par de números (x, y) comprendidos entre −1 y 1.
Este punto representarı́a el punto del cuadrado donde se ha clavado el dardo. Realizando esta
simulación un número muy alto de veces la frecuencia relativa de elección de puntos en el interior
del cı́rculo se deberá aproximar a la probabilidad buscada:
π≈
Número de lanzamientos en el interior del cı́rculo
·4
Número total de lanzamientos
El punto clave en esta simulación es el de la elección aleatoria del par de puntos que determinan las coordenadas del cuadrado. Todos los puntos deberı́an tener la misma probabilidad
de ser elegidos; y esto nos indica que los números aleatorios que los determinan deben estar
uniformemente distribuidos. MATLAB proporciona, mediante el uso repetido del comando rand
una sucesión de puntos uniformemente distribuı́dos entre 0 y 1. Cómo es generada tal sucesión
no es un problema trivial, pero se puede modificar el comienzo de la misma con el comando
rand(’seed’,n) con n un número entero positivo.
19
También se pueden obtener números aleatorios normalmente distribuı́dos. El comando que lo
hace es randn. El siguiente script puede servir para comprender la diferencia entre ambos tipos
de números aleatorios:
close all
clc
subplot(2,1,1)
x=rand(1000,1);
hist(x,30)
axis([-1 2 0 60])
title(’Distribución de los valores en rand(1000,1)’)
xlabel(sprintf(’Media= %5.3f. Mediana=%5.3f.’, mean(x),median(x)))
subplot(2,1,2)
x=randn(1000,1);
hist(x,linspace(-2.9,2.9,100))
title(’Distribución de los valores en randn(1000,1)’)
xlabel(sprintf(’Media= %5.3f. Desviacion standard=%5.3f.’, mean(x),std(x)))
Ejercicio 14 Copia este script en un fichero con el nombre randhisto.m y ejecútalo. Trata de
comprender lo que hace cada comando.
Ejercicio 15 .- Para apreciar, de otra forma, la diferencia entre la distribución uniforme y la
normal escribe un “script” que haga lo siguiente:
1.- Escoja aleatoriamente 10000 pares de puntos, primero con distribución uniforme y después
con distribución normal.
2.- Haga dos gráficas, cada una de ellas dibujando todos los puntos escogidos de cada una de las
dos formas.
3.- Ponga un tı́tulo significativo en cada gráfica.
4.- Los ejes de la primera gráfica deben estar entre 0 y 1; y los de la segunda entre -3 y 3.
Una vez que entendemos mejor la diferencia entre los comandos rand y randn, podemos volver
a nuestra simulación para el cálculo aproximado del número π. Vamos a escribir una función
que produzca la simulación del lanzamiento de los dardos. Recordemos que la parte importante
es la selección aleatoria de un par de puntos (x, y) en el interior del cuadrado (por lo tanto, con
distribución uniforme) y la determinación de si tal punto está o no en el interior del cı́rculo. La
función admite un número entero positivo
function pi=dardos(n)
%DARDOS es una función para calcular el numero pi
% usando un método de Montecarlo
20
%DARDOS admite un número entero n que es el número de
%cientos de lanzamientos y devuelve una
%aproximación a pi y la gráfica de la convergencia a
%pi del método
if (ceil(n)-n ~= 0 || n<0)
error(’n debe ser entero’);
return
else
close all; clc
rand(’seed’,0);
ndentro=0;
piestimada=zeros(n,1);
for k=1:n
x=-1+2*rand(100,1);y=-1+2*rand(100,1);
ndentro=ndentro+sum(x.^2+y.^2<=1);
piestimada(k)=(ndentro)/(100*k)*4;
end
plot(piestimada)
pi=piestimada(n);
title(sprintf(’Valor estimado de pi= %5.6f’,pi));
xlabel(’Cientos de lanzamientos’);
end
La ejecución de esta función con n = 500 (esto es, 50000 lanzamientos) produce el valor de
π = 3,1302 y la Figura 6. Debe observarse que el valor estimado de π mejora gradualmente a
Valor estimado de pi= 3.157
3.26
3.24
3.22
3.2
3.18
3.16
3.14
3.12
3.1
3.08
0
50
100
150
200
250
300
Cientos de lanzamientos
350
400
450
500
Figura 6: Una estimación de π de tipo Montecarlo.
medida que n aumenta, pero que el “progreso” hacia 3’14159 no es ni estable ni, mucho menos,
rápido. Simulaciones de este tipo se conocen con el nombre de Montecarlo (o Monte Carlo).
21
Hay una sentencia en el programa que merece atención especial: sum(x.^2+y.^2<=1). x y y son
vectores de 100 componentes cada uno y x.^2 eleva cada componente de x al cuadrado (y lo
mismo y.^2). Ahora, x.^2+y.^2 es un vector cuyas componentes son la suma de los cuadrados de
las componentes de x y de y. Finalmente, x.^2+y.^2<=1 también es un vector: sus componentes
son 0 o 1. Es 0 si la correspondiente componente no cumple la condición y 1 si la cumple. Por
lo tanto, sum((x.^2+y.^2<=1) cuenta el número de componentes del vector x.^2+y.^2 que son
menores que 1; es decir, el número de dardos que han impactado en el interior del cı́rculo.
Otros dos comandos útiles para trabajar con vectores de ceros y unos son any y all. any(x)
devuelve un 1 (“true”) si alguna componente de x es distinta de cero; si no devuelve un 0
(“false”). Y all(x) devuelve un 1 si todas las componentes de x son distintas de cero; si no
devuelve un cero. Si x es una matriz, any y all actúa por columnas. Ası́
>> x=[ 0 1 0; 1 -1 0; -1 1 0]
x =
0
1
0
1
-1
0
-1
1
0
>> any(x)
ans =
1
1
0
>> all(x)
ans =
0
1
0
Ejercicio 16 ¿Cuál es la probabilidad (aproximadamente) de que el polinomio cuadrático p(x) =
ax2 + bx + c tenga raı́ces complejas sabiendo que los coeficientes a, b y c son variables aleatorias
con distribución uniforme (0, 1)? ¿Y si lo son con distribución normal (0, 1)?. Se trata de fabricar
una función que lo simule.
6.
Aritmética en punto flotante
Dado que los ordenadores utilizan un número finito de bits para representar los números reales,
sólo pueden representar un número finito de ellos; es decir, un subconjunto finito de números
reales (o de números complejos). Esta limitación conlleva dos dificultades:
Los números representados no pueden ser arbitrariamente grandes (en valor absoluto).
Debe haber “agujeros” entre ellos.
Lo primero conduce a los fenómenos conocidos con los nombres de “overflow” y “underflow”
(rebosamiento por arriba o por abajo) y lo segundo produce el “roundoff” (redondeo). Por lo
general, es posible usar MATLAB sin preocuparse de estas cuestiones, pero de vez en cuando
22
puede que nos encontremos con problemas que un somero conocimiento del funcionamiento de
la aritmética en punto flotante puede ayudar a solucionar.
Hace 20 años la situación era mucho más complicada de lo que es ahora porque cada ordenador
tenı́a su propio sistema de números en punto flotante. Algunos eran binarios, otros decimales.
Incluso hubo algunos ordenadores rusos que usaban aritmética ternaria. Además, entre los binarios los habı́a que usaban aritmética de base 2, otros octal o hexadécimal. Y cada uno tenı́a
su propia precisión. En 1985 la IEEE Standard Board y el American National Standard Institute decidieron adoptar para la aritmética binaria de punto flotante lo que se conocce como el
ANSI/IEEE Standard 754-1985. Esta decisión fue la culminación del trabajo de casi una década de trabajo de un grupo de 92 personas integrado por matemáticos, ingenieros e informáticos
procedentes de universidades y empresas dedicadas a la construcción de ordenadores y microprocesadores. Todos los ordenadores diseñados a partir de 1985 usan la aritmética IEEE de punto
flotante. Esto no significa que todos ellos producen los mismos resultados porque hay una cierta
flexibilidad en la norma ANSI/IEEE, sino que el modelo de funcionamiento de la aritmética en
punto flotante es, hoy en dia, independiente del ordenador que se utilice.
MATLAB ha usado siempre el formato IEEE de doble precisión. Hay un formato de precisión
simple que salva espacio pero que no supone una mejora en la velocidad con los ordenadores
actuales. Nosotros hablaremos sólo de la precisión doble. Para entender bien este concepto
debemos recordar la forma en la que los ordenadores
√ trabajan con los números en punto flotante.
La mayorı́a están normalizados. Si calculamos 1/ 120 en una calculadora de bolsillo con notación
cientı́fica obtendremos (esto es lo que marca la mı́a)
9, 128709292e − 2
(1)
o algo similar. Es la notación cientı́fica para el número
9, 12870929 · 10−2 .
El número en punto flotante de (1) no está normalizado. Para considerarlo normalizado debemos
escribirlo de la siguiente forma:
0, 912870929 · 10−1
o
0, 912870929e − 1.
Es decir, un número en punto flotante es normalizado si la parte fraccionaria es de la forma
0.x1 x2 . . . con x1 6= 0. Para los números representados en base 10, 1 ≤ x1 ≤ 9, pero para los
números en base 2 x1 = 1 siempre, de modo que la parte fraccionaria tendrá la forma 0,1x2 x3 . . .
con xi = 0 o 1. Nótese que un número de esta forma puede escribirse como (1 + f )2−1 siendo
f = 0.x2 x3 . . .. Por lo tanto, en un ordenador que representa los números en base binaria (que es
el que consideraremos nosotros), los números en punto flotante normalizados tienen la siguiente
forma:
x = ±(1 + f ) · 2e
con
0≤f <1
y e un número entero.
Al número f se le llama fracción o mantisa y a e exponente o caracterı́stica.
Los números en punto flotante de precisión simple se almacenan en “palabras” de 32 bits,
mientras que los de doble precisión lo hacen en “palabras” de 64 bits. De éstos, 52 bits se usan
23
para almacenar f , 11 bits para e y 1 bit para el signo del número, 0 para + y 1 para − (Figura
7). Puesto que la fracción debe estar entre 0 y 1 y se debe almacenar en 52 bits, debe resultar
s
fracción
exponente
63
11
0 1
Figura 7: Palabra en punto flotante en doble precisión.
que 252 f es un número entero que debe estar en el intervalo
0 ≤ 252 f < 252
Y como 252 ≈ 4,5 · 1015 , los números en punto flotante en doble precisión se expresan, en base
decimal, con 15 decimales. Debe notarse, finalmente que la parte fraccional completa de los
números en punto flotante no es f sino 1 + f , que necesita 53 bits. Sin embargo, como la primera
cifra decimal siempre es 1 (si el número está normalizado), no es necesario almacenarlo. De
hecho, el formato IEEE empaqueta 65 bits de información en una “palabra” de 64 bits.
Por otra parte, para el exponente se reservan 11 bits, ası́ que e es un numero entero en el intervalo
0 ≤ e ≤ 211 = 2048.
Sin embargo, debemos permitir exponentes negativos almacenándolos en los 11 bits disponibles.
Para conseguirlo lo que se hace es acomodar en los 11 bits el número e+1023. Ası́, si el número
almacenado en los 11 bits de e es 1250 entonces e = 1250 − 1023 = 227; mientras que si el
número almacenado es 1000 entonces e = 1000 − 1023 = −23. Los valores extremos posibles en
estos 11 bits: 0 y 211 − 1 se reservan para definir números especiales que veremos más adelante.
Los restantes son valores admisibles para e. Por lo tanto el exponente debe encontrarse en el
intervalo
−1022 ≤ e ≤ 1023.
Teniendo en cuenta que
(1 + 0,99999999999999) · 21023 ≈ 1,79 · 10308
y
(1 + 0) · 2−1022 ≈ 2,23 · 10−308 ,
éstos son el mayor y menor números representables en doble precisión. En MATLAB estos
números reciben un nombre especial
realmax = (1 + 0,99999999999999) · 21023 = 1,7977 · 10308
realmin = 1 + 0) · 2−1022 = 2,2251 · 10−308 .
Si algún cálculo intenta producir un valor mayor que realmax se dice que produce un rebosamiento por arriba (“overflow”) dando como resultado un número especial llamado “infinity”,
Inf en MATLAB. Se representa tomando e = 1024 y f = 0 y cumple propiedades tales como
1/Inf=0 o Inf+Inf=Inf. Por ejemplo
24
>> realmax^2
ans =
Inf
>> Inf*Inf
ans =
Inf
Para operaciones tales como 0/0 o Inf-Inf el resultado es un valor excepcional denotado por
el sı́mbolo NaN por “not a number”.
>> 0/0
Warning: Divide by zero.
ans =
NaN
>> Inf-Inf
ans =
NaN
Si algún cálculo intenta producir un número inferior a realmin, se dice que produce un rebosamiento por abajo (“underflow”). En realidad, algunos sistemas como MATLAB permiten
números más pequeños llamados números en punto flotante denormales (o subnormales, aunque esta denominación en castellano tiene connotaciones negativas). El número más pequeño
en MATLAB es 2 ^ (-1074) ≈ 0.494e-323. Veremos más adelante de donde proviene este
número.
>> 2^(-1074)
ans =
4.9407e-324
> 2^(-1075)
ans =
0
El rebosamiento por arriba (que rara vez ocurre en la práctica) puede, a veces, evitarse escalando
adecuadamente los datos del problema para convertirlo en un rebosamiento por abajo que no
tiene consecuencias importantes. Por ejemplo, supongamos que tenemos que calcular la cantidad
p
c = a2 + b2
con a = 10200 y b = 1. Una respuesta aceptable serı́a c = 10200 debido a que b es insignificante
en comparación a a. Si hacemos este cálculo directamente en MATLAB:
>> a=10^200;b=1; c=sqrt(a^2+b^2)
c =
Inf
25
La respuesta es debida a que se ha producido un rebosamiento por arriba. Teóricamente, el
mismo resultado se obtendrı́a si hiciéramos
s
a 2 b 2
c=s
+
s
s
con s 6= 0. En particular, escogiendo s = máx{|a|, |b|} = 10200 obtenemos lo siguiente:
> s=max(abs(a),abs(b));c=s*sqrt((a/s)^2+(b/s)^2)
c =
1.0000e+200
que es la respuesta que hemos dado como aceptable. Este resultado es debido al rebosamiento
por abajo ocurrido al calcular (b/s)2 :
>> (b/s)^2
ans =
0
Los fenómenos de rebosamiento tienen su origen en las cotas superior e inferior de los exponentes
admisibles. Hay otro fenómeno importante que es consecuencia de la finitud de las posibles
mantisas o fracciones: el redondeo. Comencemos con la siguiente pregunta: ¿Cuántos números
en coma flotante hay entre 1 y 2? Son los de la forma
+(1 + f ) · 20 .
Y como f está representado por 52 bits (i.e., 52 posiciones cada una de ellas conteniendo un 0
o un 1), el número posible de fracciones es 252 = 4,503599627370496e + 15 (las formas posibles
de colocar 0 y 1 en 52 posiciones distintas). Ası́ pues, los posibles valores de f son:
0, 2−52 , 2 · 2−52 , 3 · 2−52 , 4 · 2−52 , . . . , (252 − 1) · 2−52 .
En consecuencia, los números en punto flotante en el intervalo [1, 2] son
1, 1 + 2−52 , 1 + 2 · 2−52 , 1 + 3 · 2−52 , 1 + 4 · 2−52 , . . . , 1 + (252 − 1) · 2−52 , 2.
De la misma forma, los números en punto flotante en el intervalo [2, 4) son de la forma
+(1 + f ) · 21 ,
y son, concretamente:
2, 2 + 2−51 , 2 + 2 · 2−51 , 2 + 3 · 2−51 , 2 + 4 · 2−51 , . . . , 2 + (252 − 1) · 2−51 , 4.
En general, los números en el intervalo [2j , 2j+1 ] son los de (2) multiplicados por 2j .
26
(2)
eps = 1/8
||||||| |||||||| | | | | | | | | | | | | | | | |
1/16
1/2
1
|
|
|
|
2
|
|
|
|
|
|
|
|
|
|
4
|
8−1/2
Figura 8: Floatgui.
Ejercicio 17 En el directorio matlab de tu cuenta personal encontrarás un archivo titulado
floatgui. Ha sido escrito por Cleve Moler para poner de manifiesto la distribución de los
números positivos en punto flotante en un sistema para el que es posible elegir los parámetros
t (número de bits utilizado para almacenar f ) y emáx y emı́n (el intervalo en el que está e).
Inicialmente floatgui se presenta con t = 3, emı́n = −4 y emáx = 3 y produce la distribución
de la Figura 8 Se puede observar que en cada intervalo binario [2j , 2j+1 ] los números están
igualmente espaciados con un incremento de 2j−t . Si j = 0 y t = 3, por ejemplo, el espacio entre
los números que están entre 1 y 2 es 2−3 ; el espacio entre los que están entre 2 y 3 es 2−2 , etc.
Esta “equidistribución” se hace más evidente si utilizamos una escala logarı́tmica. La Figura 9
muestra el resultado de floatgui cuando se marca la casilla de log scale con t = 5, emı́n = −4
y emáx = 3.
eps = 1/32
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
||
1/16
1/4
1/2
1
2
4
16−1/4
Figura 9: Floatgui.
Experimenta con floatgui para comprender la distribución de los números en punto flotante y
responde a las siguientes preguntas: ¿Para un valores concretos de t, emı́n y emáx cuántos números
positivos son representables exactamente en punto flotante? ¿Cuántos números positivos contiene
el conjunto de números en punto flotante del sistema IEEE?
Cualquier número real que no coincida con uno de los números en punto flotante del sistema
IEEE debe ser aproximado por uno de ellos; concretamente por el más próximo. A este fenómeno
se le llama redondeo. Si x es un número real, se denota por fl(x), el número en punto flotante
más próximo a x. Resulta que si realmin≤ x ≤realmax entonces
| fl(x) − x|
≤ 2−53 .
|x|
En efecto, suponiendo que x ∈ [2j , 2j+1 ] y que fl(x) = (1 + a · 2−52 )2j entonces
(1 + a · 2−52 )2j ≤ x < (1 + (a + 1) · 2−52 )2j o (1 + (a − 1) · 2−52 )2j < x ≤ (1 + a · 2−52 )2j
27
Pero como fl(x) = (1 + a · 2−52 )2j se tiene
x − (1 + a · 2−52 )2j < (1 + (a + 1) · 2−52 )2j − x = (1 + a · 2−52 )2j − x + 2j−52
o
(1 + a · 2−52 )2j − x < x − (1 + (a − 1) · 2−52 )2j = x − (1 + a · 2−52 )2j − x + 2j−52 .
En cualquier caso
2|x − (1 + a · 2−52 )2j | < 2j−52 ⇔ |x − (1 + a · 2−52 )2j | < 2j−53
Como fl(x) = (1 + a · 2−52 )2j y x > 2j concluı́mos que
| fl(x) − x|
≤ 2−53 .
|x|
Un razonamiento similar nos permite ver que, en términos relativos, la distancia entre dos
números en punto flotante consecutivos es 2−52 . En particular, ésta es la distancia de 1 al
siguiente número en punto flotante tal y como hemos visto en (2). A este número, se le conoce
con el nombre de épsilon de la máquina y se denota en MATLAB por eps. Ası́
eps = 2−52 ≈ 2,22 · 10−16
y se obtiene en MATLAB con el comando eps:
>> eps
ans =
2.220446049250313e-16.
Algunos autores prefieren llamar épsilon de la máquina al máximo error relativo posible al
redondear un número real por el número en punto flotante más próximo; i. e. eps/2=2−53 . En
cualquier caso, el nivel de error relativo es de aproximadamente 16 dı́gitos decimales.
Nótese que 2−52 · 2−1022 = 2−1074 . Este número ya lo hemos visto antes: era el menor valor
denormal (o subnormal) admisible en MATLAB.
En el cálculo binario del número t=0.1 se produce un redondeo que suele afectar a muchas
operaciones aritméticas. El valor almacenado en t no es exactamente 0,1 porque la fracción
decimal 1/10 expresada en base 2 requiere una serie infinita. Esto se entiende mejor si expresamos
1/10 en base 16; es decir, si usamos la representación hexadecimal :
1
9
9
9
−4
=2
1+
+
+
+ ··· .
(3)
10
16 162 163
En efecto
∞
X
1
1/16
1
= ,
=
j
16
1 − 1/16
15
j=1
y
2
−4
9
24
1
1+
=
= .
15
16 · 15
10
28
Para pasar (3) a formato binario observamos que
2−4
23 + 1
1
1
9
=
= 5 + 8,
8
16
2
2
2
2−4
9
23 + 1
1
1
=
= 9+ 1 ,
162
212
2
2 2
(4)
etc.
Por lo tanto
1
0
0
1
1
0
0
1
1
1
= 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + · · · .
10
2
2
2
2
2
2
2
2
2
La representación en número de punto flotante de 1/10 se obtiene tomando 52 términos de esta
serie (en formato binario), o 13 términos de la serie en formato hexadecimal, y redondeando el
último término al entero más próximo. En formato hexadecimal tendrı́amos que si
9
9
9
9
−4
+
+
+ · · · + 13
t1 = 2
1+
16 162 163
16
t2 =
2−4
9
9
9
10
1+
+
+
+ · · · + 13
16 162 163
16
entonces
t1 < 1/10 < t2 .
Pero resulta que 1/10 está más próximo a t2 que a t1 . Es decir,
1/10 = (1 + f ) · 2e
donde
f=
9
9
9
10
+ 2 + 3 + · · · + 13
16 16
16
16
(5)
e = −4
Hemos escrito f en formato hexadecimal. Para pasarlo a binario y conseguir los 52 bits que lo
representan se procederı́a como en (4). En realidad, la conversión de números entre las bases 2 y
16 es muy sencilla. Por ejemplo, en consonancia con (5), el comando de MATLAB format hex
aplicado a t=0.1 produce:
>> t=0.1
t =
0.1000
>> format hex
>> t
t =
3fb999999999999a
29
Las letras a a f representan los números 10 a 15 en base hexadecimal. Para pasar t a binario
basta observar que cada cifra es una “palabra” de cuatro bits. Ası́ 3fb en binario serı́a
0011 1111 1011,
que son los 12 primeros bits de t. El primer bit, 0, es el signo; por lo tanto t es positivo. Los
primeros 12 bits para −0,1 serı́a
1011 1111 1011,
que en hexadecimal es bfb. Los restantes 11 bits representan el exponente (en realidad, recordemos, 1023+e). Como 3fb en base diez es 3 · 162 + 15 · 16 + 11 = 1019, resulta que e = −4. Las
restantes cifras 999999999999a representan la fracción que en binario serı́a
1001 1001 1001 · · · 1001 1010
ocupando los 52 bits correspondientes.
Para saber la representación hexadecimal de un número en MATLAB se puede usar el comando
format hex. Una vez que se usa todas los resultados se presentarán en formato hexadecimal.
Para volver al formato decimal se deben usar los comandos format short, o format long, o
cualquiera de los otros disponibles. Ası́, el siguiente código nos da la razón áurea en base 16:
>> format hex
>> phi=(1+sqrt(5))/2
phi =
3ff9e3779b97f4a8
Una vez más, 3 es 0011 en binario, de modo que φ es positivo. Además 3ff en base 10 es 1023,
por lo que e = 0. Las restantes 13 cifras hexadecimales contienen la fracción f :
f=
9
14
10
8
+ 2 + · · · + 12 + 13 .
16 16
16
16
Con estos valores de e y f
(1 + f ) · 2e ≈ φ.
Ejercicio 18
1. ¿Cuál es la representación hexadecimal de los números 3/10 y 3 · 0,1? ¿Por
qué no es la misma?. (Si eres capaz de deducir por qué MATLAB produce esos resultados,
mejor que mejor). ¿Cuál es el error absoluto, tanto en formato hexadecimal como decimal,
cometido al aproximar 3/10 por 3 · 0,1?.
2. Explica el resultado producido por el siguiente código de MATLAB
t = 0.1
n = 1/10
e = n/10 - n*t
30
Dos últimos ejemplos en los que los efectos del redondeo se ponen de manifiesto. El primero
consiste en la resolución del siguiente sencillo sistema
17x1 + 5x2 = 22
1,7x1 + 0,5x2 = 2,2
(6)
Dado que la primera ecuación es 10 veces la segunda, este sistema tiene infinitas soluciones y la
más simple es x1 = x2 = 1.
Ejercicio 19
1. Resuelve el sistema (6) con MATLAB y comprueba que la solución obtenida
no es x1 = x2 = 1.. (Indicación: MATLAB utiliza el comando A\b para resolver el sistema
Ax = b mediante eliminación gaussiana.)
2. Utiliza MATLAB para hacer la eliminación gaussiana en etapas con formato cientı́fico; i.e.
format short e:
>> A(2,:)=A(2,:)-1.7/17*A(1,:)
>> b(2)=b(2)-1.7/17*b(1)
Observa que los elementos a22 y b2 no son cero. ¿Por qué?
3. Como a22 y b2 no son cero, x2 = b2 /a22 . Calcula con MATLAB este valor y después calcula
también x1 .
El último ejemplo de los efectos del redondeo lo vemos en el siguiente ejercicio
Ejercicio 20 El comando conv(p,q) multiplica los polinomios p y q. Por ejemplo, si p(x) =
2x3 − x + 3 y q(x) = −2x2 − x + 2 entonces
>>p=[2 0 -1 3]; q=[-2 -1 2];
>>conv(p,q)
ans =
-4
-2
6
-5
-5
6
de modo que el polinomio p(x)q(x) = −4x5 − 2x4 + 6x3 + · · · .
Considera el siguiente polinomio p(x) = (x − 2)9 y utiliza el comando conv para calcular los
coeficientes de este polinomio, Llámalo q.
1. Dibuja la gráfica de q(x) para x = 1,920, 1,921, 1,922, . . . , 2,080.
2. En la misma figura, dibuja en rojo p(x) en los mismos puntos. ¿Qué conclusión sacas?.
Referencias
[1] C. B. Moler: Numerical computing with MATLAB. SIAM, 2004.
[2] Ch. F. van Loan: Introduction to scientific computing. Prentice Hall.
31
Descargar