You are on page 1of 15

INTRODUÇÃO AO CÁLCULO NUMÉRICO

LABORATÓRIO – AULA 02

EQUAÇÕES NÃO LINEARES

1. INTRODUÇÃO
Nesta aula prática estudaremos alguns problemas que são expressos, matematicamente, como
equações não lineares, ou seja, iremos determinar a raiz dessas equações, em computador. A
ferramenta computacional que empregaremos é o Scilab, com o qual nos familiarizamos na
Aula 01 de Laboratório.

Na resolução das equações não lineares, empregaremos os métodos que aprendemos nas
aulas teórica: bissecção, falsa posição, ponto fixo, newton-raphson e secante. Cada um desses
métodos foi implementado como uma função do Scilab, armazenada em arquivos de extensão
.sci. A esta altura, você já deve ter copiado os arquivos ‘bisecção.sci’, ‘falsaposicao.sci’,
‘pontofixo.sci’, ‘newtonraphson.sci’ e ‘secante.sci’ para alguma pasta em seu computador.
Essa pasta será o diretório de trabalho para tudo o que for realizado nesta aula.

Antes de começarmos a explorar os métodos numéricos propriamente ditos, vamos conhecer


dois recursos do ambiente Scilab, funções e scritps. Ambos podem ser encarados como formas
de programação do ambiente permitindo organizar nossas atividades e alcançar um
desempenho significativamente melhor.
2. FUNÇÕES E SCRIPTS NO SCILAB

2.1. FUNÇÕES

O conceito de função do Scilab é similar ao de outras linguagens de programação


como, por exemplo, a linguagem C.

Considere o método da bissecção; na aula teórica o algoritmo foi apresentado e


discutido através do pseudocódigo correspondente e vamos supor que sabemos
traduzir esse algoritmo para a linguagem do Scilab. Então, numa situação prática,
executaríamos o Scilab e, na janela Console, definiríamos a função matemática
cuja raiz queremos determinar , digitaríamos todos os comandos correspondentes
ao método da bissecção e teríamos a solução.

Mas e se quiséssemos resolver novamente o mesmo problema com diferentes


estimativas iniciais ou, ainda, resolver uma equação não linear diferente? Teríamos
que digitar de novo todos os comandos correspondentes ao algoritmo da
bissecção mas, sem dúvida, isso é um enorme desperdício de tempo.

É aqui que entra o conceito de função; todas as instruções (ou comandos)


relacionados entre si e utilizados para executar uma tarefa bem definida são
agrupados em um único conjunto que pode ser utilizado sempre que necessário,
sem que precisemos digitar novamente todas as instruções.

Como dissemos, o conceito de função do Scilab é similar ao de outras linguagens,


porém, sua implementação tem características específicas que veremos a seguir.

As funções podem ter um número qualquer de argumentos de entrada e


argumentos de saída. Os argumentos de entrada da função não são por ela
modificados mas os argumentos de saída, sim. A sintaxe completa para a definição
de uma função é:

[o1, ... , on] = nome_da_funcao (i1, ... , in)

Os argumentos de entrada e de saída são separados por vírgulas mas os de


entrada são delimitados por parênteses enquanto que os de saída são delimitados
por colchetes.

As funções podem ser definidas de três modos distintos.

O primeiro deles corresponde a definir a função na própria Console e em seguida


utilizá-la através de chamadas a ela. Esse modo é útil quando a função é
relativamente simples (número não muito grande de instruções). Por outro lado, a
função só existe em quanto durar a sessão de trabalho. Se você fechar o Scilab, a
função se perde. Se você executar o comando clear a função também se perde,
pois esse comando limpa todo o espaço de trabalho do Scilab. Vejamos, na prática,
como funciona esse modo de definição de funções.

ATIVIDADE PRÁTICA

Na console, digite as seguintes linhas:

-->function [x2, x3] = potencias(x)


-->x2=x^2;
-->x3=x^3;
-->endfunction

Comentários
Toda definição de função começa com a palavra function e termina com
endfunction. Entre elas fica o corpo da função. A linha que começa com function é
chamada cabeçalho.

Agora a função está pronta para ser usada, isto é, podemos executar uma
chamada de função. Execute o comando:

-->[quadrado, cubo] = potencias(3)


cubo =

27.
quadrado =

9.

O segundo modo é chamado de funções “inline” e também é feito na Janela de


Console, valendo apenas na sessão de trabalho atual. Também é bastante útil
quando a função é dada por uma ou mais expressões simples.

ATIVIDADE PRÁTICA

Na console, digite os seguintes comandos. Examine a sintaxe do comando deff e


observe os resultados.

-->deff('[x2, x3]=potencias(x)',['x2=x^2';'x3=x^3;'])

-->[x2, x3]=potencias(3)
x3 =

27.
x2 =

9.
O terceiro modo de definir uma função é armazenar o código da função em um
arquivo. Desta maneira, o código não se perde quando a sessão de trabalho é
encerrada.

As funções escritas pelo usuário, por uma convenção da comunidade Scilab, ficam
armazenadas em arquivos de extensão .sci. Como são arquivos de texto, qualquer
editor de texto pode ser utilizado para escrever uma função e gravar o arquivo .sci
correspondente. No entanto, o Scilab oferece um editor de texto próprio chamado
SciNotes que pode ser acessado através do menu da Janela Principal do Scilab pela
sequência Aplicativos -> SciNotes. É recomendável utilizar sempre o SciNotes,
porque esse editor apresenta uma série de realces que facilitam muito a escrita e a
leitura de um arquivo .sci (o mesmo vale para os arquivos de script que serão
vistos no próximo item).

Como esta segunda maneira de definir funções envolve arquivos precisamos


sempre saber qual é o diretório de trabalho atual; isso pode ser feito digitando, na
Console, o comando pwd. Para mudar o diretório atual, o mais simples é usar o
Menu Principal; selecione Arquivo -> Alterar o diretório atual...

A questão, agora, é: como uma função que está armazenada em um arquivo pode
ser chamada durante uma sessão de trabalho? O Scilab fornece um procedimento
em duas etapas. Na primeira etapa, a função passa a integrar o ambiente de
trabalho, ou seja, fica disponível para ser executada. Isto é feito através do
comando exec:

--> exec(“nome_da_funcao.sci”);

(supondo que o arquivo nome_da_funcao.sci esteja no diretório atual; se não


estiver, você pode fornecer o caminho completo até o local onde o arquivo está,
exemplo: exec(“C:\...\...\nome_da_funcao.sci”)

Observe que, com o comando exec a função não é executada, de fato; ela, apenas
fica disponível para uso. Vamos repetir a ATIVIDADE PRÁTICA anterior só que,
desta vez, utilizando arquivos.
ATIVIDADE PRÁTICA

No Menu Principal, selecione Aplicativos->SciNotes. A janela do editor de texto


será exibida.

No editor, entre com o código da função ‘potencias’ da atividade anterior.


Selecione Arquivo->Salvar. Para ser usado corretamente, o nome do arquivo
deve ser exatamente igual ao nome da função, mas observe que a caixa de
diálogo apresentada pelo SciNotes já sugere esse nome. Certifique-se sobre o
diretório e salve o arquivo.

Agora, retorne para a Console do Scilab e execute os comandos e observe o


resultado.

-->exec("potencias.sci");

-->[quadrado, cubo]=potencias(4)
cubo =

64.
quadrado =

16.
Observe que, a partir do próprio SciNotes é possível carregar o arquivo .sci para
uso futuro. Para isso, no Menu Principal do SciNotes, selecione a opção Executar e,
a seguir, uma das opções exibidas. Experimente com elas e veja o resultado na
Console.

No Scilab, assim como em outras linguagens, é possível construir bibliotecas


inteiras de funções, mas não discutiremos esse assunto aqui.

2.2. SCRIPTS

De modo semelhante ao caso das Funções do item anterior, quando vários


comandos devem ser executados pode ser conveniente gravar a sequência de
comandos em um arquivo chamado script e invocar esse script toda vez que for
necessário.

Um script também pode ser criado com o editor SciNotes, mas uma diferença
entre funções e scripts é que, enquanto funções são armazenadas em arquivos
com extensão .sci, por convenção, scripts são armazenados em arquivos com
extensão .sce.

Tanto funções quanto scripts são “carregados” no ambiente de trabalho do Scilab


através do comando exec, mas uma diferença essencial é que as funções apenas
ficam disponíveis para uso enquanto que um script é executado imediatamente.

Assim, por exemplo, se você tem um arquivo chamado estudoconvergencia.sce


que contém a função cuja raiz você quer determinar e uma sequência de
chamadas a vários métodos numéricos com o objetivo de compará-los entre si, ao
executar

--> exec(“estudoconvergencia.sce”);

todos os comandos contidos no arquivo serão imediatamente executados.

Nos estudos de caso discutidos a seguir veremos alguns scripts em ação.


3. ESTUDO DE CASO: CONVERGÊNCIA DOS MÉTODOS NUMÉRICOS

Nossa primeira atividade prática envolvendo os métodos numéricos usados na


determinação de raízes de equações não lineares consiste em tomar uma equação não
linear, aplicar cada um dos métodos e compará-los através do número de iterações e
da evolução do erro relativo aproximado, por meio de gráficos. Utilizaremos a função
f(x)=e-x-x, empregada por Chapra e Canale no livro Numerical Methods for Engineers
para exemplificar o comportamento de cada método.

3.1. ANATOMIA DOS SOLVERS

Antes de iniciarmos a atividade prática propriamente dita, vamos analisar a


estrutura dos programas (solvers). Com o editor SciNotes, visualize o arquivo
newtonraphson.sci, por exemplo. Você verá o seguinte conteúdo.

function [raiz, x, iter, ea]=newtonraphson(x0, f, fp, tol, imax)


iter = 0;
xr = x0;
x(iter+1)=x0;
ea(iter+1)=100;
while (1)
xrold = xr;
xr = xrold - f(xrold)/fp(xrold);
iter = iter+1;
x(iter+1) = xr;
if(xr ~= 0) then
ea(iter+1)=abs((xr-xrold)/xr)*100;
end;
if(ea(iter+1) <= tol) then
raiz = xr;
return;
end;
if(iter >= imax) then
error('Número Máximo de Iterações Alcançado');
end;
end

Interessa-nos aqui examinar os parâmetros de entrada e saída da função


newtonraphson. Observe que os parâmetros de entrada incluem todas as
informações que o método numérico precisa para determinar a raiz; no caso do
Método de Newton-Raphson, como vimos na aula teórica, esses parâmetros são:

x0 Estimativa inicial
f Função cuja raiz será determinada
fp Derivada da função f
tol Tolerância pré-especificada
imax Número Máximo de Iterações
Os parâmetros x0, tol e imax são números que podem ser fornecidos diretamente
na chamada da função newtonraphson. Os parâmetros f e fp são nomes de
funções que avaliam, respectivamente, o valor da função matemática, f, e da
derivada de f, fp, em um determinado ponto. Devem ser definidas separadamente,
de acordo com o que foi estudado no item 2.

Outros métodos numéricos precisam de parâmetros de entrada diferentes. Por


exemplo, Bissecção, Posição Falsa e Secante exigem duas estimativas iniciais e não
precisam da derivada da função. As respectivas definições são mostradas a seguir:

function [raiz, x, iter, ea]=biseccao(xl, xu, f, tol, imax)


function [raiz, x, iter, ea]=falsaposicao(xl, xu, f, tol, imax)
function [raiz, x, iter, ea]=pontofixo(x0, f, tol, imax)
function [raiz, x, iter, ea]=secante(xi, xf, f, tol, imax)

Os parâmetros de saída, por sua vez, são os mesmos para todos os métodos e é
importante que seja assim porque permite compará-los entre si.

raiz Valor encontrado para a raiz


x Vetor com a sequência de raízes
iter Número de Iterações Executadas
ea Vetor com a sequência de erros relativos

3.2. DETERMINAÇÃO DAS ESTIMATIVAS INICIAIS GRAFICAMENTE

Todos os métodos numéricos para determinação de raízes de equações não


lineares necessitam de uma estimativa inicial para a raiz, de modo a dar início ao
processo iterativo.

Como vimos nas aulas teóricas, uma maneira de determinar a estimativa inicial (ou
duas estimativas no caso de alguns dos métodos) é fazer o gráfico da função e
identificar, aproximadamente, em que ponto o gráfico cruza o eixo das abscissas.

Vamos fazer o gráfico da função y=e-x-x, no intervalo [0,5]; esse intervalo pode ser
ajustado se for necessário para identificar melhor onde o gráfico cruza o eixo x. No
nosso caso, será suficiente e escolhemos 51 pontos igualmente espaçados para
avaliar a função. Também exibimos uma grade porque isso facilita a identificação
da estimativa inicial.
ATIVIDADE PRÁTICA: GRÁFICO DA FUNÇÃO

-->// MÉTODO GRÁFICO PARA DETERMINAR A ESTIMATIVA INICIAL

-->x=linspace(0,5,51);

-->y=exp(-x)-x;

-->plot(x,y);

-->xgrid

O resultado final é:

Examinando o gráfico podemos ver claramente que a raiz está localizada no


intervalo [0.5,1] e, de fato, bem mais próxima de 0.5 do que de 1. Então, tomemos
como estimativa inicial x0=0.5 e, para os métodos que necessitam de duas
estimativas iniciais, consideremos xl=0.5 e xu=0.7
3.3. DETERMINAÇÃO DA RAIZ

Na próxima atividade prática, você terá que digitar, na Console do Scilab, uma
longa sequência de comandos cujo resultado final é a determinação da raiz da
função de teste, através de cada um dos métodos numéricos estudados do ponto
de vista teórico em sala de aula.

Os comentários descrevem brevemente as etapas do cálculo. Inicialmente, você irá


definir, na linguagem do Scilab, a função e sua derivada (requerida por Newton-
Raphson) e, mais adiante, a função modificada (problema de ponto fixo) como
exige o método do Ponto Fixo. Nesta etapa, também são informados os
parâmetros do cálculo: estimativas iniciais, tolerância, número máximo de
iterações. A seguir, cada método (codificado no respectivo arquivo .sci) é
carregado no ambiente e a raiz é, então, calculada. Por último, é gerado um gráfico
com os erros relativos de cada método.

ATIVIDADE PRÁTICA
// VÁ PARA A PASTA DE TRABALHO (ONDE ESTÃO AS FUNÇÕES QUE
IMPLEMENTAM OS MÉTODOS
// NO MENU PRINCIPAL, SELECIONE A SEQUÊNCIA "ARQUIVO -> ALTERAR
DIRETÓRIO ATUAL..."

// DEFININDO A FUNÇÃO CUJA RAIZ SE QUER DETERMINAR

function [y] = expx_menos_x(x)


y=exp(-x)-x;
endfunction

// DEFININDO A DERIVADA DA FUNÇÃO (PARA O MÉTODO DE NEWTON-


RAPHSON)

function [y] = deriv_expx_menos_x(x)


y=-exp(-x)-1;
endfunction

// ESTIMATIVAS INICIAIS: XL e XU; SE APENAS 1 FOR NECESSARIA, X0 = XL

xl = 0.5;

xu = 0.7;

x0 = xl;

// TOLERANCIA (EM PORCENTAGEM)

tol = 0.0001;

// NUMERO MAXIMO DE ITERAÇÕES


imax = 100;

//=========================================================
// BISSECÇÃO
//=========================================================

// CARREGAR FUNÇÃO BISSECÇÃO NO AMBIENTE E CALCULAR

exec("bisseccao.sci");

// PARA COMPARAR OS MÉTODOS ENTRE SI, VAMOS DEFINIR NOMES


DIFERENTES PARA OS PARAMETROS DE SAIDA

[raiz_bisec, x_bisec, iter_bisec,


ea_bisec]=bisseccao(xl,xu,expx_menos_x,tol,imax)

//=========================================================
// FALSA POSICAO
//=========================================================

// CARREGAR FUNÇÃO FALSAPOSICAO NO AMBIENTE E CALCULAR

exec("falsaposicao.sci");

[raiz_falsap, x_falsap, iter_falsap,


ea_falsap]=falsaposicao(xl,xu,expx_menos_x,tol,imax)

//=========================================================
// PONTO FIXO
//=========================================================

// IMPORTANTE: NAO ESQUECER QUE O PROBLEMA TEM QUE SER


REFORMULADO COMO UM PROBLEMA DE

// PONTO FIXO. NESTE CASO, É IMEDIATO EXP(-X)-X=0 => X = EXP(-X)

// ASSIM DEVEMOS DEFINIR UMA FUNÇÃO DIFERENTE PARA O PONTO FIXO:

function [y]=expx_fp(x)
y=exp(-x);
endfunction

// CARREGAR FUNÇÃO PONTOFIXO NO AMBIENTE E CALCULAR

exec("pontofixo.sci");

[raiz_pfixo, x_pfixo, iter_pfixo, ea_pfixo]=pontofixo(x0,expx_fp,tol,imax)


//=========================================================
// NEWTON-RAPHSON
//=========================================================

// CARREGAR FUNÇÃO NEWTONRAPHSON NO AMBIENTE E CALCULAR

exec("newtonraphson.sci");

[raiz_newton, x_newton, iter_newton,


ea_newton]=newtonraphson(x0,expx_menos_x,deriv_expx_menos_x,tol,imax)

//=========================================================
// SECANTE
//=========================================================

// CARREGAR FUNÇÃO SECANTE NO AMBIENTE E CALCULAR

exec("secante.sci");

[raiz_secante, x_secante, iter_secante,


ea_secante]=secante(xl,xu,expx_menos_x,tol,imax)

// GRAFICO DOS ERROS RELATIVOS APROXIMADOS


[nr nc]=size(ea_bisec);
niter=linspace(1,nr,nr);
plot(niter,ea_bisec,'ro-');

[nr nc]=size(ea_falsap);
niter=linspace(1,nr,nr);
plot(niter,ea_falsap,'gx-');

[nr nc]=size(ea_pfixo);
niter=linspace(1,nr,nr);
plot(niter,ea_pfixo,'bs-');

[nr nc]=size(ea_newton);
niter=linspace(1,nr,nr);
plot(niter,ea_newton,'cd-');

[nr nc]=size(ea_secante);
niter=linspace(1,nr,nr);
plot(niter,ea_secante,'vm-');

xlabel("Número de Iterações","fontsize",4,"color","red");
ylabel("Erro Relativo Aproximado","fontsize",4,"color","red");
title("Gráfico de Convergência","color","red","fontsize",4);
//xtitle("Gráfico de Convergência f(x)=exp(-x)-x", "Número de Iterações", "Erro
Relativo Aproximado");
legend("Bissecção", "Falsa Posição", "Ponto Fixo", "Newton-Raphson",
"Secante");
O gráfico de convergência obtido deve ser o da figura abaixo:

ATIVIDADE PRÁTICA

Com base no que foi aprendido nas aulas teóricas, interprete o gráfico de
convergência.
Verifique quantas iterações foram necessárias para cada método convergir
construindo uma tabela simples com o comando:

itermatriz=[..
"Bissecção ", msprintf('%d',iter_bisec);
"Falsa Posicao ", msprintf('%d',iter_falsap);
"Ponto Fixo ", msprintf('%d',iter_pfixo);
"Newton-Raphson", msprintf('%d',iter_newton);
"Secante ", msprintf('%d',iter_secante)]

No gráfico obtido, algumas curvas ficam sobrepostas. Use o seguinte comando


para limitar os valores nos eixos x e y:

set(gca(),"data_bounds",matrix([0,8,0,3],2,-1));

(por ora, não discutiremos esse commando, use-o como uma “caixa preta”).
O resultado é:

Agora é possível visualizar que Newton-Raphson converge um pouco mais


rápido, por exemplo.
3.4. USANDO SCRIPTS PARA A DETERMINAÇÃO DA RAIZ

Suponha que você deseje realizar vários estudos variando, por exemplo, os
parâmetros do problema como as estimativas iniciais, a tolerância, etc. Seria um
grande desperdício de tempo e energia digitar todos os comandos novamente.
Esta é uma típica situação em que scripts devem ser usados. Todos os comandos
digitados anteriormente podem ser coletados e armazenados em um arquivo de
script que, como vimos, possui extensão .sce. Para agilizar as atividades práticas,
isso já foi feito previamente e está no arquivo ConvergenciaMetodos.sce.

ATIVIDADE PRÁTICA

Com o SciNotes, abra o arquivo ConvergenciaMetodos.sce e verifique que ele


contém todos os comandos digitados na Atividade Prática anterior. Usando o
script, podemos

Como vimos, para executá-lo, basta usar o comando:

exec(“ConvergenciaMetodos.sce”);

Verifique que o resultado do script é exatamente o mesmo da longa sessão de


digitação.

A vantagem é que, agora, podemos simplesmente editar o arquivo .sce, alterar


qualquer parâmetro e, até mesmo, determinar a raiz de outra equação não
linear; basta alterar as definições das funções no início do arquivo.

Com base no procedimento apresentado, você agora pode determinar a raiz de


qualquer equação não linear.

ATIVIDADE PRÁTICA

Altere o scrip ConvergenciaMetodos.sce (crie uma cópia) e encontre a raiz da


função f(x)= ex-4x2 com erro relativo igual a 0.01%.
Antes determine graficamente um intervalo que contenha a raiz.

You might also like