Un método numérico es un procedimiento para aproximar la solución de un problema matemático:
En general, un método numérico debe ser capaz de aproximar la solución al problema matemático con tanta precisión como queramos. En la práctica, tanta precisión es innecesaria, y muy costosa. Todos los métodos numéricos deben aproximar la solución buscando un equilibrio entre:
En esta asignatura, hablaremos únicamente de los dos últimos tipos de error, pero es importante recordar que hay muchas fuentes de error:
Salvo en ejemplos de laboratorio, nunca podremos conocer exactamente el error, pero a veces podremos acotarlo.
A menudo son simplificaciones conscientes, cuyo efecto en la solución se puede estimar
Pero también a veces el error de modelo es muy difícil de estimar
Errores al sustituir un objeto matemático por otro más sencillo:
Si $x$ es el número que buscamos, $y$ es la aproximación:
Atención a las unidades de cada tipo de error.
Teorema de Taylor: Sea $f(x) \in C^{m+1}[a,b]$, $x_0 \in [a,b]$.
Para cualquier $x \in (a,b)$ existe un número $c = c(x)$ en el intervalo entre $x_0$ y $x$ tal que
$$ f(x) = T_N(x) + R_N(x)$$donde $T_N(x)$ es el polinomio de Taylor de $f$ de grado $N$ en $x0$:
$$T_N(x) = \sum^N_{n=0} \frac{f^{(n)}(x_0)\cdot(x-x_0)^n}{n!}$$y $R_N(x)$ es el error de Taylor
$$R_N(x) = \frac{f^{(n+1)}(c) \cdot (x - x_0)^{n+1}}{(n+1)!}$$Es un error de truncamiento, independiente de cuántos dígitos de precisión usemos para representar los números reales.
El error de truncamiento se puede acotar si podemos acotar la derivada $f^{(n+1)}(c)$ por una constante $M$:
$$ R_N(x) = \frac{f^{(n+1)}(c) \cdot (x-x_0)^{n+1}}{(n+1)!} \leq M (x-x_0)^{n+1} $$$f(x) = e^x$, $x_0 = 0$
Podemos acotar el error que comete la aproximación $T_2$, en función de $x$.
Derivadas: $$\begin{aligned} f'(x) &= e^x \\ f''(x) &= e^x \\ f^{(n)}(x) &= e^x \end{aligned}$$
Polinomios de Taylor: $$\begin{aligned} T_N(x) &= \sum^N_{n=0} e^0 \frac{x^n}{n!} \Rightarrow \\ T_2(x) &= 1 + x + \frac{x^2}{2} \end{aligned}$$
Restos (usando $e<3$): $$\begin{aligned} R_N(x) &= e^c \frac{x^{n+1}}{(n+1)!}\Rightarrow \\ R_2(x) &= e^c \cdot \frac{x^3}{6} \leq \frac{e^x}{6} \end{aligned}$$
Es decir, aproximamos $e^1 = 2.718$ por $T_2(1) = 2.5$, y sabemos que comete un error menor que $\frac{e^1}{6}<0.5$. En realidad, el error es menor.
Un sistema de números de coma flotante, representa algunos números reales en la forma siguiente:
$$F = \pm d_1 . d_2 d_3 d_4 \ldots d_p \times \beta^E$$donde
El desbordamiento ocurre cuando el resultado de una operación es:
undefined
.s EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF
0 1 8 9 31
Overflow $= 2^{127} \approx 3.4 \times 10^{38}$
Underflow $= 2^{-126} \approx 1.2 \times 10^{-38}$
$\epsilon_{\text{machine}} = 2^{-23} \approx 1.2 \times 10^{-7}$
s EEEEEEEEEE FFFFFFFFFF FFFFFFFFFF FFFFFFFFFF FFFFFFFFFF FFFFFFFFFF FF
0 1 11 12 63
Overflow $= 2^{1024} \approx 1.8 \times 10^{308}$
Underflow $= 2^{-1022} \approx 2.2 \times 10^{-308}$
$\epsilon_{\text{machine}} = 2^{-52} \approx 2.2 \times 10^{-16}$
Cuando queramos distinguir las operaciones con números reales de las operaciones en el sistema de coma flotante, usaremos $\ominus$ para la resta, $ \oplus$ para la suma, etc.
Se pueden definir de esta forma:
Si los operandos $x$ e $y$ no son representables en el sistema, hay que definir:
Elegimos un $\delta$ más pequeño que el $ \epsilon_{\text{machine}}$ (el número positivo más pequeño del sistema):
$$1\oplus \delta \ominus 1 = (1\oplus \delta) \ominus 1 = 0$$
$$1 \ominus 1 \oplus \delta = (1 \ominus 1) \oplus \delta = \delta$$
eps
eps
1 + eps - 1
1 - 1 + eps
'Ahora con un número menor que el epsilon de la máquina'
eps/2
1 + eps/2 - 1
1 - 1 + eps/2
Si el ejemplo anterior era "inofensivo", observa qué ocurre cuando restamos números que son casi iguales.
Supóngase $x$ e $y$ dos números casi iguales con $x>y$, con sus representaciones en coma flotante de $k$ dígitos $$ \begin{align} fl(x)=0.d_1d_2\ldots d_p\alpha_{p+1}\alpha_{p+2}\ldots \alpha_{k}\times10^n \nonumber \\ fl(y)=0.d_1d_2\ldots d_p\beta_{p+1}\beta_{p+2}\ldots \beta_{k}\times10^n \nonumber \end{align} $$ Al restarlos $x\ominus y$: $$ fl(fl(x)-fl(y))=0.\sigma_{p+1}\sigma_{p+2}\ldots\sigma_{k}\times10^{n-p} $$ con $$ 0.\sigma_{p+1}\sigma_{p+2}\ldots\sigma_{k}=0.\alpha_{p+1}\alpha_{p+2}\ldots\alpha_{k}-0.\beta_{p+1}\beta_{p+2}\ldots\beta_{k} $$ La resta sólo tiene $k-p$ dígitos de precisión, aunque los operandos tenían $k$ dígitos de precisión.
Calculamos $f(x) = x + 1$ mediante $$F(x) = \frac{x^2 - 1}{x - 1}$$, y dibujamos el error $|f-F|$.
x = linspace(0.9, 1.1, 1001);
f_hat = (x.^2 - 1.0) ./ (x - 1.0);
plot(x, abs(f_hat - (x + 1.0)));
xlabel("$x$")
ylabel("Absolute Error")
Veremos que varias técnicas numéricas con mucha tradición se basan en polinomios de grado alto.
Pero evaluar un polinomio de grado alto introduce errores numéricos:
$$f(x) = x^7 - 7x^6 + 21 x^5 - 35 x^4 + 35x^3-21x^2 + 7x - 1$$
x = linspace(0.988, 1.012, 1000);
y = x.^7 - 7.0 * x.^6 + 21.0 * x.^5 - 35.0 * x.^4 + 35.0 * x.^3 - 21.0 * x.^2 + 7.0 * x - 1.0;
plot(x, y, 'r')
xlabel("x")
ylabel("y")
En este caso, el ruido numérico disminuye si evaluamos el polinomio de otra forma.
Esta evaluación anidada requiere algunas operaciones menos y acumula menos error que la evaluación naive de un polinomio.
El orden al hacer las operaciones importa.
x = linspace(0.988, 1.012, 1000);
y = ((((((x - 7.0).*x + 21.0).*x - 35.0).*x + 35.0).*x - 21.0).*x + 7.0).* x - 1.0;
plot(x, y, 'r')
xlabel("x")
ylabel("y")
En general tendremos que lidiar con los dos tipos de error a la vez. Con suerte, un error predomina, lo que simplifica el análisis, pero en general, los errores se propagan, se acumulan y a veces se amplifican.
Aproximamos la derivada de $f(x) = e^x$ en $x=1$ por la diferencia:
$$f'(x) \approx \frac{f(x + \Delta x) - f(x)}{\Delta x}$$Comparamos el error cuando $\Delta x$ decrece, entre la aproximación y la respuesta correcta $f'(1) = e$.
n = 60;
delta_x = zeros(1,n);
for i = 1:n
delta_x(i) = 2^(-i);
end
x = 1.0;
f_hat = (exp(x + delta_x) - exp(x)) ./ (delta_x);
loglog(delta_x, abs(f_hat - exp(1)), 'o-')
xlabel("Delta x")
ylabel("Absolute Error")