Cálculo Numérico Avanzado J. Javier Segura Sala 1 February 25, 2004 1 Depto. de Matemáticas, Estadı́stica y Computación. Universidad de Cantabria ii Contents 1 La importancia de saber resolver numéricamente ecuaciones diferenciales de la Fı́sica 1.1 Ejemplo 1: un péndulo para empezar . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Ejemplo 2: oscilaciones en un circuito eléctrico . . . . . . . . . . . . . . . . . . . 1.3 Ejemplo 3: distribución de temperaturas en una placa . . . . . . . . . . . . . . . 1.4 Ejemplo 4: propagación de la luz en un medio isótropo . . . . . . . . . . . . . . . 1.5 Ejemplo 5: ecuación de Schrödinger dependiente del tiempo... . . . . . . . . . . . 1.6 ... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.7 ...Ejemplo n:.... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Sistemas de numeración; errores y sus fuentes 2.1 Sistemas de números y conversiones . . . . . . . . . . . . . . . . 2.1.1 Sistemas de numeración en base q . . . . . . . . . . . . . 2.1.2 Conversión de base decimal a base q . . . . . . . . . . . . 2.1.3 Estándar IEEE de representación de números enteros y en 2.2 Errores y sus causas . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.1 Definiciones . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.2 Fuentes de errores . . . . . . . . . . . . . . . . . . . . . . 2.3 Propagación de errores: condición y estabilidad. . . . . . . . . . . 2.4 Eficiencia de un algorı́tmo numérico . . . . . . . . . . . . . . . . 2.4.1 Ejemplo: Evaluación de polinomios, método de Horner . . . . . . . . . . . . . . . . . . . . . . . . . . coma flotante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 4 5 6 8 8 8 9 9 9 10 12 14 15 15 18 20 21 Tema 1. La importancia de saber resolver ecuaciones diferenciales numéricamente J. Javier Segura Sala 2 1 La importancia de saber resolver numéricamente ecuaciones diferenciales de la Fı́sica Este curso de análisis numérico está dedicado al estudio de métodos numéricos para la resolución de ecuaciones diferenciales ordinarias y ecuaciones diferenciales en derivadas parciales. ¿Por qué es importante su estudio en una licenciatura de Fı́sica?. La respuesta es obvia: las ecuaciones diferenciales son la expresión matemática (simplificada) de gran parte de fenómenos y problemas fı́sicos. Para nuestra desgracia la mayorı́a de estas ecuaciones no se pueden resolver analı́ticamente en términos de funciones “sencillas”, de modo que debemos recurrir a métodos numéricos para su resolución. Como muestra, unos pocos ejemplos seleccionados cuya resolución abordaremos en la parte práctica del curso. 1.1 Ejemplo 1: un péndulo para empezar El péndulo es probablemente el sistema dinámico más estudiado de todos los tiempos. La ecuación diferencial que describe su movimiento en ausencia de rozamiento y fuerzas externas es mL d2 θ = −mg sin(θ) , dt (1.1) siendo θ el ángulo formado por el péndulo con respecto a la vertical, m su masa, L su longitud y g la aceleración debida a la gravedad. Habitualmente se estudia el péndulo aproximándolo por una simple ecuación lineal (sin(θ) ≈ θ), que es aproximadamente válido para pequeñas amplitudes de oscilación. La ecuación (1.1) se puede resolver analı́ticamente en términos de integrales elı́pticas, que son funciones para la que existen eficientes métodos numéricos. El procedimiento es, en lugar de resolver directamente d2 θ + ω02 sin(θ) , ω0 = g/L (1.2) dt2 tener en cuenta que 1 E= 2 dθ dt 2 3 − ω02 cos θ (1.3) Tema 1. La importancia de saber resolver ecuaciones diferenciales numéricamente es una constante de movimiento. Integrando esta constante de movimiento podemos obtener θ(t) en términos de una integral conocida (integral elı́ptica) que el propio MATLAB incluye (ası́ como casi cualquier librerı́a cientı́fica). Sin embargo, un péndulo moviéndose en ausencia de rozamiento es una simplificación excesiva del sistema. Si añadimos un término de rozamiento y una fuerza externa, la ecuación presenta ahora el siguiente aspecto mL d2 θ dθ +γ + mg sin(θ) = A cos(2πfd t) , dt dt (1.4) siendo γ la constante de rozamiento, A la amplitud de la fuerza y f d , la frecuencia de ésta. Esta ecuación no puede ser resuelta, en general, de forma analı́tica en términos de una integral “simple” y deberemos acudir a alguno de los métodos numéricos de resolución de EDOs que estudiaremos en el curso. 1.2 Ejemplo 2: oscilaciones en un circuito eléctrico La ecuación de van der Pol es un modelo para un circuito eléctrico que formaba parte de las radios antiguas. Este circuito se remonta a los dı́as en que se utilizaban tubos de vacı́o. El tubo actúa como un resistor normal cuando la corriente es elevada y lo hace como un resistor negativo cuando la corriente es baja. Por tanto, este circuito aumenta las pequeñas oscilaciones y disminuye las grandes. Este comportamiento es caracterı́stico de los denominados osciladores de relajación. La ecuación que describe este sistema es: d2 i di 2 2 − µ dt (1 − i ) + i = 0 dt (2.5) siendo µ un parámetro caracterı́stico del sistema. Como ocurrı́a con el oscilador forzado del ejemplo 1, esta ecuación no es resoluble analı́ticamente si µ 6= 0. De hecho, la influencia del parámetro µ en el comportamiento de las soluciones de esta EDO es muy acusada. Veremos que esta ecuación es prototipo de los denominados problemas stiff (rı́gidos) cuando los valores de µ son grandes. Este tipo de problemas requerirán métodos especı́ficos para que puedan resolverse de forma eficiente. J. Javier Segura Sala 4 Cálculo Numérico Avanzado 1.3 Ejemplo 3: distribución de temperaturas en una placa Supongamos que nos interesa encontrar la distribución de temperaturas u(x, y) en la placa que se muestra en la figura: 1 0.8 0.6 0.4 R1 0.2 0 −0.2 −0.4 −0.6 −0.8 −1 −1.5 −1 −0.5 0 0.5 1 1.5 con unas condiciones de contorno determinadas (por ejemplo, temperatura constante T en los bordes superior e inferior (BS,BI) y sin pérdidas de calor en los bordes laterales (BL)) y con una fuente de calor f (x, y) en el interior de la placa (I). El problema a resolver se aproxima por la siguiente ecuación en derivadas parciales: 2 ∂ u ∂2u ∂x2 + ∂y 2 = f (x, y) en I u = T en BS, BI ∂u = 0 en BL ∂n (3.6) siendo n la dirección normal al borde en cuestión. Éste es un problema de tipo elı́ptico con condiciones de contorno Dirichlet y Neumann. Es un problema estático: asumimos que no hay dependencia temporal en las variables del sistema. Dada la geometrı́a regular del sistema, veremos que un método numérico apropiado para resolver esta EDP será un esquema de diferencias finitas. En la siguiente figura se muestra la resolución de uno de estos problemas estáticos de temperaturas para un caso en el que se puede encontrar solución analı́tica (lo que no es lo habitual). 5 Cálculo Numérico Avanzado. J. Segura Tema 1. La importancia de saber resolver ecuaciones diferenciales numéricamente Sobre este caso volveremos en las clases prácticas. Si la placa tuviese una geomeotrı́a irregular, como la que se muestra en la siguiente figura, optaremos por el método de elementos finitos. Al estudio de este método dedicaremos una parte importante del curso. 1 0.8 0.6 0.4 0.2 0 P1 −0.2 −0.4 −0.6 −0.8 −1 −1.5 1.4 −1 −0.5 0 0.5 1 1.5 Ejemplo 4: propagación de la luz en un medio isótropo La luz monocromática en un medio isótropo con una permitividad que varı́a poco, se describe mediante la ecuación de Helmholtz: −∆E = k02 E (4.7) donde E representa cualquier componente del campo eléctrico y k 0 = 2π/λ es el número de J. Javier Segura Sala 6 Cálculo Numérico Avanzado ondas del vacı́o. Supongamos que E es, de forma aproximada, una onda plana que se propaga en una dirección que llamaremos z, de forma que podamos escribir E(t, x, y, z) = u(x, y, z)eiβz−iωt En estas condiciones, sustituyendo en (4.7) y asumiendo que se puede despreciar el término en uzz obtenemos: iuz = −uxx − uyy + (β 2 − k02 )u 2β (4.8) que es la ecuación de Fresnel. Suponemos que conocemos u(x, y, 0) = u 0 (x, y) y queremos obtener u(x, y, z) en z. Esta ecuación (de tipo parabólico) es un prototipo de problema de propagación. La siguiente gráfica muestra la resolución de uno de estos problemas (sin considerar propagación en el eje y. Representamos la amplitud en función de x y z (dirección de propagación). Otro ejemplo prototipo de este tipo de problemas es, como veremos, la ecuación del calor Ṫ = κ∆T , donde T (t, x) representa un campo de temperaturas. Se asume que el dato T (0, x) = T 0 (x) es conocido y se desea obtener T (t, x) para t > 0. Un aspecto importante a tener en cuenta será, como estudiaremos, los resultados de estabilidad para algunos algoritmos de métodos en diferencias aplicados a estas EDPs. Este análisis de estabilidad, debido a Von Neumann, nos permitirá entender el comportamiento numérico de estos algoritmos y nos ayudará en la selección de aquéllos que resulten más adecuados para el problema a abordar. 7 Cálculo Numérico Avanzado. J. Segura Tema 1. La importancia de saber resolver ecuaciones diferenciales numéricamente 1.5 Ejemplo 5: ecuación de Schrödinger dependiente del tiempo... La ecuación de Schrödinger dependiente del tiempo: ∂ψ(x, t) 1 d2 i = − + V (x) ψ(x, t) ∂t 2m dx2 (5.9) donde utilizamos unidades naturales para no escribir la constante de Planck, es “manejable” analı́ticamente para casos ideales (potenciales simples y combinación de pocos autoestados de energı́a), pero en general son necesarios métodos numéricos para estudiar cuantitativamente la propagación de paquetes de ondas. Ver [4] para una interesante discusión sobre la resolución de la evolución temporal de un paquete de ondas. Ver también [6] 1.6 ... 1.7 ...Ejemplo n:.... J. Javier Segura Sala 8 2 Sistemas de numeración; errores y sus fuentes En este tema se introducen los distintos sistemas de numeración y se describe cómo realizar la conversión entre distintos sistemas, ası́ como el estándar IEEE de representación de números en el sistema binario. A continuación, se introducen las nociones de error absoluto y relativo y se analizan las causas más frecuentes de error en un cálculo computacional, ilustrándolo con ejemplos. Finalmente, se introducen los conceptos de (in)estabilidad y condición. 2.1 Sistemas de números y conversiones Es necesario conocer como se representan los números enteros y decimales en formato digital para entender las limitaciones intrı́nsecas que nos encontraremos al programar un algoritmo numérico, tanto en cuanto a la mayor precisión alcanzable como en cuanto al rango de valores admisibles. Veremos además cómo un mı́nimo conocimiento del sistema de representación estándar sirve para evitar la aparición de desastrosos errores de programación (como bucles infinitos). 2.1.1 Sistemas de numeración en base q El sistema de numeración decimal es el sistema posicional de numeración más utilizado, que utiliza como base de numeración el 10 (dı́gitos 0...9). Como es bien sabido, se puede utilizar cualquier número natural mayor que 1 como base de numeración. Un número en base q se denota como (an an−1 ...a1 a0 .b1 b2 ...bk ...)q donde ai y bj pertenecen al conjunto de los q dı́gitos elementales. Estos q dı́gitos representarán valores desde 0 hasta q − 1. La conversión a decimales es, por definición: (an an−1 ...a1 a0 .b1 b2 ...bk ...)q = an q n + an−1 q n−1 + ... + a1 q + a0 q 0 +b1 q −1 + b2 q −2 + ... + bk q −k + ... (1.1) El sistema natural de numeración digital es el binario (base 2), utilizando sólo los dı́gitos 0 y 1. Ejemplo 2.1 Decimal: (123.25)10 = 1 × 102 + 2 × 101 + 3 × 100 + 2 × 10−1 + 5 × 10−2 . Binario (base 2) con 2 dı́gitos 0 y 1: 0 + 1 = 1, 1 + 1 = 10. 9 Tema 2. Sistemas de numeración. Errores y sus fuentes. (1011.01)2 = 1 × 23 + 0 × 22 + 1 × 21 + 1 × 20 + 0 × 2−1 + 1 × 2−2 = 11.25. Hexadecimal (base 16) tiene 16 dı́gitos: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E y F , que representan los valores desde 0 hasta 15 respectivamente. Por tanto: (7B.4)15 = 7 × 161 + B × 160 + 4 × 16−1 = 123.25. Los sistemas de numeración octal y hexadecimal, también son muy utilizados, en parte debido a que es muy sencilla su conversión a binario con la ventaja de que un mismo número se representa con menos cifras cuanto mayor es la base. 2.1.2 Conversión de base decimal a base q Ya sabemos como convertir un número en base q a base decimal (1.1). La conversión de base decimal a base q se base en el hecho de que, acudiendo a la definición (1.1) observamos que (eliminamos el subı́ndice 10 para números en base decimal): (an an−1 ...a1 a0 .b1 b2 ...bk ...)q × q = (an an−1 ...a1 a0 b1 .b2 b3 ...bk ...)q (an an−1 ...a1 a0 .b1 b2 ...bk ...)q × q −1 = (an an−1 ...a1 .a0 b1 b2 ...bk ...)q (1.2) Utilizaremos esto para obtener la conversión de un número en base 10 a base 2. Para esto, conviene separar la conversión de la parte entera (antes del punto decimal) de la fraccionaria (después del punto); observemos que un número entero es necesariamente entero en cualquier base y que un número fraccionario lo es en cualquier base. Conversión entera De (1.2) deducimos que: (an ...a0 )q −1 = (an ...a1 )q + (.a0 )q es decir, que (an ...a0 )q = (an ...a1 )q × q + (.a0 )q × q = (an ...a1 )q × q + (a0 )q (1.3) que es una identidad entre números, que podemos evaluar en cualquier base, y en particular en base 10 (obsérvese que de hecho mezclamos base números en distintas bases). Vemos pues que al dividir un número entero entre q el resto es el dı́gito menos significativo del número en base q. Dividiendo sucesivamente (hasta llegar al cociente 0) obtenemos los sucesivos dı́gitos del número en base q. J. Javier Segura Sala 10 Cálculo Numérico Avanzado Conversión fraccionaria A partir de (1.2) vemos que: (.b1 b2 ...bk )q × q = (b1 )q + (.b2 ...bk )q Vemos pues que la parte entera del resultado de multiplicar nuestro número por q es el primer dı́gito tras el punto decimal. Reteniendo la parte fraccionaria que resulta en cada paso y repitiendo sucesivamente el proceso, vamos obteniendo el resto de cifras tras el punto. Ejemplo 2.2 Escribamos (26.1)10 en base 2. 1. Parte entera. Dividiendo sucesivamente, tenemos que: 26 = 2 × 13 + 0 ; 13 = 2 × 6 + 1 ; 6 = 2 × 3 + 0 ; 3 = 2 × 1 + 1 ; 1 = 2 × 0 + 1 Leyendo de izquierda a derecha los números subrayados: (26) 10 = (11010)2 2. Parte fraccionaria. Multiplicando sucesivamente por dos y separando la parte fraccionaria: 0.1 × 2 = 0.2 ; 0.2 × 2 = 0.4 ; 0.4 × 2 = 0.8 ; 0.8 × 0.2 = 1.6 ; 0.6 × 2 = 1.2 ; 0.2 × 2 = ... Leyendo de izquierda a derecha tenemos los dı́gitos de la parte fraccionaria (subrayados) luego: (0.1)10 = (0.00011)2 donde las cifras subrayadas son las cifras periódicas. Obsérvese que el número 0.1 tiene infinitas cifras distintas de cero cuando se escribe en base 2 (se repiten indefinidamente desde la segunda a la quinta cifra fraccionaria). Sumando los resultados de la parte entera y la fraccionaria tenemos que (26.1)10 = (11010.00011)2 En el anterior ejemplo hemos aprendido que un número fraccionario con un número finito de dı́gitos en cierta base no tiene por qué tener un número finito en otra base. En efecto, (0.1) 10 es un número periódico con infinitas cifras cuando se escribe en base 2. Esto es importante puesto que en un procesador digital los números se almacenar en binario utilizando un número finito de cifras. Esto quiere decir que el número 0.1 no se representa exactamente en un ordenador. Esto hay que tenerlo en cuenta para evitar errores que conduzcan a bucles que se repiten indefinidamente. El siguiente algoritmo en Matlab es un ejemplo de bucle infinito, Algoritmo 2.3 Bucle infinito en precisión finita binaria: x=0; while x∼=10 (Nota: en Matlab esto significa x 6= 0) x=x+0.1; end 11 Cálculo Numérico Avanzado. J. Segura Tema 2. Sistemas de numeración. Errores y sus fuentes. Esto nos deberı́a prevenir de utilizar bucles que terminan cuando se alcanza cierto valor concreto de una variable que involucra números no enteros. Ejercicio 2.4 Si en la tercera lı́nea del anterior algoritmo cambiamos 0.1 por 0.125, ¿seguirı́amos teniendo un bucle infinito?. 2.1.3 Estándar IEEE de representación de números enteros y en coma flotante Números enteros Asumamos, como es común en la mayor parte de los procesadores, que cada palabra tiene una longitud de 32 bits, es decir, que cada número vendrá representado por 32 dı́gitos binarios. La forma más sencilla de representar un número entero es asignando uno de los 32 bits para designar el signo (0 para +, 1 para menos) y utilizando las 31 restantes posiciones para representar los dı́gitos del módulo del número entero. En consecuencia, el mayor número entero que se puede representar es 231 − 1. Éste es el estándar IEEE salvo porque, por lo general, no se suele reservar un bit para el signo, sino que se utiliza una ordenación distinta para guardar los enteros negativos. Sin embargo, en la práctica una y otra prescripción son prácticamente equivalentes. También pueden utilizarse enteros en longitud doble, utilizando dos palabras de 32 bits, con lo que se aumenta el rango de enteros admisibles. Números no enteros Para representar números con parte fraccionaria se utiliza el formato de punto (o coma) flotante. Esta representación es la correspondiente versión binaria de la conocida notación cientı́fica o exponencial para los números decimales: ±M × 10E , 1 ≤ M < 10 pero utilizando base 2: x = ±M × 2E , 1 ≤ M < 2 donde M es la mantisa y E el exponente. Inevitablemente el número de dı́gitos que se pueden almacenar de la mantisa y exponente es limitado. Hay dos tipos de precisión, la simple y la doble, que difieren en el número de bits de los que se dispone para almacenar las cifras; la distribución estándar es: 1. Precisión simple: 32 bits, de los cuales: (a) uno corresponde al signo, (b) 8 al exponente, luego −128 ≤ E ≤ 127 (2 × 128 = 2 8 ) (c) 23 a la mantisa J. Javier Segura Sala 12 Cálculo Numérico Avanzado 2. Precisión doble (a) uno para el signo (b) 11 al exponente (−1022 ≤ E ≤ 1023) (c) 52 para la mantisa Ejemplo 2.5 Veamos de forma simplificada como se guardarı́a el número 5.5 en precisión simple. Primero lo pasamos a binario: 5.5 = (101.1) 2 y normalizamos para que la mantisa 1 < M ≤ 2, de forma que 5.5 = (1.011)2 × 22 , que tiene exponente E = 2 (que se guardará en binario), signo + (bit 0) y mantisa 1.011. Normalmente, salvo para el caso del número cero, que se almacenan de distinta forma, el número delante del punto será siempre 1, por lo que no se suele almacenar. Ejemplo 2.6 El anterior es un ejemplo de un número decimal que se puede guardar de forma exacta en una palabra de 32 bits. Un ejemplo en el que esto no serı́a ası́ es el ya conocido caso de 0.1 = (0.00011)2 = (1.1001)2 ×2−4 , que necesariamente ha de redondearse antes de almacenarse; esquemáticamente (sin entrar en detalles de como se almacena el exponente), tendrı́amos, en precisión simple, la representación (recordemos que el 1 antes del punto decimal no se suele almacenar) 0|E = −4|10011001100110011001101 donde la 23a cifra tras el punto se ha redondeado a 1 porque la siguiente era 1. De esta forma, lo que realmente se almacena es: (1.10011001100110011001101)2 × 24 = 0.10000000149011611938 Esto muestra explı́citamente que, efectivamente, el algoritmo 2.3 es un bucle infinito. Debemos resaltar que la especificación del número de bits que se utilizan para almacenar mantisa y exponente es lo único que necesitamos para determinar cuales son los mayores y menores números que se pueden almacenar en coma flotante ası́ como la máxima precisión que se puede obtener. Veamos como obtener estos parámetros en el caso de doble precisión (que es la precisión utilizada por Matlab). Ejemplo 2.7 Obtener los números de “overflow” y “underflow” ası́ como la precisión máquina en doble precisión, es decir: 1. Obtener el mayor número entero positivo representable en formato de coma flotante en el caso de doble precisión (lı́mite de “overflow”) Puesto que el mayor exponente es 1023, el mayor número representable es (1.1....1) 2 × 21023 ' 1.8 × 10308 (hay 52 unos detrás del punto “decimal”). 13 Cálculo Numérico Avanzado. J. Segura Tema 2. Sistemas de numeración. Errores y sus fuentes. 2. Obtener el menor número entero positivo representable en formato de coma flotante en el caso de doble precisión (lı́mite de “overflow”). El menor decimal representable con 52 dı́gitos significativos binarios es (1.00...01) 2 × 10−1022 ' 2.23 × 10−308 . Sin embargo, el estándar IEEE admites números más pequeños, aunque tengan menos cifras significativas (es lo que llaman números sub-normales); estrictamente el número más pequeño representable en coma flotante es: (0.00..01) 2 × 2−1022 = 2−1074 ' 4.94 × 10−324 (52 dı́gitos tras la coma decimal). Para no perder dı́gitos significativos es mejor moverse en el rango (1/Nov , Nov ), donde Nov es el número de overflow Nov ' 2.23 × 10−308 . 3. Obtener la diferencia entre 1 y el menor número positivo mayor que 1 en coma flotante (épsilon-máquina). Obtener asimismo la diferencia entre 1 y el mayor número positivo menor que 1. El número que se nos pide es (1.0...01) 2 − (1.0...0)2 = (0.0...01)2 = 2−52 ' 2.2 × 10−16 . Este número representa el mejor error relativo que se puede manejar en doble precisión (definimos este conocido concepto a continuación). Este valor de épsilon-maquina significa que todos los números con 15 cifras significativas se pueden guardar de forma exacta en doble precisión y que ocurre lo mismo para la mayor parte de los números de 16 cifras. En cuanto a la diferencia entre 1 y el mayor número positivo menor que 1, esta es: (1.0..0)2 − (1.1...1)2 × 2−1 = 2−53 ' 1.1 × 10−16 Nota 2.8 Es importante tener en cuenta que Matlab trabaja en doble precisión aunque por defecto sólo muestre 5 cifras significativas. Para que el sistema muestre más cifras se puede utilizar el comando “format long”. Además de los detalles señalados hay otras caracterı́sticas fundamentales del estándar IEEE que no describiremos como son: 1. Redondeo correcto de la aritmética (volveremos más adelante sobre este punto) 1 . 2. Tratamiento de excepciones. Es decir, que un operación del tipo log(0.0) no da error e interrumpe la ejecución del programa, sino que se asigna un valor especial para representar esta excepción (para significar −∞). 3. Compatibilidad entre procesadores. Esta es por supuesto, una de las grandes ventajas de los estándares. 2.2 Errores y sus causas El análisis numérico trata de la construcción de métodos discretos para la resolución de problemas continuos. Esta discretización, que se presenta tanto en la representación numérica en 1 Un error en el “hardware” de punto flotante de los Intel Pentium (1994) le dio una considerable mala publicidad a la compañı́a. El problema fue solventado reemplazando los procesadores defectuosos J. Javier Segura Sala 14 Cálculo Numérico Avanzado un ordenador como en los propios algoritmos de cálculo, necesariamente implica la aparición de errores cuyo origen y propagación debemos estudiar 2 . 2.2.1 Definiciones Si xA es una aproximación del verdadero valor x T , definimos entonces: Error absoluto: Error relativo: Eabs = |xT − xA | Erel = |1 − xA |, si xT 6= 0. xT También se pueden utilizar estas definiciones con signo (es decir, sin el valor absoluto). El error relativo en ocasiones se expresa también en tanto por ciento. El error relativo mide el número de cifras significativas exactas de x A . Ası́, si 2Erel < 10−m , m ∈ N se dirá que xA tiene m cifras significativas exactas. 2.2.2 Fuentes de errores Las fuentes de error en un cálculo numérico pueden ser de variada naturaleza, algunas de ellas independientes del método numérico empleado. 1. Un métodos numérico para resolver determinado problema cientı́fico puede dar lugar a resultados erróneos si el modelo no es una fiel descripción de la realidad. 2. Un algoritmo numérico puede depender de ciertos datos de entrada (por ejemplo, datos fı́sicos) afectados de cierto error. Se debe vigilar que el método numérico no sea crucialmente dependiente de la exactitud de tales valores de entrada y que la precisión de estos valores sea suficiente para nuestros propósitos. En el caso en que el propio modelo fı́sico/matemático sea muy sensible a estos parámetros, tendremos un problema mal condicionado e imposible de resolver numéricamente de forma estable. 3. Los errores de programación son prácticamente inevitables durante la construcción de un método numérico. Una vez construido un algoritmo numérico que en apariencia funciona correctamente es necesario certificar su funcionamiento mediante todos los tests que estén a nuestro alcance. 2 No por ello se debe adoptar la visión reduccionista consistente en definir el análisis numérico como el área de la matemática que analiza los errores de cálculo 15 Cálculo Numérico Avanzado. J. Segura Tema 2. Sistemas de numeración. Errores y sus fuentes. 4. Errores en la aritmética de punto flotante: errores de redondeo, pérdida de cifras significativas por cancelaciones, problemas de “underflow/overflow”. Estos son los problemas derivados de la representación en punto flotante, en la cual se dispone de un número finito de bits para representar la mantisa y el exponente. Como ya vimos, esto limita tanto la mejor precisión relativa alcanzable (15-16 dı́gitos decimales en doble precisión) como el rango de valores disponible. Aunque la segunda de las limitaciones no suele presentar graves problemas, es necesario evitar la evaluación de cantidades demasiado grandes o pequeñas. La limitación de la precisión tiene por lo general mayores consecuencias. Por ejemplo, cuando se sustraen cantidades muy parecidas, el error relativo empeora drásticamente por pérdida de cifras significativas. 5. Errores de truncamiento o de discretización, inherentes al hecho de aproximar un problema continuo mediante una aproximación discreta. Por ejemplo, veremos que la regla trapezoidal sirve para aproximar integrales mediante: Z a b f (x)dx ≈ N −1 X h b−a (f (a) + f (b)) + h f (a + kh) ≡ S(h) , donde h = , h = (b − 1)/N 2 N k=1 El significado de “≈” es “aproximadamente”, lo cual significa que Z b f (x)dx = S(h) + (h) a donde (h) es el error de truncamiento, que es de esperar que sea menor cuanto menor sea h (N ∈ N lo mayor posible). Un cálculo explı́cito de los errores de truncamiento es al menos igual de difı́cil que el cálculo del problema original. Nos conformaremos con un conocimiento cualitativo de estos errores y con buscar acotaciones lo más finas posible. Trataremos de estimar los errores de truncamiento en cada algoritmo numérico que se presente. Discutamos en este punto acerca de los errores debidos a las limitaciones en la representación de punto flotante, en particular por lo que respecta a la precisión limitada del sistema Redondeo y pérdida de cifras significativas Puesto que la representación en coma flotante es limitada en cuanto al número de cifras significativas que se pueden almacenar, los números reales se redondearán a un determinado número de cifras (siempre utilizando el sistema de numeración binario) cuando el valor verdadero tenga más cifras de las que se pueden almacenar. J. Javier Segura Sala 16 Cálculo Numérico Avanzado Asimismo, tras cada operación aritmética se vuelve a redondear el resultado. En el estándar IEEE esto se hace de la mejor manera posible en el sentido de que el resultado de la operación aritmética está redondeado de forma que se almacena el valor más próximo al resultado exacto. Ası́, por ejemplo, supongamos que, para simplificar, la precisión fuese de tres dı́gitos binarios tras el punto (y no consideremos limitación en el exponente), si se suman los números en punto flotante x = (1.010)2 , y = (1.001)2 × 2−4 tenemos que el resultado exacto es (1.0101001) 2 que no serı́a un número en punto flotante (sólo disponemos de 3 posiciones tras el punto). El resultado IEEE serı́a redondear la última cifra, aumentándola si la siguiente fuese 1 y dejándola como está en otro caso. Ası́, x + y se almacenarı́a como (1.011) 2 . Otra posibilidad (menos recomendable) es, sin más, eliminar las cifras que no quepan (truncamiento). Esta desafortunada prescripción se utilizaba en los supercomputadores Cray, pero está en total deshuso. Aún cuando en el estándar IEEE se redondea al número en coma flotante más cercano, que es la opción más conveniente, es necesario estudiar como pueden afectar sucesivos redondeos al resultado de un algoritmo numérico. Por otra parte, la limitación en el número de bits para la mantisa tiene como consecuencia la posible pérdida de cifras significativas en ciertos cálculos donde dos cantidades tienden a cancelarse entre sı́ 3 . Para evitar este tipo de errores, es recomendable: a) O bien reescribir la fórmula en cuestión de modo que se eviten las restas de cantidades de la misma magnitud. b) O bien utilizar (cuando sea posible) un desarrollo de Taylor para aproximar la fórmula hasta la precisión requerida. Veamos algunos ejemplos en los que se da pérdida de cifras significativas Ejemplo 2.9 Obtener las raı́ces de x 2 − 106 x + 1. Enpuna modesta calculadora con 10 decimales y aplicando la archiconocida fórmula x = −b ± b2 − 4ac , vamos obteniendo los resultados: 2a p 106 ± 1012 − 4 106 ± 106 x= ' 2 2 que da x = 106 para la mayor raı́z y x = 0 para la menor. Es evidente que hemos perdido todas las cifras significativas para la menor raı́z. De hecho, la famosa fórmula deberı́a ser desterrada de cualquier método numérico. Es mucho mejor reescribir la solución de la ecuación de segundo grado como: p x1 = L/2a , x2 = 2c/L , L = −b − signo(b) b2 − 4ac 3 Un famoso y lamentable error de éste tipo fue el que motivó le fallo de los misiles Patriot para derribar los misiles Skud iraquı́es durante la guerra del golfo: se medı́an intervalos de tiempo restando tiempos desde el reinicio del sistema con la consiguiente pérdida progresiva de precisión 17 Cálculo Numérico Avanzado. J. Segura Tema 2. Sistemas de numeración. Errores y sus fuentes. De esta forma la mayor raı́z es como antes y en la calculadora la menor saldrı́a x = 10 −6 , cuyo error relativo respecto a la solución verdadera es ∼ 10 −12 . √ √ Ejemplo 2.10 Consideremos por ejemplo f (x) = ( x + 1 − x) para x > 0. √ Cuando√x es grande, se producen errores de redondeo importantes puesto que los valores de x + 1 y x se aproximan considerablemente. ¿Cómo evitarı́amos esta fuente de error?. Lo que podemos hacer es reescribir f (x) del siguiente modo: √ √ √ √ 1 x+1+ x f (x) = ( x + 1 − x) √ √ =√ √ . x+1+ x x+1+ x En la expresión resultante podemos apreciar que no se producen cancelaciones de cantidades de la misma magnitud. 1 − cos(x) . Cuando se evalúa g(x) para |x| << 1 se Ejemplo 2.11 Consideremos g(x) = x2 produce una pérdida considerable de cifras significativas. En este caso, para remediar el problema consideramos el desarrollo de Taylor de cos(x) entorno a 0. De este modo: 1 − [1 − x2 /2! + x4 /4! + ...] 1 x2 x4 ≈ − + . 2 4! 6! x2 Esta expresión es apropiada entonces para evaluar g(x) cuando x << 1. g(x) = Errores de overflow /underflow Aunque los lı́mites de overflow/underflow son considerablemente generosos, conviene escribir las expresiones que se utilicen de manera que se minimice esta posibilidad. Por ejemplo, es p 2 preferible calcular el módulo de un número complejo, z = x + iy, |z| = x + y 2 , como p |z| = |x| 1 + (y/x)2 De esta forma, no hay que elevar al cuadrado números que pueden ser muy grandes. De la misma forma, hay que tomar precauciones para calcular la argumento de un número complejo de manera que no se produzcan “overflows/underflows” en el cálculo de y/x. Ejercicio 2.12 Escribir un programa en Matlab que obtenga la representación polar de un número complejo dado z = reiθ , 0 ≤ θ < 2π, eliminando el riesgo de problemas de overflowunderflow. 2.3 Propagación de errores: condición y estabilidad. Un error en un cálculo numérico contamina las sucesivas evaluaciones. Esta propagación del error puede describirse en términos de dos conceptos relacionados, los de (in)estabilidad y condición. J. Javier Segura Sala 18 Cálculo Numérico Avanzado La condición de una función f (x) mide la sensibilidad de los valores de f (x) a pequeños cambios en x y se define como Erel (f (x)) C= Erel (x) donde Erel (f (x)) es el error relativo de f (x) para un error relativo E rel (x) en x. Entonces, como 4 f (xT ) − f (xA ) ' f 0 (xt )(xT − xA ) → Erel (f (x)) ' f 0 (xT ) (xT − xA ) f (xT ) luego f 0 (xT ) C ' xT f (xT ) Utilizaremos esta última expresión como definición de condición para funciones f (x) de una variable real. Definimos entonces los números de condición como 0 f (x) C(x) = x f (x) Cuando para un x dado 0 < C(x) < 1 para ese x se dirá que el problema (cálculo de f) está bien condicionado (y cuanto menor sea C mejor condicionado), mientras que si C(x) > 1 el problema estará mal condicionado. Si C(X) = 1, el error relativo se mantiene. √ x está bien condicionada, pues C(x) = 1/2, luego el error 2x2 2 En cambio f (x) = x − 1 está mal condicionada para x ' 1 pues C(x) = 2 x − 1 Ejemplo 2.13 La función f (x) = relativo se reduce. El concepto de condicionamiento se puede extender a situaciones más generales que la de una función de una variable continua. Por ejemplo, un problema clásico que involucra funciones de una variable discreta, es el estudio del condicionamiento de relaciones de recurrencia: Ejemplo 2.14 Las funciones de Bessel J n (x) satisfacen la relación de recurrencia: J n+1 (x) = −Jn−1 (x) + 2n x Jn (x), pero como las funciones de Bessel de segunda especia cumplen la misma relación y limn→∞ Jn (x)/Yn (x) = 0, el cálculo de las funciones J n a partir de J0 y J1 está mal condicionado, pues una pequeña perturbación en los datos iniciales J 0 y J1 contamina nuestra secuencia de funciones {Jn } con la secuencia {Yn }, que crece más rápido con n. Ası́, por ejemplo, empezando con los valores en precisión simple J 0 (2) = 0.22389078 y J1 (2) = 0.57672481, y aplicando la recurrencia obtenemos J 8 (2) = 4.00543213 × 10−5 que no tiene bien ni siquiera un cifra significativa: J 8 (2) = 2.2180 × 10−5 . 4 Recordemos el teorema del valor medio: Si g(x) continua en [a, b] y derivable en (a, b) entonces ∃c ∈ (a, b) : f (b) − f (a) = f 0 (c)(b − a) 19 Cálculo Numérico Avanzado. J. Segura Tema 2. Sistemas de numeración. Errores y sus fuentes. Un concepto relacionado, que no equivalente, es el de (in)estabilidad de un algoritmo, que describe la sensibilidad de un método numérico especı́fico respecto a los inevitables errores de redondeo cometidos durante su ejecución en aritmética de precisión finita. Observemos que la condición no depende de errores de redondeo pero que la estabilidad de un algoritmo sı́ depende del condicionamiento de la función que queramos evaluar. Un ejemplo puede servir para distinguir estos dos conceptos relacionados: √ √ Ejemplo 2.15 Dada la función f (x) = x + 1 − x, su número de condición es: 0 f (x) x = √ √ C(x) = x f (x) 2 x x+1 y vemos que C(x) < 1/2 para x > 0, luego la función está bien condicionada (su error relativo es menor que el error relativo en x). Sin embargo, √ el algorı́tmo para calcular x consistente en ir realizando las operaciones impli√ cadas en f (x) = x + 1 − x, a saber: 1. Input: x 2. y = x + 1 √ 3. f1 = x + 1 √ 4. f2 = x 5. f = f1 − f2 es inestable para x grande por culpa del paso 5 (hay cancelaciones entre números similares). Como sabemos, un algoritmo estable lo proporciona la siguiente reescritura de la función: 1 f (x) = √ √ x+1+ x 2.4 Eficiencia de un algorı́tmo numérico Por supuesto, cualquier algoritmo numérico sensato debe evitar ser inestable. Por otra parte, si existieran varios métodos para evaluar una misma función, entonces convendrá adoptar aquel método que sea más eficiente, es decir, más rápido. Con la mejora en proporción geométrica de la velocidad de los procesadores, podrı́amos estar tentados en despreocuparnos por la rapidez de cálculo. Esta es, sin embargo, una pésima filosofı́a: se trata de aprovechar los recursos para poder resolver problemas más complejos y no para resolver peor problemas simples. La eficiencia es y siempre será de importancia capital en el desarrollo de buenos métodos numéricos. La diferencia en tiempos de ejecución pueden llegar a ser muy considerables si ciertas operaciones elementales, que se pueden repetir miles y miles de veces, no se realizan con cuidado. J. Javier Segura Sala 20 Cálculo Numérico Avanzado Por ejemplo, para calcular x4 para cierto valor de x, es muy mala idea calcular x 4.0 (exponente en coma flotante); hay que tener cuidado en utilizar un exponente entero ya que los métododos de exponenciación en coma flotante son distintos que los de enteros y mucho más lentos; aún es mejor idea considerar el cálculo en dos pasos: x 2 = x ∗ x, x4 = x2 ∗ x2 , con lo que se economizar un producto frente a x4 = x ∗ x ∗ x ∗ x. 2.4.1 Ejemplo: Evaluación de polinomios, método de Horner Otro ejemplo notable (y por desgracia no suficientemente) conocido es la evaluación de polinomios. Por ejemplo, supongamos que nos planteamos evaluar el polinomio P (x) = 2 + 4x − 5x2 + 2x3 − 6x4 + 8x5 + 10x6 Contando con que cada potencia de exponente k entero cuente como k −1 productos, tendrı́amos que el número total de productos para evaluar el polinomio de forma directa es: 1 + 2 + 3 + 4 + 5 + 6 = 21 y el número de sumas es 6. Una forma mejor de proceder es ir calculando primero las potencias de forma sucesiva: x2 = x x , x 3 = x x 2 , x 4 = x x 3 , x 5 = x x 4 , x 6 = x x 5 con lo que sólo se añade una nueva multiplicación por potencia, par un total de 1 + 2 + 2 + 2 + 2 + 2 = 11 Pero aún se puede hacer mejor reescribiendo P (x) = 2 + x(4 + x(−5 + x(2 + x(−6 + x(8 + x10))))) con lo que sólo necesitamos 6 multiplicaciones (y el número de sumas no cambia). Vemos pues que para evaluar un polinomio de grado n en el que ninguno de los coeficientes es cero, se necesitan n(n + 1)/2 multiplicaciones por el primer método, 2n − 1 por el segundo y n para el tercero. De forma que se debe procurar utilizar el último método, particularmente cuando n es grande. Este método es además sencillo de programa, en efecto: Algoritmo 2.16 (Algoritmo de Horner o de división sintética) 21 Cálculo Numérico Avanzado. J. Segura Tema 2. Sistemas de numeración. Errores y sus fuentes. Algoritmo de Horner Dado el polinomio P (x) = a0 + a1 x + ... + an xn , an 6= 0 la evaluación de P (x) para cierto valor x = z se puede realizar en n pasos mediante (1) bn = an (2) bn−1 = an−1 + z ∗ bn (3) bn−2 = an−2 + z ∗ bn−1 ... (n) b0 = a0 + z ∗ b1 donde P (z) = b0 . Es fácil programa este algoritmo en forma de bucle, sobretodo si no nos interesan los cálculos intermedios. Ası́, se puede escribir: (1) b = an (2) Repetir mientras n > 0 (3) n = n − 1 (4) b = an + z ∗ b (5) Volver a (2) (6) p(z) = b. Esta forma de evaluar polinomios es mucho mejor que el método directo, especialmente para órdenes grandes. Dependiendo del órden de un polinomio y las veces que se repita el cálculo, será importante aplicar el método de Horner. J. Javier Segura Sala 22 Bibliography [1] Atkinson, K., Elementary Numerical Analysis (2nd. Ed), John Wiley & Sons, 1993. [2] Acton, F. S., Numerical Methods that work, Washington: The Mathematical Association of America, 1990. [3] Conte, S. D., de Boor, C., Elementary Numerical Analysis (An Algorithmic Approach), McGraw-Hill, 1981. [4] Koonin, S.E., D.C. Meredith, Computational Physics ( Fortran version), Addison-Wesley, 1990. [5] Press, W. H., S.A: Teukolsky, W.T. Vetterling y B.P. Flannery, Numerical recipes in Fortran 77, Cambridge University Press, 1992. [6] Segura, J., Fernández de Córdoba, P. Estudio numérico de la evolución de un paquete de ondas en mecánica cuántica. Revista Española de Fı́sica 7 (1993) 57–61. 23