Está en la página 1de 25

UNIVERSIDAD POLITÉCNICA DE MADRID

ESCUELA TÉCNICA SUPERIOR DE


INGENIEROS DE MINAS
DEPARTAMENTO DE MATEMÁTICA APLICADA Y
MÉTODOS INFORMÁTICOS

TITULACIÓN: INGENIERÍA DE MINAS

ASIGNATURA: PROGRAMACIÓN Y MÉTODOS


NUMÉRICOS

PRÁCTICA Nº 2: BUCLES Y
ERRORES DE REDONDEO
CURSO 2006-07
PRÁCTICA ELABORADA POR:
Prof. Carlos Conde Lázaro
Prof. Arturo Hidalgo López
Prof. Alfredo López Benito

Depto. de Matemática Aplicada y Métodos Informáticos


Escuela Técnica Superior de Ingenieros de Minas
Universidad Politécnica de Madrid

Mayo 2007
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

OBJETIVOS DE LA PRÁCTICA
1º. Realizar algoritmos simples que utilicen estructuras repetitivas.
2º. Codificar números reales en aritmética binaria en coma flotante.
3º. Analizar la influencia de los errores de redondeo en los resultados de procesos de
cálculo.

FORMA DE DESARROLLAR ESTA PRÁCTICA.


La realización de la práctica se divide en dos partes. En la primera de ellas el profesor
explicará el funcionamiento de los comandos de MAPLE necesarios mediante el
desarrollo de los ejemplos contenidos en el epígrafe de EJEMPLOS.
En la segunda parte los alumnos deberán resolver individualmente los ejercicios
propuestos que se incluyen en el epígrafe de EJERCICIOS pudiendo consultar al
profesor cuantas dudas tengan sobre los mismos.
La semana siguiente a aquella en la que se realice la práctica, los alumnos podrán
solicitar una versión de la misma en la que se incluirán los ejercicios que se proponen
debidamente resueltos.

DURACIÓN ESTIMADA DE ESTA PRÁCTICA


El tiempo estimado para la realización de esta práctica es de 2 horas.

BIBLIOGRAFÍA
Esta práctica sigue lo recogido en los apuntes:
C. Conde , A. Hidalgo y A. López (2001). Errores de redondeo en la
representación de números reales. Open Course Ware de la Universidad
Politécnica de Madrid

Algunos de los enunciados de los ejercicios de esta práctica están basados en los
recogidos en los libros:
L.F. Shampine, R.C. Allen, Jr. y S. Pruess (1997). Fundamentals of
Numerical Computing. Ed. John Wiley &Sons, Inc.
J. M. Viaño (1.995) Lecciones de Métodos Numéricos: 1.- Introducción
general y análisis de errores. Ed. Tórculo Edicións

1
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

Influencia de los errores de redondeo. Bucles.


> restart;
El siguiente ejemplo se recoge en la referencia [2]. En él se propone el cálculo
de los valores de las integrales:
1

An := ⌠

⎮ ex n (x − 1)
dx
⌡0

para n = 1, 2, …… El valor de estas integrales puede estimarse de forma


recursiva, a partir del valor de la primera de ellas, ya que:
Ai := 1 − i Ai − 1( i = 2 .. ∞ )

partiendo del valor (obtenido para n = 1):


1
A1 := = 0.36787944117144232160
e
El problema que plantea tal forma de proceder es que el valor exacto de (1/e)
tiene infinitos decimales y por ello si se toma una aproximación del mismo
formada por sus m primeros decimales se está cometiendo un error de
redondeo que, operación tras operación, puede acabar siendo desastroso. En
efecto, trabajando en coma flotante, este hecho tendrá una influencia dramática
en el cálculo de las integrales posteriores mediante la fórmula de recurrencia
dada.

Comprobémoslo con ayuda de MAPLE y trabajando con una precisión de 7


dígitos significativos en el cálculo de los valores aproximados de las integrales
(que llamaremos AP) y con 15 dígitos en la estimación de los errores absolutos
(que llamaremos eabs) y de los relativos (que llamaremos errel)

> n:=15;
n := 15
> AP:=vector(n,[]);
A:=vector(n,[]);
eabs:=vector(n,[]);
errel:=vector(n,[]);
AP := array ( 1 .. 15, [ ] )
A := array ( 1 .. 15, [ ] )
eabs := array ( 1 .. 15, [ ] )
errel := array ( 1 .. 15, [ ] )
En el valor de partida ya se comete un error al considerar sólo 7 dígitos significativos
del valor (1/e):
> A[1]:=1/exp(1);AP[1]:=evalf(1/exp(1),7);

2
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

1
A1 :=
e
AP1 := 0.3678794

> eabs[1]:=evalf(A[1]-AP[1],15);
eabs1 := 0.41171442 10 -7

> errel[1]:=evalf(abs(eabs[1]/A[1]),15);
errel 1 := 0.111915582640056 10 -6

Para la segunda integral se tiene que:


> A[2]:=1-2*A[1];AP[2]:=evalf(1-2*AP[1],7);
2
A2 := 1 −
e
AP2 := 0.2642412

> eabs[2]:=evalf(A[2]-AP[2],15);
eabs2 := -0.82342884 10 -7

> errel[2]:=evalf(abs(eabs[2]/A[2]),15);
errel 2 := 0.311620253237233 10 -6

Para la tercera:
> A[3]:=1-3*A[2];AP[3]:=evalf(1-3*AP[2],7);
6
A3 := −2 +
e
AP3 := 0.2072764

> eabs[3]:=evalf(A[3]-AP[3],15);
eabs3 := 0.24702865 10 -6

> errel[3]:=evalf(abs(eabs[3]/A[3]),15);
errel 3 := 0.119178235243190 10 -5

Podríamos ahora repetir el proceso para el cálculo de la cuarta integral, de la quinta


integral , ... hasta llegar a calcular la décimoquinta. Como escribir quince veces este
proceso es un poco "pesado" vamos a ver cómo podemos hacer que MAPLE lo realice
automáticamente

Hay una forma cómoda de obtener todos los valores que se nos piden. Esta forma
consiste en definir una estructura repetitiva (o bucle). En estos bucles se considera
una variable de control (vc) a la que inicialmente se le asigna un valor inicial (vinic), y
para la que se definen un valor final (vfin) y un incremento (incr). Las operaciones que
se incluyen en el bucle son realizadas en primer lugar para la variable de control
tomando el valor vinic. Una vez realizadas vuelven a repetirse para la variable de

3
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

control tomando el valor (vinic + incr). Tras ello se vuelven a repetir tomando la
variable de control el valor (vinic + 2 · incr). Y así sucesivamente hasta que la variable
de control tome un valor que sobrepase a vfin, en cuyo momento dejan de realizarse
las operacones incluidas dentro del bucle. Dos cosas importantes sobre los bucles son
que:
a) El valor final (vfin) debe poder alcanzarse incrementando las veces que sea
necesario "vinic" con el valor del incremento "incr". En caso contrario MAPLE te
indicará que hay un error.
b) La variable de control del bucle puede utilizarse en las operaciones del bucle.

Con ello, una estructura típica de un bucle es:

Para "vc" desde "vinic" hasta "vfin" con incremento "incr" hacer:
Operaciones a realizar
Fin del bucle.

Esto en MAPLE se escribe


for vc from vinic to vfin by incr do
Instrucciones de MAPLE que se quieren repetir
od;

Ilustrémoslo en el cálculo de los valores aproximados y exactos de las


integrales que queríamos calcular:

> for i from 2 to n by 1 do


A[i]:=1-i*A[i-1]:
AP[i]:=evalf(1-i*AP[i-1],7);
eabs[i]:=evalf(A[i]-AP[i],15);
errel[i]:=evalf(abs(eabs[i]/A[i]),15);
od:

Observa que al haber finalizado el bucle con dos puntos (:) no se han escrito los
valores calculados. Si queremos verlos podemos decirle a MAPLE que nos los escriba
con ayuda de otro bucle y de la instrucción print( ). Esto es lo que haremos a
continuación. Además, para que sea más facil la comparación escribiremos sólo los 7
primeros dígitos significativos del valor exacto de las integrales calculadas.

> for i from 1 to n by 1 do


print(i,evalf(A[i],15),AP[i],eabs[i],errel[i]);
od;

4
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

1, 0.367879441171442 , 0.3678794 , 0.41171442 10 -7 , 0.111915582640056 10 -6


2, 0.264241117657116 , 0.2642412 , -0.82342884 10 -7 , 0.311620253237233 10 -6
3, 0.20727664702865 , 0.2072764 , 0.24702865 10 -6 , 0.119178235243190 10 -5
4, 0.17089341188539 , 0.1708944 , -0.98811461 10 -6 , 0.578205209374999 10 -5
5, 0.1455329405730 , 0.1455280 , 0.49405730 10 -5 , 0.0000339481424655319
6, 0.126802356562 , 0.1268320 , -0.000029643438 , 0.000233776712071639
7, 0.11238350407 , 0.1121760 , 0.00020750407 , 0.00184639259753596
8, 0.1009319675 , 0.1025920 , -0.0016600325 , 0.0164470438961769
9, 0.091612293 , 0.0766720 , 0.014940293 , 0.163081749301919
10, 0.08387707 , 0.2332800 , -0.14940293 , 1.78121302997351
11, 0.0773522 , -1.566080 , 1.6434322 , 21.2460951336872
12, 0.071773 , 19.79296 , -19.721187 , 274.771669012025
13, 0.06695 , -256.3085 , 256.37545 , 3829.35698282300
14, 0.0628 , 3589.319 , -3589.2562 , 57153.7611464968
15, 0.059, -53838.78 , 53838.839 , 912522.694915255

Podemos representar cómo evolucionan los valores calculados. Para que pueda
apreciarse en una misma gráfica lo que sucede con los valores exactos y aproximados
sólo representaremos los 11 primeros valores (pues para los sucesivos las escalas
entre los valores exactos y los aproximados son muy distintas).

Para dibujar una gráfica de puntos es necesario seguir 2 pasos:


1º) Crear una secuencia de puntos (con ayuda del comando de MAPLE seq( ) .
2º) Utilizar la instrucción de MAPLE pointplot( ) que sirve para dibujar puntos.

Examinemos con detalle ambos pasos.

Creación de una secuencia de puntos:


Debe usarse la instrucción seq(f(vc), vc=vinic..vfin) donde f es una expresión que
depende de la variable de control vc, y esta variable de control va tomando todos los
valores enteros comprendidos entre vinic y vfin. Si además deseamos que la
secuencia esté ordenada debemos almacenarla como LISTA (encerrándola entre
corchetes según se explicó ensesiones anteriores). Además es conveniénte
asignársela a algún nombre.
En nuestro caso, además, la expresión de f deben ser las coordenadas de los puntos
[i, A[i]]. Por eso nuestras secuencias a representar serán:

5
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

> pexac:=[seq([i,evalf(A[i],7)], i=1..11)]:


> papr:= [seq([i,AP[i]], i=1..11)]:

Dibujo de la secuencia de puntos:


Debe utilizarse la instrucción de MAPLE pointplot(secuencia, opciones de dibujo).
Esta instrucción se encuentra en la librería plots que no es cargada “por defecto” al
inicializar MAPLE y por ello, antes de usar la instrucción debemos proceder a cargar
la citada librería:

> with(plots):

> pointplot(pexac,color=blue,symbol=CROSS);

> pointplot(papr,color=red,symbol=DIAMOND);

6
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

Para dibujar ambas secuencias de puntos en una misma gráfica puede utilizarse la
sentencia display( ) ya vista en prácticas anteriores.
>
dibexac:=pointplot(pexac,color=blue,symbol=CROSS):dibapr:=p
ointplot(papr,color=red,symbol=DIAMOND):
> display(dibexac,dibapr);

7
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

Observa que los valores exactos (en azul) son siempre positivos y decrecientes en
tanto que los valores aproximados, en rojo, no son siempre positivos (caso n = 11 y
otros posteriores no representados) y su valor absoluto tampoco decrece (es más,
crece a partir de n = 10). Este hecho se refleja en las gráficas siguientes en las que se
representan los errores absolutos y realtivos cometidos)

> derabs:={seq([i,eabs[i]], i=1..n)}:


derrel:={seq([i,errel[i]], i=1..n)}:
> diberabs:=pointplot(derabs,color=blue,symbol=CROSS):
diberrel:=pointplot(derrel,color=red,symbol=DIAMOND):
> display(diberabs,title="ERRORES ABSOLUTOS");

> display(diberrel,title="ERRORES RELATIVOS");

8
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

En las gráficas anteriores los errores cometidos en las primeras aproximaciones no


son nulos. Simplemente son de un orden de magnitud muy inferior a los últimos. Si
deseamos representarlos deberemos crear las secuencias con menos puntos. Por
ejemplo, si creamos las de los 10 primeros valores podremos apreciar que la escala de
ordenadas se reduce y con ello apreciaremos lo que sucede con la evolución de los
primeros errores:
> derabs:={seq([i,eabs[i]], i=1..10)}:
derrel:={seq([i,errel[i]], i=1..10)}:
> diberabs:=pointplot(derabs,color=blue,symbol=CROSS):
diberrel:=pointplot(derrel,color=red,symbol=DIAMOND):
> display(diberabs,title="ERRORES ABSOLUTOS");

9
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

> display(diberrel,title="ERRORES RELATIVOS");

Otra forma de poner los errores de manifiesto es utilizar escalas logarítmicas como se
hace a continuación:

10
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

> derrel:={seq([i,log(errel[i])], i=1..n)}:


> diberrel:=pointplot(derrel,color=red,symbol=DIAMOND):
> display(diberrel,title="LOGARITMOS NEPERIANOS DE LOS
ERRORES RELATIVOS");

> fin;
fin

Acumulación de errores.
> restart;
La idea del enunciado de este ejercicio se ha recogido de [3].

La realización de muchos cálculos en los que el resultado de unos influya en los


que que le siguen puede conducir a resultados finales con una acumulación de
errores de redondeo suficientemente grande como para inutilizar el resultado de
todo el proceso de cálculo. Esta situación es la que se trata de ilustrar con el
siguiente ejemplo.

Considera la sucesión de números generada de la forma siguiente:


x[0]=1,
x[1]=1/3,
x[n] = (13 / 3)*x[n-1] - (4/3)*x[n-2] (n = 2, 3, ......)

11
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

a) Detemínese el valor de los 20 primeros términos de la sucesión.

b) Sabiendo que x[n] = (1/3)^n (se deja como ejercicio propuesto demostrarlo)
compárense los valores obtenidos en el apartado a) con los exactos.

NOTA: Utilícense en los cálculos 7 dígitos significativos.


Procedamos a definir el número de dígitos con los que se va a operar y a asignar el
valor de los dos primeros téminos de la sucesión tanto de los valores exactos x[i] como
de los aproximados xa[i]. Observa que para ello almacenamos los valores de la
sucesión como si fueran elementos de un vector, dirigiendonos a cada uno de ellos en
la forma x[indice] o xa[indice] respectivamente:

> Digits:=7;
Digits := 7
> x[0]:=1.;
xa[0]:=1.;
x[1]:=1./3.;
xa[1]:=1./3.;
x0 := 1.

xa0 := 1.

x1 := 0.3333333

xa1 := 0.3333333

Podemos ya calcular los valores siguientes. Así para x[2] y xa[2] procederíamos como
sigue:
> x[2]:=evalf((1/3)^2);
xa[2]:=(13./3.)*xa[1]-(4./3)*xa[0];
x2 := 0.1111111

xa2 := 0.111111

Para x[3] y xa[3]:


> x[3]:=evalf((1/3)^3);
xa[3]:=(13./3.)*xa[2]-(4./3)*xa[1];
x3 := 0.03703704

xa3 := 0.0370367

Para x[4] y xa[4]:


> x[4]:=evalf((1/3)^4);
xa[4]:=(13./3.)*xa[3]-(4./3)*xa[2];
x4 := 0.01234568

xa4 := 0.0123444

12
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

Para no ir calculando uno a uno los elementos de estas sucesiones, recurramos a la


realización de un bucle:

> n:=20;
n := 20
> for i from 2 to n by 1 do
x[i]:=evalf((1/3)**i):
xa[i]:=(13./3.)*xa[i-1]-(4./3.)*x[i-2]:
od:

Si deseas ver todos los valores calculados, así como la dferencia entre ellos, puedes
utilizar otro bucle como el que sigue:

> for i from 0 to n by 1 do


difer[i]:=x[i]-xa[i]:
errel[i]:=abs(difer[i]/x[i]):
print(i,x[i],xa[i],difer[i],errel[i]);
od:
0, 1., 1., 0., 0.
1, 0.3333333 , 0.3333333 , 0., 0.
2, 0.1111111 , 0.111111, 0.1 10 -6 , 0.9000001 10 -6
3, 0.03703704 , 0.0370367 , 0.34 10 -6 , 0.9179999 10 -5
4, 0.01234568 , 0.0123443 , 0.138 10 -5 , 0.0001117800
5, 0.004115226 , 0.00410925 , 0.5976 10 -5 , 0.001452168
6, 0.001371742 , 0.00134585 , 0.000025892 , 0.01887527
7, 0.0004572474 , 0.000345049 , 0.0001121984 , 0.2453779
8, 0.0001524158 , -0.000333777 , 0.0004861928 , 3.189911
9, 0.00005080526 , -0.002056030 , 0.002106835 , 41.46884
10, 0.00001693509 , -0.009112684 , 0.009129619 , 539.0948
11, 0.5645029 10 -5 , -0.03955603 , 0.03956168 , 7008.233
12, 0.1881676 10 -5 , -0.1714321 , 0.1714340 , 91107.08
13, 0.6272255 10 -6 , -0.7428799 , 0.7428805 , 0.1184391 10 7
14, 0.2090752 10 -6 , -3.219149 , 3.219149 , 0.1539709 10 8
15, 0.6969172 10 -7 , -13.94964 , 13.94964 , 0.2001621 10 9
16, 0.2323057 10 -7 , -60.44844 , 60.44844 , 0.2602107 10 10
17, 0.7743524 10 -8 , -261.9432 , 261.9432 , 0.3382739 10 11
18, 0.2581175 10 -8 , -1135.087 , 1135.087 , 0.4397559 10 12

13
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

19, 0.8603916 10 -9 , -4918.710 , 4918.710 , 0.5716827 10 13


20, 0.2867972 10 -9 , -21314.41 , 21314.41 , 0.7431875 10 14

Volviendo a nuestro objetivo inicial, puedes observar en los valores que se acaban de
escribir cómo van obteniendose dos sucesiones totalmente distintas en x[i] y en xa[i]
debido a la acumulación de los errores de redondeo.

Dibujémoslas. Como los últimos valores son muy dispares, y en una gráfica que
incluyese todos no se apreciaría la primera solución, dibujemos sólo los 13 primeros
valores:

> dibex:={seq([k,x[k]],k=0..13)}:
dibap:={seq([k,xa[k]],k=0..13)}:
dibdif:={seq([k,difer[k]],k=0..13)}:
diferr:={seq([k,log(errel[k])],k=0..13)}:
> with(plots):

> dbe:=pointplot(dibex, color=blue, symbol=CROSS,


font=[TIMES, BOLD, 12]):
dba:=pointplot(dibap, color=red, symbol=CIRCLE,
font=[TIMES, BOLD, 12]):
dbdif:=pointplot(dibdif, color=blue, symbol=CROSS,
font=[TIMES, BOLD,12]):
dberr:=pointplot(diferr, color=brown, symbol=CROSS,
font=[TIMES, BOLD,12]):

> display(dbe,dba,title="Valores exactos (azul) y


aproximados(rojo)");

14
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

> display(dbdif,title="Errores absolutos");

> display(dberr,title="Logaritmo neperiano de los errores


relativos");

15
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

Observa como el crecimiento de los errores acumulados nos conduce, para índices
"altos", a resultados que nada tienen que ver con los reales.

> fin_de_la_primera_parte_del_ejemplo;
fin_de_la_primera_parte_del_ejemplo

En el ejemplo anterior se ha puesto de manifiesto el problema de la acumulación


de errores que anulan la validez de los resultados de un proceso. Pero debe
señalarse además que el que esto suceda o no suceda depende no sólo de las
operaciones que se realicen sino también de la propia magnitud de los
resultados numéricos que se vayan obteniendo. Para ilustrar este hecho
repitamos el mismo ejercicio pero considerando ahora valores de partida
diferentes.
En efecto, considera ahora la sucesión de números dada de la forma siguiente:
x[0]=1, x[1]=4, x[n] = (13 / 3)*x[n-1] - (4/3)*x[n-2] (n = 2, 3, ......)
a) Detemínese el valor de los 20 primeros términos de la sucesión.
b) Sabiendo que x[n] = (4)^n (se deja como ejercicio propuesto demostrarlo)
compárense los valores obtenidos en el apartado a) con los exactos.
NOTA: Utilícense en los cálculos 7 dígitos significativos.

16
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

> restart;
> Digits:=7;
Digits := 7
> x[0]:=1.; x[1]:=4.;
xa[0]:=1.; xa[1]:=4.;
x0 := 1.

x1 := 4.

xa0 := 1.

xa1 := 4.

> n:=20;
n := 20
> for i from 2 to n by 1 do
x[i]:=evalf((4.)**i):
xa[i]:=(13./3.)*xa[i-1]-(4./3.)*x[i-2]:
od:
> for i from 0 to n by 1 do
difer[i]:=x[i]-xa[i]:
errel[i]:=abs(difer[i]/x[i]):
print(i,x[i],xa[i],difer[i],errel[i]);
od:
0, 1., 1., 0., 0.
1, 4., 4., 0., 0.
2, 16., 16.00000 , 0., 0.
3, 64., 64.00000 , 0., 0.
4, 256., 256.0000 , 0., 0.
5, 1024., 1024.000 , 0., 0.
6, 4096., 4096.000 , 0., 0.
7, 16384. , 16384.00 , 0., 0.
8, 65536. , 65536.00 , 0., 0.
9, 262144. , 262144.0 , 0., 0.
10, 0.1048576 10 7, 0.1048576 10 7, 0., 0.
11, 0.4194304 10 7, 0.4194304 10 7, 0., 0.
12, 0.1677722 10 8, 0.1677722 10 8, 0., 0.
13, 0.6710886 10 8, 0.6710888 10 8, -20., 0.2980232 10 -6
14, 0.2684355 10 9, 0.2684355 10 9, 0., 0.
15, 0.1073742 10 10, 0.1073742 10 10, 0., 0.

17
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

16, 0.4294967 10 10, 0.4294968 10 10, -1000., 0.2328307 10 -6


17, 0.1717987 10 11, 0.1717987 10 11, 0., 0.
18, 0.6871948 10 11, 0.6871948 10 11, 0., 0.
19, 0.2748779 10 12, 0.2748779 10 12, 0., 0.
20, 0.1099512 10 13, 0.1099511 10 13, 0.1 10 7, 0.9094944 10 -6
> dibex:={seq([k,x[k]],k=0..20)}:
dibap:={seq([k,xa[k]],k=0..20)}:
dibdif:={seq([k,difer[k]],k=0..20)}:
diferr:={seq([k,log(errel[k])],k=0..20)}:
> with(plots):

> dbe:=pointplot(dibex, color=blue, symbol=CROSS,


font=[TIMES, BOLD,12]):
dba:=pointplot(dibap, color=red, symbol=CROSS,
font=[TIMES, BOLD,12]):
dbdif:=pointplot(dibdif, color=green, symbol=CROSS,
font=[TIMES, BOLD,12]):
dberr:=pointplot(diferr, color=brown, symbol=CROSS,
font=[TIMES, BOLD,12]):

> display(dbe,dba,title="Valores exactos (azul) y


aproximados(rojo)");

18
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

> display(dbdif,title="Errores absolutos");

> display(dberr,title="Logaritmo neperiano de los errores


relativos");

Puedes observar que, ahora los errores relativos en las soluciones obtenidas son
"insignificantes". No sucede lo mismo con los errores absolutos (que llegan a ser de
hasta 10000000) pero al referirse a números muy elevados (del orden del billón) su
gravedad se relativizaconsiderablemente. Y ello es debido a que ahora se trabaja con
números de magnitud elevada.

19
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

> fin;
fin

Sumatorios
Calculemos la suma de los números naturales impares mayores o iguales a 1 e
inferiores a 500
> n:=500:
> suma:=0:
for i from 1 to n by 2 do
suma:=suma + i:
od:
> suma;
62500

Calculemos ahora por una parte la suma de los números enteros múltiplos de 6
superiores a 1 e inferiores 327.
> k:=327:
> suma6:=0:
for i from 6 to k by 6 do
suma6:=suma6 + i:
od:
> suma6;
8910

Como ves en los ejemplos anteriores, el cálculo de un sumatorio se comienza


"vaciando" (más precisamente, asignando el valor neutro de la suma) a la variable que
va a contener el valor final del sumatorio y acumulando en ella los sumandos uno tras
otro. En los ejemplos anteriores la propia variable de control del bucle juega el papel
del sumando.

NOTA1: MAPLE tiene una instrucción llamada sum para calcular sumatorios sin
necesidad de programar los bucles. En la ayuda de MAPLE puedes consultar su
funcionamiento y reglas. Nosotros sólo lo ilustramos con un ejemplo en el que
calculamos las suma de los 100 primeros números naturales.

> sum(j, j=1..100);


5050
NOTA 2: Un comando similar a sum es el comando add de MAPLE.
> add(j,j=1..100);
5050
> fin;
fin

20
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

Productorios
> restart;

Calculemos el producto de todos lo números pares mayores que 0 y


menores que 24

> producto:=1:
for i from 2 to 24 by 2 do
producto:=producto*i:
od:
> producto;
1961990553600

Calculemos ahora por una parte la suma de los números enteros múltiplos de 6
superiores a 1 e inferiores 49.

> m:=49:
producto6:=1:
for i from 6 to m by 6 do
producto6:=producto6*i:
od:
> producto6;
67722117120

Como ves en los ejemplos anteriores, el cálculo de un productorio se comienza


asignando el valor neutro de la multiplicación 8es decir 1) a la variable que va a
contener el valor final del productorio y acumulando en ella los factores uno tras otro.
En los ejemplos anteriores la propia variable de control del bucle juega el papel del los
distintos factores.
NOTA1: MAPLE tiene una instrucción llamada product para calcular sumatorios sin
necesidad de programar los bucles. En la ayuda de MAPLE puedes consultar su
funcionamiento y reglas. Nosotros sólo lo ilustramos con un ejemplo en el que
calculamos el producto de los 10 primeros números naturales

> product(k, k=1..10);


3628800

NOTA 2: Un comando de MAPLE similar al anterior es el comando mul.

> mul(k, k=1..10);


3628800
> fin;
fin

21
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

Operaciones con elementos de matrices y


vectores
Definamos la siguiente matriz

> restart;
> n:=5:
> A:=matrix(n,n,[[1,-2,3,-4,5],[3,6,9,12,15],[-2,-4,6,
8,10],[1,1,1,1,1],[5,0,0,5,0]]);
⎡ 1 -2 3 -4 5⎤
⎢ ⎥
⎢ 3 6 9 12 15⎥
⎢ ⎥
⎢ ⎥
A := ⎢⎢-2 -4 6 8 10⎥⎥
⎢1 1 1 1⎥⎥
⎢ 1
⎢ ⎥
⎢5 0 0 0⎥⎦
⎣ 5

Sumemos los elementos que están en filas impares y en columnas pares de


esa matriz

> suma:=0:
for i from 1 to n by 2 do
for j from 2 to n by 2 do
suma:=suma + A[i,j]:
od:
od:
> suma;
3

Como ves en los bucles anidados anteriores las variables de control han jugado
el papel de subíndices de los elementos de la matriz.

> fin;
fin

EJERCICIOS
Acumulación de errores de redondeo..
La SUCESIÓN GENERAL DE NÚMEROS DE FIBONACCI puede generarse mediante
la fórmula de recurrencia siguiente:
F[0]=1, F[1] = c, F[n]=F[n-1]+F[n-2] (n = 2, 3, .....)

Se pide obtener los n = 30 primeros términos de la sucesión de Fibonacci que se


genera con el valor c = (1-sqrt(5))/3
a) Trabajando en aritmética exacta

22
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

b) Aproximando el valor de c con 10 dígitos y realizando las operaciones con 10


dígitos.
c) Compárense ambos resultados, dibujándolos en gráficas de puntos, y extráiganse
las conclusiones pertinentes sobre la influencia de los errores de redondeo.
> restart;
>
>
>
>
>
>
>

Disminución de la influencia de los errores de


redondeo
El enunciado de este ejercicio se basa en uno de los ejemplos que se recogen en la
referencia [2].
El cálculo de los valores de las integrales:
1

An := ⌠

⎮ ex n (x − 1)
dx
⌡0

para n = 1, 2, …… El valor de estas integrales se realizó en el primer ejercicio


mediante la fórmula recursiva:

: Ai := 1 − i Ai − 1( i = 2 .. ∞ )
partiendo del valor (obtenido para n = 1):
1
A1 := = 0.36787944117144232160
e
Según se vio en dicho ejercicio, el error se iba acumulando de forma tal que los
valores que se obtenían para n suficientemente altos no tenían nada que ver con los
exactos.
Otra forma de calcular estas integrales consiste en proceder en retroceso estimando el
valor de la integral para un valor de n en función del valor obtenido para (n+1).
Concretamente:
1 − Ai + 1
Ai :=
i+1

Para n suficientemente elevado el valor de la integral An puede tomarse como nulo. A


partir de él puede estimarse mediante la expresión anterior el valor de An-1 . Y de este
el de An-2 y así sucesivamente. Se pide que,
a) tomando como valor aproximado de A50 el valor A50 = 0, calcules los valores de
A49, A48, A47, …., A1 utilizando en los cálculos 7 dígitos decimales, :

23
Programación y Métodos Numéricos. C. Conde, A. Hidalgo y A. López
Práctica 2 :Bucles y errores de redondeo ETSI Minas de la Univ. Politécnica de Madrid

b) compares con los valores exactos, y


c) Representes gráficamente la evolución de los errores relativos y absolutos,
comparando con los obtenidos en el primero de los ejemplos de esta práctica.

> restart;
>
>
>
>
>
>
>

24

También podría gustarte