Representación en Punto Flotante
Problema:
Calcular los números cuya representación en punto flotante de precisión doble es:
-
\[0 \, 10000000100\] \[0111110000000000000000000000000000000000000000000000\]
-
\[1\, 10000000010\] \[1011001000000000000000000000000000000000000000000000\]
Solución:
% Número 1 signo=0; exponente=(2^2+2^10)-1023; mantisa=2^-2+2^-3+2^-4+2^-5+2^-6; numero=(-1)^signo*2^exponente*(1+mantisa) %Número 2 signo=1; exponente=(2+2^10)-1023; mantisa=2^-1+2^-3+2^-4+2^-8; numero=(-1)^signo*2^exponente*(1+mantisa)
Resultado:
- Primer número: 47.5
- Segundo número: -13.53125
Representación IEEE de -17.25
Problema:
Escribe la representación normalizada en el estándar IEEE de doble precisión del número decimal -17.25.
Solución:
Resultado:
La representación IEEE 754 de -17.25 es:
- Signo: 1 (negativo)
- Exponente: 10000000011 (4 + 1023 = 1027)
- Mantisa: 0001010000000000000000000000000000000000000000000000
Verificación:
- 17.25 = 1.000101 × 2⁴
- El bit de signo 1 indica número negativo
- El exponente 4 se representa como 1027 (4 + 1023)
Comparación de Precisión
Problema:
¿Qué estimación es más precisa?
Solución:
% Calcular valores exactos valor_exacto1 = 9/11; valor_exacto2 = sqrt(18); % Aproximaciones dadas aprox1 = 0.818; aprox2 = 2.243; % Calcular errores relativos error_rel1 = abs((valor_exacto1 - aprox1)/valor_exacto1) error_rel2 = abs((valor_exacto2 - aprox2)/valor_exacto2) % Escritura con formato fprintf('9/11:\n'); fprintf('Valor exacto: %.15f\n', valor_exacto1); fprintf('Aproximación: %.3f\n', aprox1); fprintf('Error relativo: %.10f\n\n', error_rel1); fprintf('sqrt(18):\n'); fprintf('Valor exacto: %.15f\n', valor_exacto2); fprintf('Aproximación: %.3f\n', aprox2); fprintf('Error relativo: %.10f\n', error_rel2);
Resultado:
Análisis de precisión:
- 9/11 ≈ 0.81818181818181...
- Error relativo de 0.818: 2.22×10⁻⁴
- √18 ≈ 2.24360635350064...
- Error relativo de 2.243: 2.72×10⁻⁴
La aproximación de 9/11 = 0.818 es más precisa ya que tiene un error relativo menor.
Aproximaciones Históricas de π
Problema:
Calcular el error absoluto, el error relativo y el número de cifras significativas de las siguientes aproximaciones de π:
- p* = 22/7 (Antiguo Egipto, siglo XXVI a.C)
- p* = 223/71 (Arquímedes, Antigua Grecia, siglo III a.C.)
- p* = 3.14159 (Liu Hui, China, año 265)
- p* = 355/113 (Zu Chongzhi, China, año 480)
Solución:
% Definir las aproximaciones históricas aprox = [22/7, 223/71, 3.14159, 355/113]; nombres = {'Egipto', 'Arquímedes', 'Liu Hui', 'Zu Chongzhi'}; % Calcular errores for i = 1:length(aprox) error_abs(i) = abs(pi - aprox(i)); error_rel(i) = error_abs(i)/pi; % Escritura con formato %fprintf('\n%s:\n', nombres{i}); %fprintf('Aproximación: %.10f\n', aprox(i)); %fprintf('Error absoluto: %.10e\n', error_abs(i)); %fprintf('Error relativo: %.10e\n', error_rel(i)); end % Escritura sin formato [error_abs' error_rel']
Resultado:
Aproximación | Error Absoluto | Error Relativo |
---|---|---|
22/7 | 1.2644×10⁻³ | 4.0251×10⁻⁴ |
223/71 | 8.4897×10⁻⁵ | 2.7019×10⁻⁵ |
3.14159 | 2.6535×10⁻⁶ | 8.4445×10⁻⁷ |
355/113 | 2.6676×10⁻⁷ | 8.4889×10⁻⁸ |
Intervalo de Aproximación para √2
Problema:
Determina el mayor intervalo en el cual debe estar p* para que aproxime a √2 con un error menor que 10⁻².
Solución:
% Valor exacto de sqrt(2) valor_exacto = sqrt(2); % Error máximo permitido error_max = 1e-2; % Calcular límites del intervalo limite_inferior = valor_exacto * (1 - error_max); limite_superior = valor_exacto * (1 + error_max); % Visualización del intervalo x = linspace(limite_inferior-0.1, limite_superior+0.1, 1000); y = abs(x - valor_exacto)/valor_exacto; fprintf('Intervalo de aproximación:\n'); fprintf('Límite inferior: %.6f\n', limite_inferior); fprintf('Valor exacto: %.6f\n', valor_exacto); fprintf('Límite superior: %.6f\n', limite_superior); % Verificación p_test = [1.4, 1.41, 1.415, 1.42]; for i = 1:length(p_test) error_rel = abs(p_test(i) - valor_exacto)/valor_exacto; fprintf('\nPrueba p* = %.3f\n', p_test(i)); fprintf('Error relativo: %.6f\n', error_rel); fprintf('¿Dentro del intervalo? %s\n', ... error_rel < error_max ? 'Sí' : 'No'); end
Resultado:
Para un error relativo menor que 10⁻², p* debe estar en el intervalo:
Este intervalo garantiza que:
Sistema de Ecuaciones Lineales
Problema:
Resuelve el siguiente sistema con Matlab:
Una solución obvia es x₁ = x₂ = 1 y el sistema tiene infinitas soluciones (la segunda ecuación es la primera dividida por 10). ¿Qué sucede?
Solución:
% Definir el sistema A = [17 5; 1.7 0.5]; b = [22; 2.2]; % Mostrar la matriz aumentada fprintf('Matriz aumentada:\n'); disp([A b]); % Intentar resolver el sistema warning('off', 'MATLAB:nearlySingularMatrix'); x = A\b; fprintf('\nSolución computada:\n'); disp(x); % Verificar la solución difere = A*x - b; disp(difere)
Resultado:
El problema presenta inestabilidad numérica debido a:
- Las ecuaciones son linealmente dependientes (una es múltiplo de la otra)
- Pequeñas perturbaciones en los coeficientes producen grandes cambios en la solución
Aunque matemáticamente el sistema tiene infinitas soluciones, numéricamente es inestable debido a los errores de redondeo en la representación de punto flotante.
Estabilidad de Sucesiones Recursivas
Problema:
Se quiere calcular pₙ como (1/3)ⁿ para n>0 considerando p₀=1 usando dos métodos:
- Definiendo pₙ=(1/3)pₙ₋₁ para n>1
- Definiendo p₀=1 y p₁=1/3 y calculando para n>2:
\[p_n = \frac{10}{3}p_{n-1} - p_{n-2}\]
¿Alguno de los dos métodos es inestable?
Solución:
% Comparar ambos métodos para varios valores de n N = 20; % Número de términos a calcular % Método 1: pn = (1/3)pn-1 p1 = zeros(1,N); p1(1) = 1; % p0 for n = 2:N p1(n) = (1/3) * p1(n-1); end % Método 2: pn = (10/3)pn-1 - pn-2 p2 = zeros(1,N); p2(1) = 1; % p0 p2(2) = 1/3; % p1 for n = 3:N p2(n) = (10/3)*p2(n-1) - p2(n-2); end % Valores exactos para comparación p_exact = (1/3).^(0:N-1); % Calcular errores relativos err1 = abs((p1 - p_exact)./p_exact); err2 = abs((p2 - p_exact)./p_exact); % Mostrando resultados con formato fprintf('n\tMétodo 1\tMétodo 2\tExacto\n'); fprintf('-------------------------------------------\n'); for n = 1:N fprintf('%d\t%.2e\t%.2e\t%.2e\n', ... n-1, p1(n), p2(n), p_exact(n)); end
Resultado:
Análisis de estabilidad:
- El primer método es estable: el error se mantiene acotado y los resultados son precisos
- El segundo método es inestable:
- Los errores crecen exponencialmente
- La recursión amplifica los errores de redondeo
- Los resultados se desvían significativamente de los valores exactos
Suma de Series en Diferentes Órdenes
Problema:
Evaluar la serie armónica hasta 10 millones de términos:
Calcular primero en orden usual y luego en orden opuesto. Explicar las diferencias obtenidas e indicar cuál es el resultado más preciso.
Solución:
% Parámetros N = 10000000; % Suma en orden ascendente suma_asc = 0; for n = 1:N suma_asc = suma_asc + 1/n; end % Suma en orden descendente suma_desc = 0; for n = N:-1:1 suma_desc = suma_desc + 1/n; end % Mostrar resultados fprintf('Suma en orden ascendente: %.15f\n', suma_asc); fprintf('Suma en orden descendente: %.15f\n', suma_desc);
Resultado:
Análisis de los resultados:
- La suma en orden descendente es más precisa porque:
- Suma primero los términos más pequeños
- Minimiza la pérdida de precisión por cancelación
- Reduce el error de redondeo acumulado
- Diferencias observadas:
- La suma ascendente pierde precisión en términos pequeños
- Los errores de redondeo se amplifican más en el orden ascendente
- La diferencia entre ambos resultados es significativa
Estabilidad Numérica de Expresiones
Problema:
Indica cómo evaluar con Matlab la expresión:
para los valores de h siguientes: 10⁻², 10⁻⁴,..., 10⁻²². Escribe una reformulación de esta expresión de forma que no se produzca cancelación.
Solución:
% Definir valor de x x = 1; % Podemos usar cualquier valor no nulo % Generar valores de h h = 10.^(-2:-2:-22); % Función original f1 = @(x,h) 1./(x + h) - 1./x; % Función reformulada f2 = @(x,h) -h./(x.*(x + h)); % Configurar formato de salida format longEng; % Resultados [h' f1(1,h)' f2(1,h)'] % Evaluación y escritura con formato fprintf(' h Original Reformulada Dif. Rel.\n'); fprintf('------------------------------------------------\n'); for i = 1:length(h) v1 = f1(x,h(i)); v2 = f2(x,h(i)); dif_rel = abs(v1-v2)/abs(v2); fprintf('%8.0e %12.5e %12.5e %8.1e\n', ... h(i), v1, v2, dif_rel); end % Visualización del error relativo loglog(h, abs(f1(x,h) - f2(x,h))./abs(f2(x,h)), 'b-o'); grid on; title('Error Relativo vs h'); xlabel('h'); ylabel('Error Relativo');
Resultado:
La expresión original sufre de cancelación cuando h es pequeño porque:
- Los términos 1/(x+h) y 1/x se vuelven muy similares
- La resta de números casi iguales pierde dígitos significativos
La expresión reformulada:
Es más estable porque:
- Evita la resta de términos casi iguales
- Mantiene la precisión incluso para h muy pequeño
- Es algebraicamente equivalente a la expresión original
Evaluación de Diferencias
Problema:
Indica cómo evaluar con Matlab la expresión:
para los valores de x siguientes: 10⁻², 10⁻⁴,..., 10⁻²². Escribe una reformulación de esta expresión de forma que no se produzca cancelación.
Solución:
% Definir valor de x x = 1; % Podemos usar cualquier valor no nulo % Generar valores de h h = 10.^(-2:-2:-22); % Función original f1 = @(x) sqrt(x.^2+1)-1; % Función reformulada f2 = @(x) x.^2./(sqrt(x.^2+1)+1); % Configurar formato de salida format longEng; % Resultados [h' f1(x,h)' f2(x,h)'] % Evaluar y escribir con formato fprintf(' h Original Reformulada Dif. Rel.\n'); fprintf('------------------------------------------------\n'); for i = 1:length(h) v1 = f1(x,h(i)); v2 = f2(x,h(i)); dif_rel = abs(v1-v2)/abs(v2); fprintf('%8.0e %12.5e %12.5e %8.1e\n', ... h(i), v1, v2, dif_rel); end % Visualización del error relativo loglog(h, abs(f1(x,h) - f2(x,h))./abs(f2(x,h)), 'b-o'); grid on; title('Error Relativo vs h'); xlabel('h'); ylabel('Error Relativo');
Resultado:
La expresión original sufre de cancelación cuando x es pequeño porque:
- Los términos √(x² + 1) y 1 se vuelven muy similares
- La resta de números casi iguales pierde dígitos significativos
La expresión reformulada:
Es más estable porque:
- Evita la resta de términos casi iguales
- Mantiene la precisión incluso para x muy pequeño
- Es algebraicamente equivalente a la expresión original
Ejemplo 3.8: Reformulación Logarítmica
Problema:
Calcular una fórmula alternativa para la expresión:
que no sea susceptible de pérdida de cifras significativas cuando x es grande y positiva.
Solución:
% Definir función original f1 = @(x) -log(x - sqrt(x.^2 - 1)); % Función reformulada usando identidad logarítmica f2 = @(x) log(x + sqrt(x.^2 - 1)); % Comparar para valores grandes de x x = 10.^(5:5:30)'; %Valores [x f1(x) f2(x)] % Escritura con formato fprintf(' x Original Reformulada Dif. Rel.\n'); fprintf('-------------------------------------------\n'); for i = 1:length(x) v1 = f1(x(i)); v2 = f2(x(i)); fprintf('%8.1e %10.4f %10.4f %8.1e\n', ... x(i), v1, v2, abs(v1-v2)/abs(v2)); end
Resultado:
La expresión original pierde precisión porque:
- Para x grande, x y √(x² - 1) son casi iguales
- La resta causa pérdida de precisión
- El logaritmo amplifica los errores
La expresión reformulada:
Es más estable porque:
- Usa suma en lugar de resta
- No hay pérdida de cifras significativas
- Es algebraicamente equivalente (son expresiones inversas)
Sucesión Convergente a π
Problema:
Considera la sucesión recurrente:
que converge a π. Explica el comportamiento para x₅₅₀
Solución:
% Implementar la sucesión x = zeros(1, 550); x(1) = 2; % Calcular términos for n = 1:549 factor = 2^(n - 0.5); inner = 1 - 4^(1-n)*x(n)^2; if inner < 0 fprintf('Error: Raíz de número negativo en n=%d\n', n); break; end x(n+1) = factor * sqrt(1 - sqrt(inner)); end % Analizar convergencia for i = [1:5, 10:10:50, 100:100:550] if i <= length(x) fprintf('x_%d = %.15f\n', i, x(i)); fprintf('Error vs pi: %.2e\n\n', abs(x(i)-pi)); end end % Visualizar convergencia semilogy(abs(x(1:end) - pi)); title('Convergencia a π'); xlabel('n'); ylabel('|x_n - π|');
Resultado:
La sucesión presenta problemas numéricos porque:
- Involucra potencias grandes (2^n) que crecen rápidamente
- La resta 1 - 4^(1-n)x_n² causa pérdida de precisión
- Los errores de redondeo se amplifican en cada iteración
Para n = 550:
- Los términos pierden precisión significativa
- La convergencia a π se ve afectada por inestabilidad numérica
- El método no es práctico para n grande
Integral Recursiva
Problema:
Considera la integral:
que satisface la relación de recurrencia:
Calcula y₂₀ utilizando esta recurrencia. ¿Qué ocurre si utilizas la ley de recurrencia inversa?
Solución:
% Calcular usando recurrencia hacia adelante y_forward = zeros(1, 21); y_forward(1) = exp(1) - 1; % y₀ = e - 1 for n = 1:20 y_forward(n+1) = exp(1) - n*y_forward(n); end % Calcular usando recurrencia hacia atrás y_backward = zeros(1, 21); y_backward(21) = 0; % Aproximación inicial for n = 20:-1:1 y_backward(n) = (exp(1) - y_backward(n+1))/n; end % Comparar resultados fprintf('n Forward Backward Diferencia\n'); fprintf('-------------------------------------------------\n'); for n = 1:21 fprintf('%2d %14.6e %14.6e %14.6e\n', ... n-1, y_forward(n), y_backward(n), ... abs(y_forward(n) - y_backward(n))); end % Visualizar diferencias semilogy(0:20, abs(y_forward - y_backward), '-o'); title('Diferencia entre métodos'); xlabel('n'); ylabel('|y_{forward} - y_{backward}|');
Resultado:
Análisis de los métodos:
- Recurrencia hacia adelante (yₙ₊₁ = e - (n+1)yₙ):
- Es numéricamente inestable
- Los errores se amplifican en cada paso
- Pierde precisión rápidamente
- Recurrencia hacia atrás (yₙ = (e - yₙ₊₁)/(n+1)):
- Es numéricamente estable
- Mantiene la precisión
- Proporciona resultados más confiables
La diferencia en el comportamiento se debe a que:
- La recurrencia hacia adelante amplifica los errores por un factor n
- La recurrencia hacia atrás los reduce por un factor 1/n
- Para integrales de este tipo, es preferible usar la recurrencia hacia atrás