Recursividade e Iteração Factorial, Fibonacci e Maior Divisor Comum - ppt carregar
PublicouÍsis Miguel Alterado mais de 7 anos atrás
Apresentação em tema: "Recursividade e Iteração Factorial, Fibonacci e Maior Divisor Comum"— Transcrição da apresentação:
1 Recursividade e Iteração Factorial, Fibonacci e Maior Divisor Comum
2 Programas e Funções Como visto em exemplos anteriores, um programa pode ser considerado como o encadeamento de diversas funções, isto é, no corpo de uma função são chamadas outras funções. Um programa pode pois ser estruturado de forma a ser composto por várias funções, tal como é feio na "matemática". Por exemplo, tg(x) = sin(x) / cos(x). Em algumas linguagens de programação, nomeadamente naquelas em que as funções só podem retornar um valor, em vez de funções são usados procedimentos, mas a filosofia de encadeamento é semelhante. De notar que o programa principal, pode ele próprio ser visto como uma função.
3 Funções Recursivas Um caso particular ocorre quando as funções se chamam a si próprias, isto é, quando as funções são recursivas. Talvez o exemplo mais simples seja o da função factorial, que pode ser definida (incompletamente) como fact(n) = n * fact(n-1) Nestas condições, tal como nos ciclos, levanta-se o problema da terminação. Se uma função se chama a si própria, existe o risco de a computação se tornar infinita (entrar em ciclo fechado ou "loop"). É pois condição necessária para evitar estes ciclos infinitos que sejam definidas e testadas em primeiro lugar as condições de fim da recursividade.
4 Funções Recursivas Em geral, a recursividade é feita com base num conjunto recursivo (indutivo), definido através de cláusulas de base; um ou vários elementos de base (que fecham a recursão) de recursão: uma definição recursiva que permite a obtenção de elementos a partir de outros elementos. Num grande número de casos, o conjunto recursivo utilizado é o conjunto dos numeros inteiros, em que 1 (ou 0) é um número inteiro (cláusula de base) Se i é inteiro, i+1 também é inteiro (cláusula de recursão) Tendo em conta esta estrutura recursiva, podemos definir (correctamente) a função factorial tendo em conta a cláusula de base e a cláusula recursiva
5 Função Factorial A função factorial pode ser definida (em pseudo-código) como função fact(n) se n = 0 então % elemento base fact  1 senão % definição recursiva fact  n * fact(n-1) fimse; fimfunção; Em Octave, a definição é semelhante function f = fact(n); if n == % elemento base f = 1 else % definição recursiva f = n * fact(n-1) endif; endfunction;
6 Limites à Recursividade
De notar que para prevenir os ciclos infinitos, o Octave tem uma variável prédefinida, max_recursion_depth, que limita o número de chamadas recursivas de uma função. Por omissão ("default"), o valor da variável é 256, pelo que não se pode calcular fact(260) sem alterar o valor da variável. Existem várias outras funções recursivas em que pode existir mais do que um elemento base ou em que o conjunto recursivo é mais difícil de definir. Em qualquer caso é essencial definir a condição de terminação. Para exemplificar estas funções, estudamos de seguida a determinação dos números de Fibonacci e o cálculo do maior divisor comum entre dois números.
7 Função Fibonacci (Recursiva)
Fibonacci (matemático da Renascença italiana) estabeleceu uma série curiosa de números para modelar o número de casais de coelhos em sucessivas gerações. Em cada geração, o número pode ser obtido através dos das 2 gerações anteriores através de fib(n) = fib(n-1) + fib(n-2) Assumindo que nas primeiras duas gerações só existe um casal de coelhos, os sucessivos números de Fibonacci são 1,1,2,3,5,8,13,21,34,55,89, ... Estes números ocorrem em vários processos biológicos (e não só), por exemplo, no número de pétalas de algumas flores. A sua determinação recursiva impõe o cálculo directo do valor para 2 elementos de base (a 1ª e a 2ª geração).
8 Função Fibonacci (Recursiva)
Em Octave, a definição do números de Fibonacci pode ser feita muito facilmente como function f = fib(n); if n == % 1º elemento base f = 1; elseif n == % 2º elemento base else % definição recursiva f = fib(n-1) * fib(n-2); endif; endfunction; Como é fácil de constatar, se o número n inicial for maior ou igual a 1, a recursão termina. No entanto, se se chamar fib(0) a computação não termina (em Octave termina quando o número de chamadas recursivas exceder o valor da variável max_recursion_depth)!
9 Função Máximo Divisor Comum (Recursiva)
Como se sabe, o máximo divisor comum (mdc) entre dois números m e n é também um divisor da sua diferença, m-n. Por exemplo, o mdc de 60 e 36 é 12, que divide 24 = Por outro lado, o mdc dos dois números m e n é ainda o mdc do menor número (n) com a diferença (m-n). Se houvesse um divisor comum maior, ele seria igualmente divisor de n, contrariamente à hipótese. Assim, pode determinar-se o mdc de dois números através da determinação do mdc de números cada vez menores. A computação termina quando os números forem iguais, caso em que o mdc é esse número. Por exemplo: =24 ; 36-24=12; 24-12=12; 12 = 12 !
10 Função Máximo Divisor Comum (Recursiva)
Em Octave, pode determinar-se o maior divisor comum de dois números com a função seguinte function d = mdc(m,n); if m == n d = m; else if m-n >= n d = mdc(m-n,n); d = mdc(n,m-n); endif; endfunction; De notar que na chamada, o 1º argumento (m) é sempre maior ou igual que o 2º (n), de forma a garantir que m-n seja positivo!
11 Recursão e Iteração Em geral, uma função ou procedimento definidos recursivamente podem ser também definidos de uma forma iterativa (através de ciclos). Em geral, a definição recursiva é mais "declarativa" na medida em que explicita o que se pretende obter e não a forma como se obtém (ou seja, um determinado programa que é usado). Por outro lado, uma definição iterativa, embora não permita uma compreensão tão imediata, é geralmente mais eficiente, já que as instruções de programação de baixo nível para a iteração são mais eficientes que as de chamadas de funções. No entanto, estas diferenças são geralmente pouco importantes, excepto em casos de recursão múltipla, em que a ineficiência pode ser "catastrófica".
12 Recursão e Iteração function f = fib(n); % versão recursiva
if n <= 2 f = 1; else f = fib(n-1) + fib(n-2); endif; endfunction; function f = fib(n) % versão iterativa f1 = 1; f2 = 1; for i = 3:n f = f1+f2; f1 = f2; f2 = f; endfor;
13 Recursão e Iteração Esta é a situação da função de Fibonacci, em que o seu valor depende de 2 chamadas recursivas. Como as chamadas são independentes, a mesma função acaba por ser recalculada várias (muitas !) vezes. 7 5 3 2 1 4 6 Na realidade, o número de funções chamadas é o próprio número de fibonacci (7:1, 6:1, 5:2, 4:3, 3:5, 2:8) que aumenta exponencialmente com o valor de n.
14 Recursão e Iteração Para se ter uma ideia do aumento, podemos notar que apesar de inicialmente pequenos os números tornam-se rapidamente "enormes" tornando proibitiva a sua computação recursiva (normal).
15 Memorização Por vezes é possível aliar a declaratividade da versão recursiva, com a eficiência da versão iterativa, através da memorização dos valores já computados. Por exemplo se se pretenderem os primeiros 100 números de fibonacci, pode criar-se uma tabela, fib_m, com os valores já computados. Se fib_m(n) ainda não contiver o valor de fib(n), então determina-se fib(n) e escreve-se em fib_m(n). Caso contrário, apenas se retorna o valor de fib_m(n). Para que este esquema seja posível, é conveniente que a tabela fib_m seja visível por todas as instâncias da função fib(n). Para evitar passá-la como parâmetro deve declarar-se como uma variável global.
16 Variáveis Globais em Octave
Em Octave, para que uma variável seja global, ela deve ser declarada no programa principal com a declaração global. No caso actual, se se pretende um vector linha com 100 elementos inicializados a zero, devemos declarar a variável global global fib_m = zeros(1,100) Uma vez declarada uma variável global, ela só pode ser eliminada através da declaração clear. Se pretendermos um vector com 200 elementos deveremos fazer clear fib_m global fib_m = zeros(1,200) Para que na função a variável, fib_m considerada seja a variável global e não uma variável local, a variável deve ser identificada novamente como global.
17 Memorização function f = fib(n); % versão recursiva com memória
global fib_m; if fib_m(n) > 0 f = fib_m(n); else if n <= 2 f = 1; fib_m(n) = fib_mem(n-1)+fib_mem(n-2); endif; endfunction;