1
SOLUCION DE ECUACIONES
Y PROGRAMACIÓN
…
19 DE MAYO DE 2017
Facultad de Ingenieria Civil y Arquitectura
INFORME N° 001 – 2017 – UNA / EPIC / EPP
A:
Lic.
Docente de curso de Métodos Numéricos
De:
- Edgar Portugal Pari
Estudiante del curso en mención.
Asunto:
Presentación del trabajo de “SOLUCIÓN DE ECUACIONES Y PROGRAMACIÓN”
Fecha:
19 de Mayo de 2017
El preente trabajo tiene como objetivo principal la resolución de ecuaciones lineales con los métodos: Bisección, Punto Fijo, Nexton Raphson, Falsa Posicion y Secante, todo esto usando los programas Visual Basic en Excel, Dev C++ y Python.
Se presentan los algoritmos que darán a conocer la raíz de la función mostrada en la primera parte.
Atte: Edgar Portugal Pari
Código: 151366
INTRODUCCIÓN
Uno de los problemas más corrientes en matemáticas consiste en resolver una ecuación, es decir, encontrar un valor x* E R que satisfaga
f(x) = 0
Donde f es una función de variable y valor real, o sea,
f:lR---+lR.
Este x* se llama solución de la ecuación. A veces también se dice que x* es una raíz. En algunos casos no se tiene una expresión sencilla de f, sino que f (x) corresponde al resultado de un proceso; por ejemplo:
∫ 𝑒−𝑡2𝑑𝑡 − 0.2 = 0 𝑥
−∝
Lo mínimo que se le exige a f es que sea continua. Si no es continua en todo lR, por lo menos debe ser continua en un intervalo [a, b] donde se busca la raíz. Algunos métodos requieren que f sea derivable. Para la aplicación de algunos teoremas de convergencia, no para el método en sí, se requieren derivadas de orden superior. Los métodos generales de solución de ecuaciones sirven únicamente para hallar raíces reales. Algunos métodos específicos para polinomios permiten obtener raíces complejas.
Los métodos presuponen que la ecuación f(x) = O tiene solución. Es necesario, antes de aplicar mecánicamente los métodos, estudiar la función, averiguar si tiene raíces, ubicarlas aproximadamente. En algunos casos muy difíciles no es posible hacer un análisis previo de la función, entonces hay que utilizar de manera mecánica uno o varios métodos, pero sabiendo que podrían ser ineficientes o, simplemente, no funcionar. La mayoría de los métodos parten de Xo, aproximación inicial de x*, a partir del cual se obtiene X1 A partir de X1 se obtiene X2 después X3, y así sucesivamente se construye la sucesión [Xk] con el objetivo, no siempre cumplido, de que
lim
𝑘→∞𝑋𝑘 = 𝑋
∗
El proceso anterior es teóricamente infinito, y obtendría la solución después de
haber hecho un número infinito de cálculos. En la práctica el proceso se detiene
cuando se obtenga una aproximación suficientemente buena de x*. Esto
querría decir que el proceso se detendría cuando
|𝑋𝑘− 𝑋∗| ≤ 𝜀
Para un E dado. El anterior criterio supone el conocimiento de x*, que es justamente lo buscado. Entonces se utiliza el criterio, éste si aplicable,
|𝑓(𝑋𝑘)| ≤ 𝜀
En la mayoría de los casos, cuanto más cerca esté Xo de x*, más rápidamente se obtendrá una buena aproximación de x*.
Otros métodos parten de un intervalo inicial [ao, bo], en el cual se sabe que existe una
raíz x*. A partir de él, se construye otro intervalo
[a1, b1] contenido en el anterior, en el que también está x* y que es de menor tamaño.
De manera análoga se construye [a2, b2].
METODO DE NEWTON RAPHSON
Tal vez, de las fórmulas para localizar raíces, la fórmula de Newton-Raphson (figura 6.5) sea la más ampliamente utilizada. Si el valor inicial para la raíz es xi, entonces se puede trazar una tangente desde el punto [xi, f(xi)] de la curva. Por lo común, el punto donde esta tangente cruza al eje x representa una aproximación mejorada de la raíz. El método de Newton-Raphson se deduce a partir de esta interpretación geométrica
De la gráfica la primera derivada en x es equivalente a la pendiente:
El algoritmo capaz de dar solución a la ecuación: (𝑥 − 0.5)2− 0.1 = 0
ALGORITMO
#include <iostream>
#include <iomanip> // setprecision #include <cmath> #include <windows.h> #define PRECISION 10 #define MAX_ITERACIONES 10 #define INTERVALOS 6 using namespace std;
void tabula(double a, double b, int intervalos); // Muestra un # tabulado de intervalos double f(double x); // Retorna el valor de la función evaluada en x
double f_derivada(double x); // Retorna la derivada de la función evaluada en x void newton_raphson(double x0, double tolerancia, int max_interaciones); // Función que calcula la raiz aproximada de una función
int main() {
double a; double b;
double tolerancia; // Tolerancia double x0; // Primera aproximación
cout << setprecision(PRECISION); // Se establece la precisión
cout << "\nCalculo de las raices de una funcion aplicando el metodo de Newton - Raphson\n";
cout << "\nIngrese el intervalo inicial [a,b]:" << endl; // Se ingresa el intervalo cout << "\na = "; cin >> a; cout << "b = "; cin >> b;
// Se tabulan los valores de f para INTERVALOS intervalos tabula(a, b, INTERVALOS);
// Se pide elegir una aproximación inicial
cout << "\nEscoja el punto inicial adecuado: x0 = "; cin >> x0;
// Se pide ingresar la tolerancia cout << "Tolerancia = ";
cin >> tolerancia;
// Newton Raphson
newton_raphson(x0, tolerancia, MAX_ITERACIONES);
cin.get(); cin.get(); return 0; }
void tabula(double a, double b, int intervalos) {
int puntos = intervalos + 1;
double ancho = (b - a) / intervalos;
cout << "\n\tx\t\tf(x) " << endl; for (int i = 0; i < puntos; i++) {
cout << "\t" << a << "\t\t" << f(a) << endl; a = a + ancho; } } double f(double x) { return pow(x-0.5,2)-0.1; //return pow(x-0.5,2)-0.1 ; } double f_derivada(double x) { return 2*x-1; //return 2*x-1; }
void newton_raphson(double x0, double tolerancia, int max_iteraciones) {
double x1; // Siguiente aproximación
double error; // Diferencia entre dos aproximaciones sucesivas: x1 - x0 int iteracion; // # de iteraciones
bool converge = true;
// Se imprimen los valores de la primera aproximación cout << "\nAproximacion inicial:\n";
cout << "x0 = " << x0 << "\n" << "f(x0) = " << f(x0) << "\n" << "f'(x0) = " << f_derivada(x0) << endl; iteracion = 1; do { if (iteracion > max_iteraciones) {
converge = false; // Se sobrepasó la máxima cantidad de iteraciones
permitidas
break;
} else {
x1 = x0 - f(x0) / f_derivada(x0); // Cálculo de la siguiente aproximación
error = fabs(x1 - x0); // El error es la diferencia entre dos aproximaciones sucesivas
// Se imprimen los valores de la siguiente aproximación x1, f(x1), f_derivada(x1), error
cout << "\a"; Sleep(500);
cout << "\n\nIteracion #" << iteracion << endl; cout << "\nx" << iteracion << " = " << x1 << "\n"
<< "f(x" << iteracion << ") = " << f(x1) << "\n"
<< "f'(x" << iteracion << ") = " << f_derivada(x1) << "\n" << "error = " << error << endl;
// La diferencia entre dos aproximaciones sucesivas es también conocida como error. // La condición de terminación consiste en que que el error debe ser <= que la tolerancia dada
// Si se cumple la condición de terminación, se ha encontrado la raiz aproximada buscada.
if (error <= tolerancia) { // Condición de terminación converge = true;
break;
// Si no se cumple el criterio de terminación, se pasa a la siguiente iteración } else { x0 = x1; iteracion++; } } } while (1); // Respuesta final cout << "\a"; Sleep(500); if (converge) {
cout << "\n\nPara una tolerancia de " << tolerancia << " la RAIZ APROXIMADA de f es = " << x1 << endl;
} else {
cout << "\n\nSe sobrepasó la máxima cantidad de iteraciones permitidas" << endl;
} }
SOLUCIÓN
Abrimos el programa Y CALCULAMOS LA PRIMERA RAÍZ EN EL INTERVALO [0,1]
DONDE
X1= 0.1836538462 X2 = 0.8163461538
METODO DE LA FALSA POCISIÓN.
Es una modificación del método de la bisección. También empieza con un intervalo [ao, bo] donde f es continua y tal que f(ao) y f(bo) tienen signo diferente.
En el método de bisección, en cada iteración, únicamente se tiene en cuenta el signo de f(ak) Y de f(bk), pero no sus valores: no se está utilizando toda la información
disponible. Además es de esperar que si f(ak) está más cerca de O que f(bk), entonces
puede ser interesante considerar, no el punto medio, sino un punto más cercano a ak.
De manera análoga, si f(bk) está más cerca de O que f(ak), entonces puede ser
interesante considerar, no el punto medio, sino un punto más cercano a bk.
En el método de Falsa Pocisión se considera el punto donde la recta que pasa por (ak, f(ak)), (bk, f(bk)) corta el eje x. Como f(ak) Y f(bk) tienen signo diferente, entonces el punto de corte Ck queda entre ak Y bk.
ALGORITMO
#include <iostream>
#include <iomanip> // setprecision #include <cmath> // fabs
#define PRECISION 6 #define INTERVALOS 10 using namespace std;
void tabula(double a, double b); double f(double x);
int main() {
cout << setprecision(PRECISION);
cout << "\nCalculo de las raices de una funcion aplicando el metodo de la falsa posicion\n";
cout << "\nIngrese el intervalo inicial [a,b]:" << endl; double a, b, tolerancia; cout << "\na = "; cin >> a; cout << "b = "; cin >> b; tabula(a, b);
cout << "\nEscoja el intervalo adecuado" << endl; cout << "\na = "; cin >> a; cout << "b = "; cin >> b;
double xr; // La solución aproximada double xa = 0; // Solución anterior
if (f(a) * f(b) > 0) {
cout << "\nNo se puede aplicar el metodo de la falsa posicion\n"; cout << "porque f(" << a << ") y f(" << b << ") tienen el mismo signo" << endl; } else { cout << "Tolerancia = "; cin >> tolerancia;
cout << "\na\tb\tx\tf(a)\t\tf(b)\t\tf(x)\n" << endl; do {
xr = b - f(b) * ((b - a) / (f(b) - f(a)));
cout << a << "\t" << b << "\t" << xr << "\t" << f(a) << "\t" << f(b) << "\t" << f(xr) << endl;
// if (fabs(f(xr)) <= tolerancia) {
if (fabs(xr - xa) / fabs(xr) <= tolerancia) {
cout << "\n\nPara una tolerancia de " << tolerancia << " la raiz de f es: " << xr << endl;
break;
} else {
xa = xr; // Se guarda el valor de la aproximación anterior if (f(xr) * f(a) > 0) { a = xr; } else if (f(xr) * f(b) > 0) { b = xr; } } } while (1); } cin.get(); cin.get(); return 0; }
void tabula(double a, double b) {
int puntos = INTERVALOS + 1;
double ancho = (b - a) / INTERVALOS;
cout << "\n\tx\tf(x) " << endl; for (int i = 0; i < puntos; i++) {
cout << "\t" << a << "\t" << f(a) << endl; a = a + ancho; } } double f(double x) { // return ((x-0.5)^2)-0.1; return pow(x-0.5,2)-0.1; }
SOLUCIÓN:
OBSERVAMOS QUE LAS SOLUCIONES A LA ECUACIÓN SON: X1 = 0.184
METODO DE BISECCIÓN
El método de bisección, conocido también como de corte binario, de partición de intervalos o de Bolzano, es un tipo de búsqueda incremental en el que el intervalo se divide siempre a la mitad. Si la función cambia de signo sobre un intervalo, se evalúa el valor de la función en el punto medio. La posición de la raíz se determina situándola en el punto medio del subintervalo, dentro del cual ocurre un cambio de signo. El proceso se repite hasta obtener una mejor aproximación. En la figura 5.5 se presenta un algoritmo sencillo para los cálculos de la bisección. En la figura 5.6 se muestra una representación gráfica del método. Los siguientes ejemplos se harán a través de cálculos reales involucrados en el método.
Procedimiento:
ALGORITMO (VISUAL BASIC)
Sub BiseccionFc1()
k = 10 'NUMERO DE ITERCIONES a = -1 'VALOR DEL LIMITE INFERIOR
b = 1 'VALOR DEL PUNTO O LIMITE INFERIOR m = (a + b) / 2 'MITAD DE LOS PUNTOS FuncionA = a ^ 2 - a + 0.15 FuncionB = b ^ 2 - b + 0.15 FuncionM = m ^ 2 - m + 0.15 j = 3 Cells(j, 1) = "k" Cells(j, 2) = "a" Cells(j, 3) = "b" Cells(j, 4) = "m" Cells(j, 5) = "F(a)" Cells(j, 6) = "F(b)"
Cells(j, 7) = "F(m)" Cells(j, 8) = "L = |b-a|" Cells(j, 9) = "L < Tolerancia" j = j + 1
Tolerancia = 0.0000000000001 If ((FuncionA * FuncionB) < 0) Then While (Abs(b - a) > Tolerancia) m = (a + b) / 2 FuncionA = Sin(8 * a) + 0.531 FuncionB = Sin(8 * b) + 0.531 FuncionM = Sin(8 * m) + 0.531 Cells(j, 1) = k Cells(j, 2) = a Cells(j, 3) = b Cells(j, 4) = m Cells(j, 5) = FuncionA Cells(j, 6) = FuncionB Cells(j, 7) = FuncionM Cells(j, 8) = Abs(b - a)
Cells(j, 9) = "L aun sigue siendo mayor que tolerancia"
If (FuncionA * FuncionM < 0) Then b = m Else a = m End If k = k + 1 j = j + 1 Wend Cells(j, 1) = k Cells(j, 2) = a Cells(j, 3) = b Cells(j, 4) = m Cells(j, 5) = FuncionA Cells(j, 6) = FuncionB Cells(j, 7) = FuncionM Cells(j, 8) = Abs(b - a)
Cells(j, 9) = "L ya es menor que Tolerancia"
MsgBox ("SE HA CONCLUIDO SATISFACTORIAMENTE EL METODO DE BISECCION PARA F(X)")
Else
MsgBox ("NO EXISTE UNA POSIBLE RAIZ EN LOS PUNTOS INGRESADOS") End If
SOLUCIÓN:
Intervalo [0; 0.5]METODO DE LA SECANTE
Un problema potencial en la implementación del método de Newton-Raphson es la evaluación de la derivada. Aunque esto no es un inconveniente para los polinomios ni para muchas otras funciones, existen algunas funciones cuyas derivadas en ocasiones resultan muy difíciles de calcular. En dichos casos, la derivada se puede aproximar mediante una diferencia finita dividida hacia atrás, como en:
La ecuación es la fórmula para el método de la secante. Observe que el método requiere de dos valores iniciales de x. Sin embargo, debido a que no se necesita que f(x) cambie de signo entre los valores dados, este método no se clasifica como un método cerrado.
ALGORITMO:
Public Function fRaizSecante(ByVal Xa As Double, ByVal Xb As Double, Optional ByVal tolerancia As Double = 0.000001) As Double
Dim f_a As Double, f_b As Double, f_c As Double Dim Xc As Double
Dim errorAproximacion As Double Dim Seguimiento As String
Static intIteracion As Integer f_a = fFuncionCalculo(Xa) f_b = fFuncionCalculo(Xb)
If ((f_a * f_b) < 0) Then 'Se produce un cambio de signo errorAproximacion = VBA.Abs(Xa - Xb)
Do While tolerancia <= errorAproximacion If f_a <> f_b Then
Else
Xc = (Xa + Xb) / 2 'El punto medio, para evitar el paso por tramos concavos o convexos
End If
f_c = fFuncionCalculo(Xc) 'Se obtiene el valor de la función en dicho punto errorAproximacion = VBA.Abs(Xa - Xb)
Seguimiento = CStr(intIteracion) + "ª" & VBA.Chr(9) & "x= " & VBA.CStr(Xc) & Chr(9) & " f(x)= " & VBA.CStr(f_c) & VBA.Chr(9) & " error= " & VBA.CStr(errorAproximacion) & VBA.Chr(13) & VBA.Chr(10)
intIteracion = intIteracion + 1
If ((f_c * f_a) < 0) Then 'Si el cambio de signo se produce entre Xa y Xc, cambiamos los límites
Xb = Xc
ElseIf ((f_c * f_b) < 0) Then 'Si el cambio de signo se produce entre Xc y Xb, cambiamos los límites
Xa = Xc End If Loop Else
MsgBox "Verificar que entre " & Xa & " y " & Xb & " existe una raíz. Acote mejor los extremos de la raiz y vuelva a empezar"
Exit Function End If
fRaizSecante = Xc End Function