introduÇÃo ao cÁlculo numÉrico laboratÓrio – … · aulas teórica: bissecção, falsa...

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.

Upload: phunghanh

Post on 08-Jul-2019

220 views

Category:

Documents


0 download

TRANSCRIPT

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.