Práctica 1. Errores de cancelación y redondeo. Acumuladores. Vectorización.
Veremos que la manera en que Matlab almacena los números puede dar lugar a errores. También usaremos bucles para implementar acumuladores de suma y de producto, y veremos como obtener estos acumuladores sin necesidad de usar bucles, sino comandos de Matlab para manejar vectores.
Contents
Errores de redondeo
Es sabido que en la recta real, entre dos puntos dados hay infinitos números reales. También es sabido que no existe el 'menor número que es estrictamente positivo'. Esto no ocurre en Matlab, ya que sólo puede representar un número finito de números.
Por defecto Matlab representa los números con precisión finita, es decir con cierta cantidad de cifras significativas y un exponente. (Como este exponente permite colocar el punto decimal en distintas posiciones se dice que la representación es en 'punto flotante'.)
Debido a esta precisión finita se pueden producir errores de redondeo al almacenar números y efectuar operaciones.
La función eps de Matlab permite hallar la distancia entre un número y el siguiente número en la representación interna en punto flotante. Con esta precisión finita, entre estos dos números no se puede representar ningún otro.
dis=eps(7) b=7+dis
dis =
8.8818e-16
b =
7.0000
Veamos que el número b es distinto del 7, pero entre el 7 y el b Matlab no puede representar ningún número. A continuación vemos que b es distinto de 7, pero c es igual a 7, aunque el número dis sea distinto de cero.
c=7+dis/2 b-7 c-7
c =
7
ans =
8.8818e-16
ans =
0
Errores de cancelación
Al restar cantidades muy próximas se pueden producir errores de cancelación que suponen la pérdida de cifras significativas correctas en los resultados.
Por defecto Matlab muestra sólo unos pocos decimales de los resultados. Para poder apreciar los errores de cancelación, usaremos el comando format long, que hace que muestre más decimales. (Para volver al formato usual con menos decimales usaremos format short)
pi
format long
pi
ans =
3.1416
ans =
3.141592653589793
Veamos en un ejemplo este fenómeno. Supongamos que los valores exactos de a1 y a2 son los que se pretenden asignar
a1=0.3333333333333298 a2=0.3333333333333187
a1 = 0.333333333333330 a2 = 0.333333333333319
Podemos ver que Matlab no nos muestra los valores que hemos introducido. En los valores mostrados las cifras 298 del número a1 han sido redondeadas a 300 lo cual es un error en la cifra decimocuarta. Las cifras 187 del número a2 han sido redondeadas a 190 lo cual es un error en la cifra decimoquinta.
a1 a2
a1 = 0.333333333333330 a2 = 0.333333333333319
Si restamos 'a mano' los valores exactos de a1 y a2, el resultado es 1.11e-014, sin embargo Matlab proporciona un valor cuya quinta cifra significativa es erronea. Observe como hemos pasado de errores en la cifra decimocuarta a errores en la quinta cifra.
a1-a2
ans =
1.110223024625157e-14
Veamos ahora otro ejemplo en el que los errores de cancelación se ven afectados por la multiplicación por números 'grandes'. Dado un valor x, consideraremos dos expresiones v1 y v2 que representan el mismo número, pero al calcular la primera se produce un error de cancelación. (Puede comprobar que, para x positivo, v1 y v2 representan al mismo número real si multiplica numerador y denominador de v2 por sqrt(x+1)-sqrt(x) y simplifica.)
x=15; v1=x*(sqrt(x+1)-sqrt(x)) v2=x/(sqrt(x+1)+sqrt(x))
v1 = 1.905249806888745 v2 = 1.905249806888747
Hallamos la diferencia entre v1 y v2. Observe que aunque ambas expresiones representan el mismo número real, el valor numérico de v1 es distinto del de v2.
v1-v2
ans =
-1.998401444325282e-15
Ej 1. Descargue de la web de la asignatura el script cancelacion.m para comprobar el error de cancelación que se produce al evaluar las expresiones v1 y v2. Ejecute el script para los valores x=19, 10^15, 10^20. (Sol. Errores = -3.9968e-015, 2.8151e+006, -5.0000e+009).
Usamos la instrucción format short para que los siguientes resultados se muestren con menos decimales.
format short
Acumulador (suma)
Ahora vamos a implementar un algoritmo sencillo en el que usamos un acumulador para calcular la suma de N números. (Estas instrucciones se encuentran en el archivo acumulador_suma.m )
% Definimos un vector que contiene los números que vamos a sumar x=[2 4 9 3 6 0 3 2 1 8 6 7 5] % Hallamos el número de elementos del vector N=length(x) % Inicializamos el acumulador s=0; % Sumamos al acumulador cada uno de los elementos del vector x for i=1:N s=s+x(i); end % Mostramos el resultado disp('La suma de las componentes es:') disp(s)
x =
2 4 9 3 6 0 3 2 1 8 6 7 5
N =
13
La suma de las componentes es:
56
Vectorización (suma)
En este caso se puede hallar la suma de las componentes del vector x de una forma más eficiente sin emplear un bucle for, usando la función sum.
sum(x)
ans =
56
Ej 2. Defina un vector llamado y que contenga las cifras de su DNI o pasaporte. Use un acumulador para hallar la suma de las componentes del vector y. Obtenga el mismo resultado usando la función sum.
Acumulador (producto)
De forma similar, implementamos el uso de un acumulador para calcular el producto de N números, y además dejaremos sin multiplicar los que sean nulos.
En este caso, el acumulador se inicializa con el valor 1, y dentro del bucle comprobaremos que las componentes a multiplicar sean distintas de cero.
% Definimos un vector que contiene los números que vamos a multiplicar v=[2 4 9 3 6 0 3 2 1 0 6 7 5] % Hallamos el número de elementos del vector N=length(v) % Inicializamos el acumulador p=1 % Multiplicamos el acumulador por cada uno de los elementos no nulos del vector v for i=1:N if v(i)~=0 p=p*v(i); end end % Mostramos el resultado disp('El producto de las componentes no nulas es:') disp(p)
v =
2 4 9 3 6 0 3 2 1 0 6 7 5
N =
13
p =
1
El producto de las componentes no nulas es:
1632960
Si empleamos el comando prod obtendremos el producto de todos los elementos, incluyendo los nulos.
prod(v)
ans =
0
Si queremos evitar los elementos nulos, debemos usar la función find que nos da los índices (las posiciones) de aquellos elementos no nulos.
Si observamos el vector v tenemos que son nulos los elementos sexto y décimo, y todos los demás son distintos de cero.
v
v =
2 4 9 3 6 0 3 2 1 0 6 7 5
Vectorización (producto)
Con esta instrucción obtenemos un vector con los índices de los elementos no nulos de v. Vemos que aparecen los números del 1 al 13, salvo el 6 y el 10.
find(v)
ans =
1 2 3 4 5 7 8 9 11 12 13
La siguiente instrucción halla los elementos de v no nulos.
vd=v(find(v))
vd =
2 4 9 3 6 3 2 1 6 7 5
Ahora podemos hallar el producto de los elementos no nulos de v.
prod(vd)
ans =
1632960
Si quisiéramos calcular el producto de los elementos no nulos de v con una sola instrucción, podríamos haber empleado la instrucción siguiente.
prod(v(find(v)))
ans =
1632960
La función find también sirve para encontrar los índices de los elementos que cumplan cierta condición. Por ejemplo, la siguiente instrucción nos da los índices de los elementos de v que son mayores estrictamente que 4.
find(v>4)
ans =
3 5 11 12 13
Ej 3. Halle el producto de todas las cifras de su DNI o pasaporte que sean menores o iguales que 5. Haga este ejercicio en primer lugar usando un bucle, y luego sin usar bucles. (Evidentemente, si en las cifras usadas hay algún 0 debe obtener un resultado nulo.)
Ej 4. Defina un vector con los números naturales del 10 al 60. Halle la suma de los elementos que sean mayores o iguales que 35. Haga este ejercicio en primer lugar usando un bucle, y luego sin usar bucles. (El resultado es 1235.)
% Matemáticas II. Grado en Ingeniería Química. (A. Palomares)
disp(date)
13-Feb-2017