Introdução à Programação na linguagem F
Jaime Ramos, Amílcar Sernadas e Paulo Mateus
DMIST, Setembro de 2005
Capítulo 3 Unidades de programa: módulos
Objectivos
Unidades de programa: módulos. Funções como argumento de funções.
Unidades de programa
A definição de funções e subrotinas em F pode ser feita dentro do corpo principal do programa, como foi
ilustrado atrás, ou fora deste, numa unidade à parte chamada módulo. Um módulo é uma unidade de
programa que contém, entre outras, definições de funções e subrotinas, e que não pode ser executada
directamente, podendo apenas ser utilizada por outros programas. A vantagem de um módulo é que pode
ser utilizado por diferentes programas sem necessidade de repetir o código. Considerem-se as funções
sobre matrizes definidas no capítulo anterior. Podemos definir um módulo que disponibilize estas funções
e que poderá ser utilizado por um ou mais programas que necessitem de algumas dessas funções e
subrotinas sem ser necessário repetir o respectivo código.
Apresenta-se em seguida um módulo que disponibiliza algumas funções sobre matrizes.
module mmatrices
public :: somaEl, prodEscalar, somaM, prodM, pesquisa
private :: prodLC
contains
function somaEl(m) result(x)
real, dimension(:,:), intent(in) :: m
real :: x
integer :: i, j
x=0
do i=1,size(m,1)
do j=1,size(m,2)
x=x+m(i,j)
end do
end do
end function somaEl
function pesquisa(x,m) result(b)
real, dimension(:,:), intent(in) :: m
real, intent(in) :: x
logical :: b
integer :: i, j
b=.false.
do i=1,size(m,1)
do j=1,size(m,2)
if (x==m(i,j)) then
b=.true.
exit
end if
end do
if (b) then
exit
end if
end do
end function pesquisa
subroutine prodEscalar(m,x)
2
real, dimension(:,:), intent(inout) :: m
real, intent (in) :: x
integer :: i,j
do i=1,size(m,1)
do j=1,size(m,2)
m(i,j)=m(i,j)*x
end do
end do
end subroutine prodEscalar
function somaM(m1,m2) result(a)
real, dimension(:,:), intent(in) :: m1,m2
real, dimension(size(m1,1),size(m1,2)) :: a
integer :: i,j
if ((size(m1,1)==size(m2,1)).and.(size(m1,2)==size(m2,2))) then
do i=1,size(m1,1)
do j=1,size(m1,2)
a(i,j)=m1(i,j)+m2(i,j)
end do
end do
else
print *,"Erro! As matrizes não são da mesma forma"
end if
end function somaM
function prodM(m1,m2) result(a)
real, dimension(:,:), intent(in) :: m1,m2
real, dimension(size(m1,1),size(m2,2)) :: a
integer :: i,j
if (size(m1,2)==size(m2,1)) then
do i=1,size(m1,1)
do j=1,size(m2,2)
a(i,j)=prodLC(m1(i,1:size(m1,2)),m2(1:size(m2,1),j))
end do
end do
else
print *,"Erro! As matrizes nao sao compativeis"
end if
end function prodM
function prodLC(l,c) result(x)
real, dimension(:), intent(in) :: l,c
real :: x
integer :: k
x=0
do k=1,size(l)
x=x+l(k)*c(k)
end do
end function prodLC
end module mmatrices
O modulo anterior é constituido por duas partes: a primeira parte, entre o início do módulo e a instrução
contains; a segunda parte, desde a instrução contains até ao fim do módulo.
Na primeira parte declaram-se eventuais módulos que este módulo possa utilizar, funções e subrotinas
que o módulo disponibiliza (através da instrução public), funções e subrotinas auxiliares (através da
instrução private), declarações de variáveis, entre outras de que veremos exemplos adiante. No caso
3
do exemplo, o módulo apenas disponibiliza as funções e subroutines somaEl, prodEscalar, somaM,
prodM e pesquisa, já descritas anteriormente, através da declaração
public :: somaEl, prodEscalar, somaM, prodM, pesquisa
e define ainda uma função auxiliar, prodLC, que embora seja implementada no módulo não pode ser
utilizada fora deste pois foi declarada como privada, através da declaração
private :: prodLC
Na segunda parte, definem-se as funções e subrotinas do módulo, quer as que são disponibilizadas pelo
módulo quer as auxiliares. As funções auxiliares apenas podem ser referênciadas dentro do módulo, por
outras funções, não sendo conhecidas fora deste. No caso do módulo anterior, a função prodLC apenas
pode ser utilizada dentro do módulo (como de facto é, pela função prodM), não podendo ser utilizada por
nenhum programa que utilize este módulo.
Um programa pode utilizar um módulo através da instrução use. O programa seguinte utiliza o módulo
mmatrices para multiplicar duas matrizes.
program testeProd
use mmatrices
real, dimension(2,2) :: m1,m2,m3
m1(1,1:2)=(/ 1.0,2.5 /)
m1(2,1:2)=(/ 4.5,1.1 /)
m2(1,1:2)=(/ 1.3,2.3 /)
m2(2,1:2)=(/ 5.5,0.5 /)
m3=prodM(m1,m2)
print *,m3(1,1:2)
print *,m3(2,1:2)
end program testeProd
Ao utilizar o módulo mmatrices, o programa anterior tem à disposição todas as funções
disponibilizadas (públicas) por este módulo.
A compilação do programa anterior é, no entanto, um pouco mais complexa. Em primeiro lugar, há que
compilar o módulo. Como o resultado não é um ficheiro executável, há que indicar isso aquando da
compilação, através da opção –c. A instrução anterior gera um ficheiro mmatrices.o. Cada módulo só
precisa de ser compilado quando é criado e de cada vez que é alterado (mas não quando é utilizado). Uma
vez compilado o módulo, podemos compilar o programa. O processo de compilação é semelhante ao visto
anteriormente, sendo apenas necessário acrescentar o nome do(s) módulo(s) que o programa utiliza.
A estrutura genérica de um módulo é a seguinte:
module nome
[use módulos]
public :: nomes
private :: nomes
outras declarações
contains
definição de funções e subrotinas
end module nome
Funções como argumento de procedimentos
4
Tal como foi visto anteriormente, é muitas vezes necessário definir funções ou subrotinas cujos
parâmetros são eles próprios funções. Pretende-se definir uma função integrate que recebe como
argumentos uma função real de variável real f e dois números reais a e b e um número inteiro n e calcula
o integral de f no intervalo [a,b] (dividido em n subintervalos), tal como foi descrito anteriormente. A
declaração de um parâmetro de tipo função é feita através da declaração da interface da função, onde se
indicam quais os tipos dos parâmetros e qual o tipo do resultado. No caso presente, pretende-se que o
parâmetro f seja uma função com um parâmetro real e devolvendo um número real, o que é obtido
através da declaração seguinte:
interface
function f(x) result(y)
real, intent(in) :: x
real :: y
end function f
end interface
Uma solução possível para a função integrate, disponibilizada pelo módulo mnumeric.f95, é a
seguinte:
function integrate(f,a,b,n) result(y)
interface
function f(x) result(y)
real, intent(in) :: x
real :: y
end function f
end interface
real, intent(in) :: a,b
integer, intent(in) :: n
real :: y
real:: d,x,s
integer :: i
d=(b-a)/n
s=0
x=a
do i=1,n
s=s+f(x)
x=x+d
end do
y=d*s
end function integrate
O funcionamento desta função já foi descrito anteriormente. A principal diferença reside na necessidade
de declaração dos parâmetros e das variáveis auxiliares e, em particular, na declaração do parâmetro f.
Repare-se que, uma vez declarado, este parâmetro pode ser usado como uma função real de variável real,
como acontece na expressão s=s+f(x).
O programa seguinte utiliza esta função para calcular o integral da função quad (definida pela expressão
analítica -x2-x+2), disponibilizada no módulo mquad.
program testintegrate
use mnumeric
use mquad
real :: a,b
integer :: n
read *,a
read *,b
5
read *,n
print *,"O integral da funcao -x^2-x+2"
print *,"no intervalo [",a,",",b,"]"
print *,"e: ",integrate(quad,a,b,n)
end program testintegrate
O programa solicita ao utilizador os extremos do intervalo bem como o número de subdivisões pretendido
e calcula o respectivo integral, de acordo com o método apresentado.
Seguem-se alguns exemplos de execução:
-2.0
2.0
100
O integral da funcao -x^2-x+2
no intervalo [ -2.0000000 ,
e:
2.7456055
-3.0
3.0
10000
O integral da funcao -x^2-x+2
no intervalo [ -3.0000000 ,
e:
-5.9991608
2.0000000 ]
3.0000000 ]
Note-se que a função que vai ser passada como argumento (neste caso a função quad) tem que estar
definida num módulo diferente do da função que a vai receber como parâmetro (neste caso, a função
integrate). Com efeito, a função quad está definida no módulo mquad e a função integrate está
definida no módulo mnumeric.
6
Download

Capítulo 3