Prévia do material em texto
1
Universidade Estadual de Santa Cruz
Departamento de Engenharias e Computação
Engenharia Química
Roberta S. Nascimento(202011222).
Análise Computacional de Algoritmos para Resolução de Equações
Não-Lineares e Sistemas de Equações Lineares
Ilhéus - Ba
2025
2
Roberta S. Nascimento (202011222).
Análise Computacional de Algoritmos para Resolução de Equações
Não-Lineares e Sistemas de Equações Lineares
Relatório técnico sobre a implementação e
análise de métodos numéricos para
resolução de equações não-lineares e
sistemas lineares utilizando Linguagem
C++. Inclui estudo dos métodos da
Bisseção, Newton-Raphson, Secante e
Ponto Fixo, além da Eliminação Gaussiana,
Decomposição LU e Decomposição de
Cholesky, com avaliação de desempenho,
convergência e estabilidade numérica,
fornecendo critérios para a escolha
adequada de cada método.
Orientador (a) : Prof. Geizane Lima da
Silva.
Ilhéus - Ba
3
2025
SUMÁRIO
INTRODUÇÃO............................................................................................................. 4
OBJETIVO................................................................................................................... 5
RESULTADOS E DISCUSSÃO................................................................................... 6
CONCLUSÃO............................................................................................................ 12
4
INTRODUÇÃO
Os métodos numéricos são ferramentas essenciais para a resolução de problemas
matemáticos complexos, especialmente aqueles que não possuem soluções
analíticas ou que seriam inviáveis de resolver por métodos tradicionais. Este
relatório apresenta uma análise detalhada e comparativa de métodos numéricos
importantes, divididos em duas categorias principais: métodos iterativos para
equações não-lineares e métodos diretos para sistemas de equações lineares.
No estudo das equações não-lineares, foram implementados quatro métodos
clássicos. O Método da Bisseção baseia-se no Teorema do Valor Intermediário e
utiliza uma busca incremental, dividindo o intervalo ao meio a cada iteração. Apesar
de apresentar convergência linear, garante encontrar a raiz se a função for contínua
e apresentar troca de sinal no intervalo inicial.
O Método de Newton-Raphson destaca-se pela convergência quadrática,
utilizando a derivada da função para gerar aproximações sucessivas segundo a
relação:
𝑥
𝑛+1
= 𝑥
𝑛
−
𝑓( 𝑥
𝑛
)
𝑓'( 𝑥
𝑛
)
Exige, contudo, uma boa estimativa inicial e o cálculo da derivada.
O Método da Secante surge como uma alternativa eficiente ao método de Newton,
aproximando a derivada por diferenças finitas e apresentando convergência
superlinear, sem necessidade de cálculo direto da derivada.
Já o Método do Ponto Fixo transforma a equação na forma , 𝑓(𝑥) = 0 𝑥 = 𝑔(𝑥)
cuja convergência depende diretamente da escolha apropriada da função de
iteração . 𝑔(𝑥)
Para a solução de sistemas lineares, três métodos fundamentais foram estudados. A
Eliminação Gaussiana é um método direto que transforma o sistema original em
um sistema triangular equivalente, por meio de operações elementares sobre as
5
linhas, sendo relativamente simples de implementar. A Decomposição LU expande
essa ideia ao dividir a matriz do sistema em duas matrizes triangulares, L (lower) e U
(upper), sendo vantajosa quando se precisa resolver múltiplos sistemas com a
mesma matriz de coeficientes. A Decomposição de Cholesky, por sua vez, é um
caso especial para matrizes simétricas positivas definidas, aproveitando sua
estrutura para maior eficiência e estabilidade numérica, sendo amplamente utilizada
em análise estrutural e métodos de elementos finitos.
A linguagem de programação escolhida foi C++. Programar em C++ envolve
compreender a estrutura básica da linguagem, que combina simplicidade com
grande poder de abstração. Todo programa começa pela inclusão de bibliotecas,
como a , responsável pela comunicação de entrada e saída, e pela
função principal main(), que é o ponto de partida da execução. Dentro dessa
função, o programador pode declarar variáveis de diferentes tipos, como inteiros,
reais ou caracteres, utilizar operadores matemáticos e lógicos para realizar cálculos
e tomar decisões, além de empregar estruturas de controle como if, switch, for e
while para organizar o fluxo lógico do programa.
Um dos grandes diferenciais do C++ é a possibilidade de criar funções, que
permitem dividir o código em partes menores, facilitando a leitura, a reutilização e a
manutenção. Além disso, a linguagem se destaca pelo suporte à programação
orientada a objetos, em que o desenvolvedor pode definir classes que agrupam
atributos e métodos relacionados, gerando objetos capazes de representar
elementos do mundo real dentro do programa. Isso torna possível aplicar conceitos
como encapsulamento, herança e polimorfismo, que contribuem para a construção
de sistemas mais organizados, robustos e escaláveis.
Outro recurso fundamental é a Standard Template Library (STL), que oferece
estruturas de dados já prontas, como vetores, filas, pilhas e mapas, além de
algoritmos de ordenação e busca, o que otimiza o processo de desenvolvimento.
Combinando a eficiência de baixo nível — por meio do controle direto de memória e
ponteiros — com a flexibilidade da programação genérica e orientada a objetos, o
C++ proporciona ao programador tanto a capacidade de criar aplicações simples,
6
como calculadoras e jogos básicos, quanto sistemas complexos de alta
performance, como motores gráficos, softwares científicos e simuladores.
OBJETIVO
O objetivo deste estudo é implementar esses métodos utilizando a linguagem
computacional C++, comparar seu desempenho por meio de métricas objetivas,
analisar taxas de convergência e estabilidade numérica, e fornecer critérios técnicos
para a escolha adequada do método de acordo com o problema. A avaliação será
realizada a partir de estudos de caso representativos, incluindo funções não-lineares
típicas e sistemas lineares de média complexidade, com geração sistemática de
tabelas de convergência para permitir uma análise quantitativa do desempenho. A
compreensão dessas técnicas é fundamental para profissionais de engenharia,
matemática aplicada e ciências computacionais, que precisam resolver problemas
numéricos complexos de forma eficiente, precisa e confiável.
RESULTADOS E DISCUSSÃO
1. ANÁLISE DA FUNÇÃO , 𝑓(𝑥) = 𝑥3 + 𝑥 − 1 ε = 10−6
7
Objetivo: Implementar e comparar quatro métodos numéricos (Bisseção,
Newton-Raphson, Secante e Ponto Fixo) para encontrar a raiz da função
, . Gerar tabelas de convergência detalhadas e realizar 𝑓(𝑥) = 𝑥3 + 𝑥 − 1 ε = 10−6
análise comparativa do desempenho, considerando número de iterações, velocidade
de convergência e estabilidade numérica de cada método.
Tabela 1: Método da Bisseção.
Tabela 1.2: Método de Newton.
8
Tabela 1.3: Método da Secante.
Tabela 1.4: Comparação de Convergência dos Métodos
Entre os métodos analisados, Newton-Raphson destacou-se pela maior eficiência,
alcançando a solução em 4 iterações com precisão de . A Secante surgiu como 10−16
boa alternativa, convergindo em 6 iterações sem exigir derivadas. Já o Ponto Fixo e
a Bisseção foram os mais lentos, necessitando de 12 e 20 iterações,
respectivamente, refletindo sua convergência linear. Assim, confirma-se a hierarquia:
Newton (quadrática), Secante (superlinear) e, por último, Ponto Fixo e Bisseção
(lineares).
9
2. ANÁLISE DA FUNÇÃO , 𝑓(𝑥) = 𝑥 − 𝑒𝑥 − 4 ε = 10−5Objetivo: Implementar os métodos da Bisseção, Newton-Raphson e Ponto Fixo,
determinando o número de iterações necessárias e investigando casos de
divergência. Comparar a rapidez de convergência entre os métodos e implementar
mecanismos de detecção de divergência.
Tabela 2: Método da Bisseção.
10
Tabela 2.1: Método de Newton
Tabela 2.2: Comparação entre os métodos.
O método de Newton demonstrou superioridade significativa, exigindo apenas 6
iterações contra 17 da Bisseção. O método do Ponto Fixo mostrou divergência
completa devido à incompatibilidade fundamental entre as funções de iteração
naturais e a localização da raiz negativa, resultando em crescimento exponencial
dos valores e overflow numérico já nas primeiras iterações."
3. ANÁLISE DO SISTEMA.
Objetivo: Resolver um sistema linear de 7 equações e 7 incógnitas utilizando dois métodos
diretos: Eliminação Gaussiana e Decomposição LU. Implementar ambos os algoritmos,
comparar os resultados obtidos e analisar as vantagens de cada abordagem. Validar a
solução através da concordância entre os métodos e discutir a aplicabilidade de cada
técnica para sistemas lineares de média dimensão.
Tabela 3: Matriz do Sistema.
11
Tabela 3.2: Vetor de Termos independentes.
Tabela 3.3: Comparação das Soluções
Os dois métodos analisados apresentaram resultados idênticos dentro da precisão
de ponto flutuante adotada (6 casas decimais). A diferença absoluta encontrada
12
entre as soluções foi nula, o que confirma que, do ponto de vista matemático, ambos
são equivalentes quando considerados sob aritmética de precisão infinita. Isso
mostra que, em termos práticos, a escolha entre um e outro não afeta o valor final
obtido para este sistema específico.
No que diz respeito à estabilidade numérica, observou-se que tanto a Eliminação
Gaussiana quanto a Decomposição LU são suscetíveis a erros de arredondamento.
A Eliminação Gaussiana, quando aplicada sem pivotamento, pode sofrer maior
propagação desses erros ao longo das etapas de eliminação. A Decomposição LU,
apesar de também ser sensível, tende a oferecer um controle numérico ligeiramente
melhor devido à sua estrutura de fatoração, que organiza o processo em etapas
mais estáveis.
Um aspecto importante a ser considerado é o pivotamento. Neste caso, não foi
necessário implementá-lo porque os elementos da diagonal principal não
apresentaram valores nulos ou muito pequenos e a matriz analisada não mostrou
sinais de mal-condicionamento. Dessa forma, a resolução pôde ser conduzida sem
comprometer a estabilidade do processo.
4. DECOMPOSIÇÃO CHOLESKY.
Resolver um problema de análise estrutural representado pelo sistema KU=F, onde K é a
matriz de rigidez global e F o vetor de forças nodais. Verificar as propriedades de simetria e
positiva definição da matriz K, implementar a decomposição de Cholesky e determinar os
deslocamentos nodais U. Validar a solução obtida e interpretar fisicamente os resultados,
analisando a consistência numérica e a aplicação do método em problemas de engenharia
estrutural.
Tabela 4: Matriz L (Cholesky).
Tabela 4.2:Solução do Sistema KU = F.
13
A análise do sistema usando a Decomposição de Cholesky mostrou que o método
funciona bem tanto do ponto de vista numérico quanto físico. A matriz de rigidez 𝑘
manteve suas propriedades essenciais, como simetria e positividade, o que garante
que os resultados fazem sentido.
Os deslocamentos calculados ficaram na faixa de metros, compatíveis com as 10−5
cargas aplicadas. O nó 3 teve o maior deslocamento horizontal, enquanto todos os
deslocamentos verticais foram positivos, mostrando que a estrutura tende a se
elevar levemente. O resíduo numérico de confirma que os cálculos foram 10−12
precisos e estáveis.
Além disso, a Cholesky foi eficiente, exigindo cerca de metade das operações da
decomposição LU e sem precisar de pivotamento. Os resultados mostram que a
estrutura é rígida e segura para as cargas aplicadas, e o método é confiável para
análises mais complexas de engenharia estrutural.
CONCLUSÕES
Este trabalho permitiu analisar e comparar diferentes métodos numéricos,
mostrando suas vantagens e limitações em contextos variados. A aplicação prática
dos algoritmos possibilitou entender melhor a eficácia de cada método em
problemas matemáticos e de engenharia.
14
Na resolução de equações não-lineares (Questões 1 e 2), ficou claro que a escolha
do método precisa levar em conta as características da função. O Newton-Raphson
se destacou pela rapidez e precisão, atingindo convergência quadrática, mas
depende de uma boa estimativa inicial e do cálculo da derivada. O Método da
Bisseção, embora mais lenta, se mostrou confiável e sempre convergente. Já o
Ponto Fixo mostrou-se muito sensível à função de iteração, podendo levar a
divergência, como foi visto na Questão 2.
Para sistemas lineares (Questão 3), a comparação entre Eliminação Gaussiana e
Decomposição LU mostrou que ambos dão resultados consistentes. A escolha entre
eles depende do contexto: a Gaussiana é mais simples de implementar para
sistemas únicos, enquanto a LU é mais eficiente quando é necessário resolver
várias vezes o mesmo sistema.
No problema de análise estrutural (Questão 4), o Método da Decomposição de
Cholesky se mostrou eficiente e também respeitou as propriedades físicas da
estrutura. A simetria e a positividade da matriz de rigidez foram confirmadas, e os
deslocamentos calculados estavam coerentes com a física do problema, validando a
modelagem e a solução numérica.
De forma geral, o trabalho mostrou que não existe um método melhor para todos os
casos, mas sim escolhas adequadas para cada situação. O sucesso depende do
entendimento teórico, da análise das propriedades do problema e de uma
implementação cuidadosa, levando em conta estabilidade e precisão. Os resultados
obtidos servem como referência para escolher métodos numéricos em problemas
futuros de engenharia e ciências computacionais, reforçando a importância do
pensamento crítico na aplicação dessas ferramentas.
15
CÓDIGO DA QUESTÃO 1:
#include
#include
#include
using namespace std;
double f(double x) {
return x*x*x + x - 1;
}
double df(double x) {
16
return 3*x*x + 1;
}
// Método da Bisseção
void bissecao(double a, double b, double epsilon) {
cout epsilon && iter epsilon && iter"Raiz aproximada: " epsilon && iter epsilon && iter
#include
#include
22
using namespace std;
double f2(double x) {
return x - exp(x) - 4;
}
double df2(double x) {
return 1 - exp(x);
}
// Função original que causa divergência
double g2_divergente(double x) {
return exp(x) + 4;
}
// Tentativa alternativa (também problemática)
double g2_alternativa(double x) {
return (x + exp(x) + 4) / 2;
}
void bissecao_questao2(double a, double b, double epsilon) {
23
cout = 0) {
cout epsilon && iter epsilon && iter = 2 && erro > 1e10) {
cout = 5 || x > 1e50) {
divergencia_detectada = true;
break;
}
} while (erro > epsilon && iter 1" = 2 && erro > 1e10) {
cout = 5 || x > 1e50) {
divergencia_detectada = true;
break;}
} while (erro > epsilon && iter 1" > 1) → CONDIÇÃO VIOLADA" 1 na trajetória do método"
#include
#include
#include
using namespace std;
class SistemaLinear {
private:
vector> A;
vector b;
int n;
public:
SistemaLinear(const vector>& matriz, const vector&
vetor) {
A = matriz;
34
b = vetor;
n = matriz.size();
}
// Eliminação de Gauss
vector eliminacaoGauss() {
vector> Ab = A;
vector b_copy = b;
// Eliminação progressiva
for (int k = 0; k x(n);
for (int i = n-1; i >= 0; i--) {
x[i] = b_copy[i];
for (int j = i+1; j >, vector>> decomposicaoLU() {
vector> L(n, vector(n, 0));
vector> U = A;
for (int i = 0; i resolverLU() {
auto [L, U] = decomposicaoLU();
// Resolver Ly = b
vector y(n);
for (int i = 0; i x(n);
for (int i = n-1; i >= 0; i--) {
x[i] = y[i];
for (int j = i+1; j & x, const string& metodo) {
cout > A = {
{3, -9, 8, 6, 9, 4, -1},
{-9, 3, 8, 9, -12, 6, 3},
{1, -9, 2, -3, 1, -5, 5},
{4, 8, -10, 8, -1, 4, -4},
{-5, 5, 4, 11, 3, 8, 7},
{6, -2, 9, -7, -5, -3, 8},
{8, 7, 2, 5, 2, 1, -3}
};
vector b = {-0.108, 26.24, 92.808, 53.91, 143.55, -6.048, 137.94};
SistemaLinear sistema(A, b);
auto sol_gauss = sistema.eliminacaoGauss();
39
sistema.imprimirSolucao(sol_gauss, "ELIMINAÇÃO GAUSSIANA");
auto sol_lu = sistema.resolverLU();
sistema.imprimirSolucao(sol_lu, "DECOMPOSIÇÃO LU");
return 0;
}
…………………………………………………………………………………………………..
CÓDIGO DA QUESTÃO 4:
#include
#include
#include
#include
using namespace std;
class CholeskySolver {
private:
vector> A;
vector b;
40
int n;
public:
CholeskySolver(const vector>& matriz, const vector&
vetor) {
A = matriz;
b = vetor;
n = matriz.size();
}
bool isSimetrica() {
for (int i = 0; i 1e-10) {
return false;
}
}
}
return true;
}
bool isPositivaDefinida() {
41
// Verificação simplificada - todos os autovalores positivos
// Para uma verificação mais rigorosa, usar decomposição
auto L = decomposicaoCholesky();
if (L.empty()) return false;
for (int i = 0; i > decomposicaoCholesky() {
vector> L(n, vector(n, 0));
for (int i = 0; i}
}
}
return L;
}
vector resolver() {
auto L = decomposicaoCholesky();
if (L.empty()) return {};
43
// Resolver Ly = b
vector y(n);
for (int i = 0; i x(n);
for (int i = n-1; i >= 0; i--) {
x[i] = y[i];
for (int j = i+1; j >& mat, const string& nome) {
cout & x) {
cout > K = {
{7.1111e8, 0, -1.7778e8, 5.3333e8, 0, 0},
{0, 2.1333e9, -5.3333e8, 5.3333e8, 0, 0},
{-1.7778e8, -5.3333e8, 7.1111e8, 0, -1.7778e8, 5.3333e8},
{5.3333e8, 5.3333e8, 0, 2.1333e9, -5.3333e8, 5.3333e8},
{0, 0, -1.7778e8, -5.3333e8, 3.5556e8, -5.3333e8},
{0, 0, 5.3333e8, 5.3333e8, -5.3333e8, 1.0667e9}
};
vector F = {0, 0, -10000, 0, -5000, 0};
CholeskySolver solver(K, F);
cout