Upload
catarina-alcaide-ramires
View
219
Download
1
Embed Size (px)
Citation preview
7 de Abril de 2005 Funções, Expressões e Excepções 1
Funções, Expressões e Excepções
Pedro BarahonaDI/FCT/UNL
Abril 2004
7 de Abril de 2005 Funções, Expressões e Excepções 2
Funções e Passagem de Parâmetros• Em muitos casos, ao invocar-se uma função pretende-se
obter não apenas um mas vários resultados.• Este requisito é tratado diferentemente em diferentes
linguagens de programação, dependendo em grande parte da forma como são passados os parâmetros de uma função.
• Em OCTAVE, os parâmetros são passados exclusivamente por valor (com uma excepção - nomes de funções).
• Isto quer dizer, que ao especificar-se uma variável no parâmetro de uma função a invocar, o que se passa para a função é o valor da variável.
• Durante a função, a variável não pode ser alterada no programa que invoca a função!
7 de Abril de 2005 Funções, Expressões e Excepções 3
Passagem de Parâmetros por Valor• Exemplo: Consideremos a função
function y = f(x) x = 2*x y = xendfunction;
• Se chamada com o valor x = 5, durante a computação da função, esse valor é duplicado e retornado.
• Por exemplo, se invocarmos a função na sequência (pode ser ao terminal)
..., x = 5; z = f(x); x, z, ...
os valores de x e y reportados no terminal são x = 5 e z = 10.
7 de Abril de 2005 Funções, Expressões e Excepções 4
Passagem de Parâmetros por Valor• Exemplo: ..., x = 5; z = f(x); x, z, ...
function y = f(x) x = 2*x; y = x;endfunction;
A computação da função f pode ser assim explicado: 1. Quando começa a ser executada a função f, é criada uma nova variável x, que
é local à função f, e que não se confunde com a variável x do programa.2. O valor inicial da variável x local é o valor da variável do programa que é
passsada como parâmetro (e que por acaso se chama x).3. A instrução x=2*x apenas envolve a variável local x, que passa a valer 10.4. Na instrução y=2*x, é a nova variável local que é considerada, e portanto, y =
10, valor esse retornado.5. No “programa principal” esse valor é atribuído à variável z.
7 de Abril de 2005 Funções, Expressões e Excepções 5
Passagem de Parâmetros por Referência• Outras linguagens (Pascal, C, C++, ...) permitem a passagem de
parâmetros por referência, i.e. é passada a referência à variável do programa principal, que pode ser alterada pela função.
• Por exemplo se o parâmetro x fosse passado por referência (indicado com uma notação fictícia)
..., x = 5; z = f(x); x, z, ...function y = f(ref x) x = 2*x; y = x;endfunction;
os valores de x e y reportados no terminal seriam • x = 10 (sendo passada por referência, a variável x referida na
função é a mesma variável que a variável x do programa); e• z = 10
7 de Abril de 2005 Funções, Expressões e Excepções 6
Funções com Múltiplos Resultados• A passagem de parâmetros por referência permite que uma
função (ou procedimento) passe vários valores para o programa que a invocou. Basta passar por referência as variáveis onde esses valores devem ser “colocados”.
• O Octave, não suporta passagem de parâmetros por referência. A computação de vários resultados numa função é conseguida pela computação de um vector de resultados.
• Por exemplo, se se pretender que a função f, com argumento x, retorne dois valores, f1 e f2, especifica-se a função como
function [f1,f2] = f(x) ... f1 = ...; f2 = ...; ...endfunction;
7 de Abril de 2005 Funções, Expressões e Excepções 7
Exemplo: maior_alcance_ffunction [dist, angulo] = maior_alcance_f(vi, ka); dist = 0; angulo = 0; for alfa = 0:90 x = alcance(vi,alfa,ka); if x > dist dist = x; angulo = alfa; endif; endfor;endfunction;
• A função maior_alcance_f apresentada abaixo é exactamente equivalente ao programa maior_alcance anterior, com a natural diferença de entrada e saída de parâmetros, podendo ser invocada como, por exemplo.
[d,a] = maior_alcance_f(20, 1);
7 de Abril de 2005 Funções, Expressões e Excepções 8
Funções Booleanas (Predicados) e Mistas• A função anterior facilmente alterada para determinar se
existem velocidades e ângulos iniciais para se atingir uma determinada distância d.
• Neste caso, o objectivo é múltiplo:
– Em primeiro lugar saber se a distância é atingida;
– Se a distância for atingida então indicar a velocidade e o ângulo iniciais.
• Desta forma, para além das velocidade e ângulo iniciais, a função deve retornar um valor booleano que indica se a distância foi atingida ou não.
7 de Abril de 2005 Funções, Expressões e Excepções 9
Exemplo: função atinge_1• Esse valor booleano é mantido pela variável atingida na função
apresentada abaixo:
function [vi, angulo, atingida] = atinge_1(ka, d); atingida = false; for v = 18:22 for alfa = 20:70 x = alcance(v,alfa,ka); if abs(x-d) < 0.1
vi = v; angulo = alfa;
atingida = true endif; endfor;
endfor;endfunction;
7 de Abril de 2005 Funções, Expressões e Excepções 10
Expressões Booleanas• Este enunciado, embora correcto, é algo ineficiente, já que após a
descoberta da velocidade e ângulo iniciais adequados todas as restantes trajectórias são ainda calculadas!
• Esta ineficiência pode ser corrigida se se alterarem os ciclos “para” por ciclos “enquanto”, mas impondo na condição de entrada que não tenha sido ainda descoberta uma solução.
• Essa condição pode ser especificada através de uma expressão booleana, resultante da conjunção de duas expressões booleanas mais simples
– A limitação normal do número de ciclos; e– A variável booleana, atingida, que é falsa enquanto não tiver
sido encontrada uma solução
7 de Abril de 2005 Funções, Expressões e Excepções 11
Expressões Booleanas: função atinge_2 function [vi, angulo, atingida] = atinge_2(ka, d); atingida = false; v = 18; while v <= 22 & ! atingida alfa = 20; while alfa <= 70 & ! atingida x = alcance(vi,alfa,ka); atingida = abs(x-d) < 0.001 if atingida
vi = v; angulo = alfa;
endif; alfa = alfa+1; endwhile;
v = v+1; endwhile;
endfunction;
7 de Abril de 2005 Funções, Expressões e Excepções 12
Expressões Booleanas• Expressões booleanas podem ser construidas recursivamente a
partir de outras mais simples com os operadores booleanos de– Conjunção, “e” ou “and”, expressa como & em OCTAVE
– Disjunção, “ou” ou “or”, expressa como | em OCTAVE
– Negação, “não” ou “not”, expressa como ! em OCTAVE
• As variáveis booleanas podem tomar os valores verdade ou falso. Em OCTAVE, que só considera variáveis “numéricas”, 0 corresponde a falso e qualquer outro valor a verdade!
• De notar que uma variável booleana pode ser atribuído o valor booleano de uma comparação numérica. Por exemplo:
encontrada = (x > xmin & y > ymax)
7 de Abril de 2005 Funções, Expressões e Excepções 13
Excepções (em ciclos)• Embora as expressões booleanas sejam muito convenientes e
permitam escrever programas muito compactos, neste caso a passagem de ciclos “para” para ciclos “enquanto” torna os programas menos “naturais”.
• Uma forma mais natural de expressar a intenção de descobrir a solução é indicar que se pretende percorrer todo o intervalo de possibilidades, excepto se se encontrar uma solução!
• A especificação de excepções é possível em muitas linguagens de programação. No Octave utiliza-se a instrução “break”, para se terminar excepcionalmente um ciclo.
7 de Abril de 2005 Funções, Expressões e Excepções 14
Excepções (em ciclos) ... encontrada = 0; vi = 1; while vi <= 20 & !encontrada ... if condição encontrada = 1; endif; ... vi = vi + 1; endwhile; ...
... for vi = 1:20 ... if condição break; endif; ... endfor; ...
• Por exemplo,
em vez da forma
pode utilizar-se a forma mais simples
7 de Abril de 2005 Funções, Expressões e Excepções 15
Excepções (em ciclos)• Infelizmente, a explicitação de excepções não conduz sempre a
uma grande simplificação da especificação global do programa.
• No caso corrente, como existem dois ciclos, ao sair do ciclo interno (de alfa) é necessário verificar se se deve igualmente sair do ciclo externo (em v).
• Em geral, é conveniente saber se o ciclo terminou de uma forma “normal” ou “excepcional”, pelo que é conveniente continuar a utilizar uma variável booleana para o efeito.
• Por exemplo, os dois ciclos anteriores (em v e alfa) podem ser especificados com excepções break na forma apresentada de seguida:
7 de Abril de 2005 Funções, Expressões e Excepções 16
Excepções (em ciclos) : função atinge_3 function [vi, angulo, atingida] = atinge_3(ka, d); atingida = false; for v = 18:20 for alfa = 20:70 x = alcance(v,alfa,ka); atingida = abs(x-dist) < 0.1; if atingida break endif; endfor;
if atingida break endif; endfor;
vi = v; angulo = alfa; endfunction;
7 de Abril de 2005 Funções, Expressões e Excepções 17
Excepções (em funções)• Se, como é o caso corrente, existirem vários ciclos no interior de
uma função, e se se detectar no interior do ciclo mais interno que o objectivo da função já foi atingido, existe um mecanismo de excepção, através da instrução “return”, que permite terminar a função imediatamente.
• Assim, podem imediatamente terminar-se todos os ciclos, sem se ter de verificar para cada um se o ciclo imediatamente interno terminou com uma excepção ou não.
• No entanto, poderá ter interesse informar o programa (ou função) que chama a função que pode terminar excepcionalmente, se a sua terminação foi normal ou não, o que pode ser feito através de uma variável adicional que é retornada no valor da função.
7 de Abril de 2005 Funções, Expressões e Excepções 18
Excepções (em funções): função atinge_4 function [vi, angulo, atingida] = atinge_4(ka, d); atingida = false; for v = 1:20 for alfa = 1:90 x = alcance(vi,alfa,ka); atingida = abs(x-dist) < 0.1; if atingida
vi = v; angulo = alfa; return endif; endfor; endfor;
endfunction;
7 de Abril de 2005 Funções, Expressões e Excepções 19
Um Pequeno Problema• Em muitas situações, nomeadamente no corpo de ciclos, pretende-
se trocar o valor de duas variáveis, A e B, ou sejaA B.
• Por hipótese, façamos A = 2 e B = 5. O problema é que ao fazer-se uma atribuição, por exemplo
A B
perde-se o valor inicial de A (fica A=B=5) e a atribuição seguinte, B A, mantém a situação. A forma mais simples de resolver este problema é utilizar um avariável secundária onde se guarda o valor inicial de A. As instruções seguintes resolvem pois o problema
C A % C = 2A B % A = 5 B C % B = 2
7 de Abril de 2005 Funções, Expressões e Excepções 20
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, “como 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 programa principal, pode ele próprio ser visto como uma função.
7 de Abril de 2005 Funções, Expressões e Excepções 21
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) comofact(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.
7 de Abril de 2005 Funções, Expressões e Excepções 22
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) – 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
7 de Abril de 2005 Funções, Expressões e Excepções 23
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 == 0 % elemento base f = 1 else % definição recursiva f = n * fact(n-1) endif; endfunction;
7 de Abril de 2005 Funções, Expressões e Excepções 24
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 de Abril de 2005 Funções, Expressões e Excepções 25
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).
7 de Abril de 2005 Funções, Expressões e Excepções 26
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 % 1º elemento base f = 1; elseif n == 2 % 2º elemento base f = 1; else % definição recursiva f = fib(n-1) * fib(n-2); endif; endfunction;
• Como é fácil de constatar, se o número n inicial fôr 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)!
7 de Abril de 2005 Funções, Expressões e Excepções 27
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 = 60-36.
• 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: 60-36 =24 ; 36-24=12; 24-12=12; 12 = 12 !
7 de Abril de 2005 Funções, Expressões e Excepções 28
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_rec(m,n); if m == n d = m; else if m-n >= n d = mdc_rec(m-n,n); else d = mdc_rec(n,m-n); endif; 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!