João Miguel da Costa Sousa 135
Programação com Funções
Problemas complexos – divididos em subproblemas
Subprogramas
funções (function)
subrotinas (subroutine)
Fortran contém funções intrínsecas, ou de biblioteca.
Exemplos de funções intrínsecas: SQRT, ABS, SIN, EXP,
INT, FLOOR, LOG, etc.
Exemplo
INTEGER :: Numero_1, Numero_2, Pequeno
REAL :: Alfa, Beta, x
PRINT *, ABS(x)
Alfa = ANINT(100.0 * Beta) / 100.0
Pequeno = MIN(0, Numero_1, Numero_2)
Subprogramas do tipo Função
O programador pode necessitar de definir funções
(functions) em Fortran
As funções definidas pelo programador são
utilizadas da mesma forma que as funções
pré-definidas.
Subprograma Função
________________________________________________________
cabeçalho de função
zona de especificações
zona de instruções
João Miguel da Costa Sousa 137
Cabeçalho de funções
Cabeçalho de função
_____________________________________________________________________Forma:
FUNCTION nome_funcao(lista_argumentos)
ou
tipo FUNCTION nome_funcao(lista_argumentos
)Onde:
o
nome_funcao
pode ser qualquer identificador válido em Fortran;
a
lista_argumentos
é um identificador ou uma lista separada por
vírgulas;
o
tipo
é um identificador opcional, que indica o tipo dos argumentos
retornados pela função.
Dá um nome à função e declara os seus argumentos.
A
lista_argumentos
é a lista dos parâmetros formais que servem para
passar a informação do subprograma a outro programa.
Definição de Funções
Zona de especificações dum subprograma é idêntica à zona de
especificações de um programa, excepto:
Deve declarar o tipo da função, se este não tiver sido declarado no
cabeçalho;
Deve declarar o tipo de cada um dos parâmetros formais. Deve
igualmente conter um especificador INTENT.
Zona de instruções deve conter:
nome_funcao = expressao
onde expressao pode conter:
qualquer expressão envolvendo constantes,
argumentos formais da função,
outras variáveis declaradas no subprograma,
referências para outras funções.
João Miguel da Costa Sousa 139
Ex: Conversão de Temperaturas
Conversão graus Fahrenheit em Celsius:
Celsius
= (Fahrenheit – 32.0) / 1.8
Cabeçalho:
FUNCTION Fahr_em_Celsius(Temperatura)
Zona de especificações deve conter:
REAL :: Fahr_em_Celsius
Outra possibilidade:
REAL FUNCTION Fahr_em_Celsius(Temperatura)
A zona de declarações deve conter igualmente:
REAL, INTENT(IN) :: Temperatura
Conversão de Temperaturas
!--Fahr_em_Celsius---! Funcao que converte uma temperatura em
! graus Fahrenheit em graus Celsius
!
! Recebe: Temperatura em Fahrenheit
! Retorna: Temperatura em Celsius
!---FUNCTION Fahr_em_Celsius(Temperatura)
REAL :: Fahr_em_Celsius
REAL, INTENT(IN) :: Temperatura
! Calcula a temperatura em graus Celsius
Fahr_em_Celsius = (Temperatura – 32.0) / 1.8
João Miguel da Costa Sousa 141
Posicionar subprogramas
Formas de posicionar um subprograma:
antes de END PROGRAM , subprograma interno;
num módulo, subprograma modular;
após END PROGRAM , subprograma externo.
Secção de subprogramas
Secção de subprogramas
________________________________________________________
Forma:
CONTAINS
subprograma_1
subprograma_2
...
subprograma_n
onde cada
subprograma_i
é uma função ou subrotina que não
contém subprogramas.
Com esta definição, os subprogramas são internos e podem ser
apenas utilizados por este programa.
João Miguel da Costa Sousa 143
Prog: Conversão Temperaturas
PROGRAM Conversao_de_Temperaturas
!---! Programa que converte varias temperaturas de graus Fahrenheit na ! temperatura correspondente em Celsius. A funcao Fahr_em_Celsius e ! utilizada para converter as temperaturas. Identificadores usados: ! Fahr_em_Celsius: funcao interna que converte temperaturas Fahrenheit ! em Celsius
! TempFahrenheit: temperatura em Fahrenheit a converter ! TempCelsius: temperatura em graus Celsius
! Resposta: resposta do utilizador a pergunta ! “Mais dados a converter?”
! Entradas: TempCelsius, Resposta ! Saida: TempFahrenheit
!---IMPLICIT NONE
REAL :: TempFahrenheit, TempCelsius CHARACTER (1) :: Resposta
DO
! Le temperatura em graus Celsius
WRITE(*, ‘(1X, A)’, ADVANCE = “NO”) “Escreva a & & temperatura em graus Fahrenheit:” READ(*,*) TempFahrenheit
! Usa a funcao Fahr_em_Celsius para converter temperatura TempCelsius = Fahr_em_Celsius(TempFahrenheit)
Prog: Conversão Temperaturas
! Mostra os resultados
WRITE(*, ‘(1X, 2(F6.2, A))’), TempFahrenheit, & “em graus Fahrenheit e & & equivalente a ”, TempCelsius, “em Celsius.”
! Verifica se existem mais temperaturas a converter WRITE (*, ‘(/ 1X, A)’, ADVANCE = “NO”) &
”Existem mais temperaturas a converter (S ou N)?” READ(*,*) Resposta
IF (Resposta /= “S”) EXIT END DO
CONTAINS
!--Fahr_em_Celsius---! Funcao que converte graus Fahrenheit em Celsius !
! Recebe: Temperatura em Fahrenheit ! Retorna: Temperatura em Celsius
!---FUNCTION Fahr_em_Celsius(Temperatura)
REAL :: Fahr_em_Celsius REAL, INTENT(IN) :: Temperatura
Fahr_em_Celsius = (Temperatura - 32.) / 1.8 END FUNCTION Fahr_em_Celsius
João Miguel da Costa Sousa 145
Resultados
Exemplo de execução:
> Escreva a temperatura em graus Fahrenheit: 32
> 32.00 em graus Fahrenheit e equivalente a 0.00 em Celsius.
> Existem mais temperaturas a converter (S ou N)? N
Associação de argumentos
Referência a uma função:
nome_funcao(lista_argumentos)
Inclusão de INTENT(IN)assegura que
o valor do argumento actual é passado ao argumento formal;
o valor do argumento formal não é alterado enquanto a função estiver a
ser executada.
Se INTENT(IN) não é utilizado, uma alteração do
argumento formal implica uma alteração do argumento
actual!
O número e o tipo dos argumentos actuais devem corresponder
aos dos argumentos formais.
João Miguel da Costa Sousa 147
Função factorial
Esta função contém uma variável local
!--Factorial---! Funcao que calcula o factorial N!--Factorial---! de N,
! que e 1 se N = 0, e 1 * 2 * … * N se N > 0. !
! Recebe: Inteiro N ! Retorna: Inteiro N! !
! Nota : I e uma variavel interna do tipo ! Inteiro, usada como contador
!---FUNCTION Factorial(N) INTEGER :: Factorial INTEGER, INTENT(IN) :: N INTEGER :: I Factorial = 1 DO I = 2, N Factorial = Factorial * I END DO
END FUNCTION Factorial
Alcance
Entidades como variáveis, constantes, tipos e subprogramas
podem ser declaradas em vários pontos.
As partes do programa onde esses itens são visíveis constitui o
seu alcance.
Princípio fundamental do alcance
Alcance de uma entidade é o programa ou subprograma onde é
declarado.
1ª regra do alcance
Itens declarados em subprogramas não são acessíveis fora deste; são
itens locais.
2ª regra do alcance
Itens declarados no programa principal são entidades globais, e são
acessíveis em qualquer subprograma interno, excepto naqueles onde
entidades locais tenham o mesmo nome.
João Miguel da Costa Sousa 149
Módulos
Programação modular
Blocos principais são facilmente identificados, colocados em
subprogramas individualizados, e testados separadamente.
Programas mais simples de desenvolver, testar, perceber e modificar.
Módulos (versão simplificada)
_______________________________________________________________________
Forma:
MODULE nome_modulo
CONTAINS
subprograma_1
subprograma_2
...
subprograma_n
END MODULE nome_modulo
onde cada
subprograma_i
são subrotinas ou funções. São chamados
subprogramas módulo.
Conjunto de subprogramas constitui uma biblioteca
Exemplo de biblioteca
Biblioteca de conversão de temperaturas
MODULE Biblioteca_Temperatura
!---! Modulo que contem os seguintes subprogramas para
! conversao de temperaturas:
! Fahr_em_Celsius - conversao de Fahreneit em Celsius ! Celsius_em_Fahr - conversao de Celsius em Fahreneit !---IMPLICIT NONE
CONTAINS
!--Fahr_em_Celsius---! Funcao que converte graus Fahrenheit em Celsius ! Recebe: Temperatura em Fahrenheit
! Retorna: Temperatura em Celsius
!---FUNCTION Fahr_em_Celsius(Temperatura)
REAL :: Fahr_em_Celsius REAL, INTENT(IN) :: Temperatura
Fahr_em_Celsius = (Temperatura - 32) / 1.8 END FUNCTION Fahr_em_Celsius
João Miguel da Costa Sousa 151
Biblioteca temperaturas
Utilização de módulos
Instrução USE
______________________________________________________Forma:
USE nome_modulo
USE nome_modulo, ONLY: lista
!--Celsius em_Fahr---! Funcao que converte graus Celsius em Fahrenheit ! Recebe: Temperatura em Celsius
! Retorna: Temperatura em Fahrenheit
!---FUNCTION Celsius_em_Fahr(Temperatura)
REAL :: Celsius_em_Fahr REAL, INTENT(IN) :: Temperatura
Celsius_em_Fahr = 1.8 * Temperatura + 32 END FUNCTION Celsius_em_Fahr
! Outras funcoes relacionadas com temperatura …
END MODULE Biblioteca_Temperatura
Compilação e ligação de módulos
Compilação - programa fonte convertido em
linguagem-máquina. Cria os ficheiros objecto (.OBJ em DOS)
Ligação - funções contidas em módulos são ligadas ao
programa principal, criando o programa executável, guardado
num ficheiro executável (.EXE em DOS)
João Miguel da Costa Sousa 153
Funções recursivas
Função recursiva - função que se chama a ela própria.
Exemplo: função factorial
0! = 1
n
! = n (n – 1)! , se n > 0
Função definida recursivamente:
1.
Âncora, ou caso mais simples;
2.
Passo recursivo, onde os valores são definidos com base nos anteriores.
Exemplo para 4!
4! = 4 × 3!, etc.
Definição de funções recursivas
Em Fortran são definidas com:
RECURSIVE
no cabeçalho
RESULT
no fim do cabeçalho, indicando a variável a retornar o valor da
função, em vez da própria função. O tipo da função será o tipo desta
variável.
Função Fortran para factorial
!--Factorial---! Funcao que calcula factoriais recursivamente !
! Recebe: inteiro n >= 0 ! Retorna: n!
!---RECURSIVE FUNCTION Factorial(n) RESULT(Fact)
INTEGER :: Fact ! Variavel com resultado INTEGER, INTENT(IN) :: n IF (n == 0) THEN Fact = 1 ELSE Fact = n * Factorial(n - 1) END IF
João Miguel da Costa Sousa 155
Programação com Subrotinas
Análise top-down: problemas complexos divididos em
subproblemas
Diferenças entre funções e subrotinas
Subrotinas podem retornar mais de um ou nenhum valor ao programa
principal.
As funções retornam valores através do nome; subrotinas retornam
através de argumentos.
Uma função é chamada pelo seu nome, enquanto uma subrotina usa
instrução CALL
Subprograma Subrotina
________________________________________________________cabeçalho de subrotina
zona de especificações
zona de instruções
END SUBROUTINE nome_subrotina
Subrotinas - definições
Cabeçalho de subrotina
_____________________________________________________________________Forma:
SUBROUTINE nome_subrotina(lista)
ou
RECURSIVE SUBROUTINE nome_subrotina(lista)
Onde:
o
nome_subrotina
pode ser qualquer identificador válido em Fortran;
a
lista
é um identificador ou uma lista separada por vírgulas.
Dá um nome à subrotina e declara os seus argumentos.
A
lista
contém os parâmetros formais, que servem para
João Miguel da Costa Sousa 157
Instrução CALL
Instrução CALL
___________________________________________________________________
Forma:
CALL nome_subrotina(lista)
Onde:
o
nome_subrotina
constitui o nome da subrotina a ser
chamada;
a
lista
contém as variáveis, constantes ou expressões
constituindo os parâmetros actuais. Os tipos dos parâmetros
actuais e formais devem coincidir.
Ex: Conversão coordenadas
Conversão coordenadas polares em cartesianas
x
= r cos θ
y
= r sin θ
!--Converte_em_Cartesianas---! Subrotina que converte coordenadas polares
! em cartesianas.
!
! Recebe: Coordenadas polares R e Theta(radianos)
! Retorna: Coordenadas cartesianas X e Y
!---SUBROUTINE Converte_em_Cartesianas(R, Theta, X, Y)
REAL, INTENT(IN) :: R, Theta
REAL, INTENT(OUT) :: X, Y
X = R * COS(Theta)
Y = R * SIN(Theta)
João Miguel da Costa Sousa 159
Prog: Conversão coordenadas
PROGRAM Polar_em_Cartesianas
!---! Programa que aceita coordenadas polares num ponto, e mostra as coordenadas ! cartesianas correspondentes. A subrotina interna Converte_em_Cartesianas e ! utilizada para a! conversao. Variaveis usadas:
! CoordR, CoordT : coordenadas polares de um ponto ! CoordX, CoordY : coordenadas cartesianas de um ponto ! Resposta: : Se sim existem mais dados a converter !
! Entradas: CoordR, CoordT, Resposta ! Saidas: CoordX, CoordY
!---IMPLICIT NONE
REAL :: CoordR, CoordT, CoordX, CoordY CHARACTER (1) :: Resposta
! Le e converte coordenadas até nao haver mais dados DO
WRITE (*, ‘(1X, A)’, ADVANCE = “NO”) &
“Escreva as cordenadas polares R e Theta(radianos):” READ (*,*) CoordR, CoordT
CALL Converte_em_Cartesianas(CoordR, CoordT, CoordX, CoordY)
Prog: Conversão coordenadas (2)
! Mostra os resultados
WRITE (*,*) “Coordenadas cartesianas:”, CoordX, CoordY
WRITE (*, ‘(1X, A)’, ADVANCE = “NO”) “Mais coordenadas a converter? (S ou N)?” READ *, Response IF (Response /= “S”) EXIT END DO CONTAINS !--Converte_em_Cartesianas---! Subrotina que converte coordenadas polares ! em cartesianas.
! Recebe: Coordenadas polares R e Theta(radianos) ! Retorna: Coordenadas cartesianas X e Y
!---SUBROUTINE Converte_em_Cartesianas(R, Theta, X, Y)
REAL, INTENT(IN) :: R, Theta REAL, INTENT(OUT) :: X, Y X = R * COS(Theta) Y = R * SIN(Theta)
END SUBROUTINE Converte_em_Cartesianas END PROGRAM Polar_em_Cartesianas
João Miguel da Costa Sousa 161
Exemplo de execução
> Escreva as cordenadas polares R e Theta(radianos): 1.0, 0
> Coordenadas cartesianas: 1.0000000 0.0000000E+00
> Mais coordenadas a converter? (S ou N)? S
> Escreva as cordenadas polares R e Theta(radianos): 1.0, 1.57
> Coordenadas cartesianas: 7.9627428E-04 0.9999997
> Mais coordenadas a converter? (S ou N)? N
Associação de argumentos
Quando a instrução CALL é executada:
CALL Converte_em_Cartesianas(CoordR, CoordT, CoordX, CoordY)
Parâmetros
Actuais
Parâmetros
Formais
CoordR
→ R
CoordT
→ Theta
CoordX
X
CoordY
Y
Parâmetros Actuais Parâmetros Formais CoordR → R CoordT → Theta CoordX ← X CoordY ← YApós a execução da subrotina:
João Miguel da Costa Sousa 163
Parâmetros de entrada/saída
Se os parâmetros formais forem declarados com
INTENT(INOUT):
parâmetro_actual
←→
parâmetro formal
Como OUT e INOUT são utilizados para retornar
valores para o programa principal, os parâmetros
utilizados deverão ser variáveis
.
O número e tipo dos parâmetros actuais e formais
devem concordar!
Se um parâmetro não é definido, o Fortran toma-o
como INOUT. Isto é extremamente perigoso!
Números aleatórios
Não é possível gerar números aleatórios em
computador
Geram-se assim números pseudo-aleatórios.
O valor inicial é dado por uma semente, dada por
RANDOM_SEED
em Fortran 90.
Cada novo número aleatório obtido é utilizado no cálculo do
seguinte. Operação efectuada pela subrotina
RANDOM_NUMBER. Produz números aleatórios entre 0 e 1
com distribuição uniforme.
João Miguel da Costa Sousa 165
Exemplo
Exemplo: Lançar dois dados
! Introduz um valor para a semente
CALL RANDOM_SEED
!...
CALL RANDOM_NUMBER(R1)
CALL RANDOM_NUMBER(R2)
Dado_1 = 1 + INT(6*R1)
Dado_2 = 1 + INT(6*R2)
Par = Dado_1 + Dado_2
Onde
R1
e
R2
são dois números aleatórios, e
Par
é a soma dos
valores dos dois dados.
Subprogramas como parâmetros
Subprogramas podem ser parâmetros
devem ser modulares, externos ou intrínsecos;
Não podem usar o atributo INTENT
Subprogramas como parâmetros:
externos - declarados após END PROGRAM
João Miguel da Costa Sousa 167
Exemplo
Exemplo: Integral
f x dx
a
b
( )
z
PROGRAM Integral_Numerico !---! Programa que aproxima o integral de uma função no! intervalo [A,B] usando o metodo de aproximacao trapezoidal, ! calculada pela subrotina Integral; o integrando e o # de ! subintervalos são passados como parametros para Integral. A ! funcao Integrando e importada do modulo Funcao_Integrando. ! Identificadores usados:
! A, B : limites do intervalo de integracao
! Integral: subrotina que aproxima o integral de F em[A,B] ! Integrando: o integrando
! Numero_subintervalos: # de subintervalos em que [A,B] e ! subdividido
!
! Entradas: A, B, , Numero_subintervalos
! Saidas: Aproximacao do integral de F em [A,B]
!---USE Funcao_integrando ! Modulo contendo integrando
IMPLICIT NONE REAL :: A, B
INTEGER :: Numero_subintervalos
Prog: Integral numérico
WRITE (*, ‘(1X, A)’, ADVANCE = “NO”) &
“Escreva os limites do intervalo e o # de subintervalos:” READ *, A, B, Numero_subintervalos
CALL Integral(Integrando, A, B, Numero_subintervalos)
CONTAINS
!--Integral---! Subrotina que calcula a aproximacao trapezoidal do integral da ! funcao F no intervalo [A,B] usando N subintervalos. Variaveis locais: ! I : contador
! DeltaX : comprimento dos subintervalos ! X : ponto de subdivisao
! Y : valor da funcao no ponto X ! Soma : soma aproximada
!
! Recebe: Funcao F, limites A, B e numero N subintervalos ! Retorna: Valor aproximado do integral F em [A,B]
!---SUBROUTINE Integral (F, A, B, N)
REAL, INTENT(IN) :: A, B INTEGER, INTENT(IN) :: N REAL :: F, DeltaX, X, Y, Soma INTEGER :: I
! Calcula comprimento dos subintervalos ! e inicializa as aproximacoes Soma e X DeltaX = (B - A)/ REAL(N)
X = A Soma = 0.0
João Miguel da Costa Sousa 169
Prog: Integral numérico (concl.)
! Calcula a soma aproximada DO I = 1, N - 1
X = X + DeltaX Y = F(X) Soma = Soma + Y END DO
Soma = DeltaX * ((F(A) + F(B)) / 2.0 + Soma
PRINT 10, Numero_subintervalos, Soma
10 FORMAT (1X, “Aproximacao trapezoidal usando”, I4, “subintervalos e de”, F10.5) END SUBROUTINE Integral
END PROGRAM Integral_Numerico
!---MODULE Funcao_integrando
!---! Modulo contendo a funcao Integrando
!---CONTAINS FUNCTION Integrando(X) REAL :: Integrando REAL, INTENT(IN) :: X Integrando = EXP(X**2) END FUNCTION Integrando
END MODULE Funcao_integrando
Subprogramas e parâmetros
Fortran não controla directamente número de parâmetros de
uma função. Para isso usam-se blocos INTERFACE contendo:
Tipo do valor retornado pela função
Número de argumentos e tipo de cada um deles
Exemplo com a função
Integrando
:
INTERFACE
FUNCTION Integrando(X)
REAL :: Integrando
REAL, INTENT(IN) :: X
END FUNCTION Integrando
END INTERFACE
João Miguel da Costa Sousa 171
Inteligência Artificial
Projecta sistemas computacionais com características associadas
à inteligência humana, tais como:
aprendizagem
raciocínio dedutivo
linguagem natural
reconhecimento e processamento de imagens
Áreas da IA
Sistemas periciais (controlo, consultoria, etc.)
Reconhecimento de padrões (voz, escrita, etc.)
Visão computacional
Robótica (máquinas sensoriais)
Técnicas de procura (procura na Internet)
Jogos
Muitos destes problemas são recursivos
Subrotinas recursivas
Problema: Torres de Hanoi
Pretende-se resolver o puzzle da figura, onde se devem mover os discos do
poste da esquerda para a direita, seguindo as seguintes regras:
1.
Quando um disco é movido, deve ser posicionado no topo de um dos
postes.
2.
Só se pode mover um disco de cada vez, e este deve ser o do topo de um
dos postes.
3.
Um disco maior nunca pode estar situado em cima de um mais pequeno.
Problema simples para um número pequeno de discos; torna-se difícil para
João Miguel da Costa Sousa 173
Exemplo: Torres de Hanoi
Algoritmo
Este algoritmo recursivo resolve o puzzle das Torres de Hanoi.
Entradas: Número N de discos a mover.
Saídas: A sequência de movimentos a efectuar de forma a resolver o puzzle.
Recebe N.
Se existe um disco:
Passo mais simples:
Move o disco do poste A para C, resolvendo o puzzle.
Caso contrário faz o seguinte:
Passo recursivo:
Move os N - 1 discos do poste A para o poste B, usando o poste C como poste
auxiliar.
Move o disco maior restante de A para C.
Move os N - 1 discos do poste B para o poste C, usando o poste A como poste
auxiliar.
Programa: Torres de Hanoi
PROGRAM Torres_de_Hanoi
!---! Programa que resolve o puzzle das Torres de Hanoi de uma ! forma recursiva, usando a subrotina Move. Identificadores: ! Poste_1, Poste_2, Poste_3 : marcas dos postes!
! Numero_Discos : numero de discos
! Move : Subrotina para mover os discos !
! Entrada : Numero_Discos
! Saidas : Sequencia de movimntos que resolve o puzzle !---IMPLICIT NONE
CHARACTER(*), PARAMETER :: Poste_1 = “A”, Poste_2 = “B”, & Poste_3 = “C”,
INTEGER :: Numero_discos
WRITE (*, ‘(1X, A)’, ADVANCE = “NO”) &
“Escreva o numero de discos:” READ *, Numero_discos
PRINT *
CALL Move(Numero_discos, Poste_1, Poste_2, Poste_3) CONTAINS
João Miguel da Costa Sousa 175
Programa: Torres de Hanoi (concl.)
!--Move---! Subrotina recursiva que move N discos de PosteInicial para PosteFinal ! usando um poste auxiliar. Variaveis:
! N : numero de discos ! PosteInic : poste contendo os discos ! PosteFin : poste onde ficarao os discos ! PosteAux : poste auxiliar de armazenamento ! Recebe : N, PosteInic, PosteFin, PosteAux ! Retorna: Sequencia de movimentos a efectuar
!---RECURSIVE SUBROUTINE Move(N, PosteInic, PosteAux, PosteFin)
INTEGER, INTENT(IN) :: N
CHARACTER, INTENT(IN) :: PosteInic, PosteAux, PosteFin
IF (N == 1) THEN ! Caso mais simples
PRINT *, “Move disco de”, PosteInic, “para ”,PosteFin ELSE ! Passo recursivo
! Move n -1 discos de PosteInic para PosteAux ! utilizando PosteFin como poste auxiliar CALL Move(N - 1, PosteInic, PosteFin, PosteAux)
! Move disco de PosteInic para PosteFin CALL Move(1, PosteInic, “ ”, PosteFin)
! Move n -1 discos de PosteAux para PosteFin ! utilizando PosteInic como poste auxiliar CALL Move(N - 1, PosteAux, PosteInic, PosteFin) END IF
END SUBROUTINE Move
END PROGRAM Torres_de_Hanoi