Você está na página 1de 44

Procedures e Programação Estruturada

Program Unit
Programa Principal
Subrotinas
Funções

Procedures
External Procedures
Internal Procedures
Vantagens das Subrotinas Externas
• Independência no teste das subrotinas: Cada subrotina pode
ser escrita e compilada como uma unidade independente. A
subrotina pode ser testada em separado antes de combiná-la
com o programa principal;
• Partes diferentes do programa podem executar a mesma
tarefa. É mais simples do que escrever várias vezes a mesma
tarefa;
• Estanquiedade: Isolamento dos efeitos dos erros de
programação;
• A comunicação é feita apenas com as variáveis parâmetros
das rotinas.
Organização de uma Subrotina
Subroutine nome da sub (lista de argumentos)
implicit none
seção de declaração
lista de comandos
[return]
end subroutine
O comando Return tem o mesmo efeito que o comando
End Subroutine. O seu uso somente se justifica quando se
deseja retornar ao programa de chamada antes de encerrar
a subrotina.

Chamada de uma Subrotina


Call nome da sub (lista de argumentos)
Uma subrotina pode chamar outra subrotina, mas
uma subrotina não pode chamar a sí mesma a não
ser que seja declarada como Recursive.
Comunicação de Variáveis entre
Subrotinas
Quando ocorre uma chamada de subrotina, o programa
principal passa um ponteiro para a localização na memória de
cada um dos parâmetros da subrotina.
Program teste subroutine sub1(x,y,i)
real:: a,b(4) real,intent(out):: x
integer:: n real,intent(in):: y(4)
....... integer:: i
call sub1(a,b,n) .......
.............. end subroutine
end program
Comunicação de Variáveis entre
Subrotinas

Programa Teste

Subroutine sub1 Endereço da memória Programa Principal Subrotina


001 a x
002 b(1) y(1)
003 b(2) y(2)
004 b(3) y(3)
005 b(4) y(4)
006 n i
Comunicação de Variáveis entre
Subrotinas

Os parâmetros de chamada da subrotina no programa


principal e na subrotina devem ter correspondência em
número, ordem e tipo.
Cuidar para não colocar variáveis simples no lugar de
variáveis do tipo array.
Subroutine hipot (lado1,lado2,hipo) ! Parâmetros da sub
! Descrição da sub
!
Implicit none
real,intent(in) :: lado1 ! Lado1
real,intent(in) :: lado2 ! Lado2
real,intent(out) :: hipo ! hipotenusa
! Declaração das variáveis locais
real ::temp
temp=lado1**2+lado2**2
hipo=sqrt(temp)
end subroutine
Uso da instrução Intent()
O uso da instrução Intent() é recomendável em todas as
subrotinas porque torna mais claro o funcionamento das
subrotinas além de facilitar na identificação de erros de
programação.
Intent(in): Indica que o argumento passa dados para a
subrotina, mas não é modificado nesta;
Intent(out): Indica que o argumento é uma variável de saída de
dados da subrotina;
Intent(inout): O argumento passa dados para a subrotina, mas
também faz a saída de dados.
Program teste
implicit none
real:: s1 ! Lado1
real:: s2 ! Lado2
real:: hipo ! Hipotenusa
write(*,*)”Entre lado1”;read(*,*) s1
write(*,*)”Entre lado2”;read(*,*) s2
call hipot(s1,s2,hipo)
write(*,100) hipo
100 format(1x”A hipotenusa vale: “,F10.4)
end program
Como passar Arrays para as Subrotinas
Explicit-shape dummy array
As extensões do array são passadas para a subrotina como
parâmetros. Com isso a subrotina conhece a forma do array
quando executada.

Subroutine teste(n,ik,data1)
implicit none
integer,intent(in):: n,ik
real,intent(out):: data1(n)
Como a subrotina conhece a forma e tamanho do array, as
operações do tipo Whole array operations e array sectins
podem ser feitas.

A desvantagem é que as dimensões do array devem ser


passadas como parâmetro da subrotina. Resulta num
código um pouco mais complicado de ser gerenciado.

Assumed shape dummy array:


Necessita de uma interface explícita para a subrotina.
Assumed-size dummy array (forma mais antiga)
Neste caso o compilador não tem informação sobre o
comprimento do array. As operações do tipo Whole array
operations, array section e controle de limite de laço não
funcionam.
Subroutine processo (data1,data2,nvals)
real,intent(in):: data1(*)
real,intent(out):: data2(*)

Essa forma não deve ser usada em programas novos.


Passando Variáveis Character
subroutine sample(string)
character(len=*),intent(in):: string
O compilador não precisa saber o comprimento do caracter
quando a rotina é compilada. O comprimento adotado é o da
variável passada. Para conhecer o comprimento do caracter
dentro da subrotina deve-se fazer
len(string)
Atributo Save
Quando algum valor local não deve ser alterado entre as
chamadas de uma subrotina.
Real, save:: soma
subroutine media_movel(x,ave,std_dev,nvals,reset)
! Se reset é .true. Limpa sums e exit
implicit none
real,intent(in):: x ! Entrada
real, intent(out):: ave ! Média móvel
real,intent(out):: std_dev! Desvio padrao móvel
integer,intent(out):: nvals ! Número corrente de pontos
logical,intent(in):: reset ! Reset flag: limpa sums se .true.
Integer,save:: n ! Número de pontos de entrada de dados
Real,save:: sum_x ! Soma dos valores de entrada
real,save:: sum_x2! Soma do quadrado dos valores de entrada
if (reset) then
n=0;sum_x=0.;sum_x2=0.
Ave=0.;std_dev=0.;nvals=0.
Else
n=n+1;sum_x= sum_x+x; sum_x2= sum_x2+x**2
ave=sum_x/real(n)
if(n>=2) then
std_dev=sqrt(n*sum_x2-sum_x**2)/(n*(n-1)))
else
std_dev=0.
End if
nvals=n
end if
end subroutine
Automatic Arrays
Subroutine sub1(x,y,n,m)
integer,intent(in):: n,m
real,intent(in):: x(n,m)
real:: temp(n,m)
temp=0.
....
End subroutine
Array temporário: A rotina é encerrada e o array é
eliminado.
Automatic array x allocatable array
Automatic array é alocado automaticamente enquanto os
outros devem ser alocados e desalocados manualmente.
Allocatable array: Podem ser criados e destruídos em rotinas
distintas. Para isso deve-se usar o comando save na
declaração do array senão ele é automaticamente eliminado.
Compartilhando Dados usando Módulos

Module nome do módulo


implicit none
save ! Comando recomendável quando for módulo de
!compartilhamento de dados
integer,parameter:: vals=5
real:: values(vals)
End module
Para que o programa veja o módulo deve-se usar o comand Use
após o Program.
Program comunica
use test
implicit none
real,parameter:: pi=3,141592
values=pi*(/1.,2.,3.,4.,5./)
call sub1
end program

subroutine sub1
use test
implicit none
write(*,*) values
end subroutine

As variáveis declaradas no módulo não precisam ser


declaradas novamente.
Module Procedure
Module nome
implicit none
! Dados compartilhados
contains
lista das subrotinas
end module
Usando Módulos para Criar uma Interface Explícita
Quando a rotina é compilada num módulo, e este é empregado
num programa, todos os detalhes da interface da subrotina são
colocados para o compilador. O compilador pode testar o
número de argumentos da chamada, o tipo de cada argumento ,
se cada argumento é ou não um array e o intent() de cada
argumento.
Rotinas que não são escritas em módulos separados têm uma
interface implícita. O compilador não dispõe das mesmas
informações se a interface fosse explícita.
Assumed Shape Arrays
Quando uma subroutine tem uma interface explícita, todos os
detalhes; tipo, ordem, intent(), rank; dos argumentos são
conhecidos.
Nesse caso o dimensionamento de um argumento do tipo
array pode ser feito como:
real:: array1(:,:) ! Define-se o tipo e o rank do array.
Esse tipo de dimensionamento é melhor que o explicit-shape
dummy arrays porque não é necessário passar os parâmetros
de dimensionamento para a subrotina. Entretanto o
dimensionamento do tipo assumed-shape array somente
funciona com interface explícita.
Functions
Function nome da função
seção de declaração
seção de execução
end function
O resultado de uma function é um valor simples, valor lógico,
character ou array.
O tipo da função também deve ser declarado:
integer function nome(..,..,..)
ou
function nome(...,...,...)
integer:: nome
• Por definição uma função bem programada deve
produzir apenas um único resultado a partir de um ou
mais dados. Além disso, a função nunca deve
modificar um dos seus parâmetros. Recomenda-se
sempre usar Intent(in) para os parâmetros de uma
função. A função que altera os seus parâmetros
apresenta “efeito de lado”.
Program teste
implicit none
real:: quadf,a,b,c,x
read(*,*)a,b,c
write(*,*)”quadf(“,x,”) = “,quadf(x,a,b,c)
end program

real function quadf(x,a,b,c)


implicit none
real,intent(in)x,a,b,c
quadf=a*x**2+b*x+c
end function
O fortran permite que se trabalhe com funções internas a uma
subrotina ou a um programa principal. Nesse caso não há uma
declaração formal da função, mas deve-se tomar cuidado de não
colocar nenhum comando executável entre a declaração das
variáveis e as funções.
Nesse tipo de esquema as variáveis utilizadas pela função são
as mesmas variáveis do programa principal ou da subrotina na
qual está inserida a função.
program teste
implicit none
! Declaração das variáveis
real:: a,b,c
real:: x,x1,d
real:: f,f1
integer:: i
! Declaração das funções
f(x)=a*x**2+b*x+c
f1(x)=2*a+b
! Inicialização das variáveis
Lista de comandos
end program
CONSTRUÇÃO ALTERNATIVA PARA ROTINAS
INTERNAS
Program teste
implicit none
real:: quadf,a,b,c,x
read(*,*)a,b,c
write(*,*)”quadf(“,x,”) = “,quadf(x,a,b,c)
Contains
real function quadf(x,a,b,c)
implicit none
real,intent(in)x,a,b,c
quadf=a*x**2+b*x+c
end function
end program
Passando uma Função como argumento de uma
subrotina
Program:: test
Real, external:: fun1,fun2
Real:: x,y,output
...
Call evaluate(fun1,x,y,output)
Call evaluate(fun2,x,y,output)
...
End program
subroutine evaluate(fun,a,b,result)
Real,external:: fun
Real,intent(in):: a,b
Real,intent(out):: result
Result=b*fun(a)
End subroutine
Um ponteiro é passado para a função fun1 na primeira
chamada e a função fun1 é usada no lugar do
parâmetro formal fun da subrotina.
Uma função apenas pode ser passada como
argumento se é declarada com o atributo External.
Real function ave_value(func,first,last,n)
Real, external:: func
Real,inten(in):: first,last
Integer,inten(in):: n
Real:: delta,sum
Integer:: i
Delta=(last-first)/(real(n-1))
Sum=0.
Do i=1,n
sum=sum+func(real(i-1)*delta)
End do
Ave_value=sum/real(n)
End function
Program test_ave_value
Real:: ave_value
Real,external:: my_function
Real:: ave
Ave=ave_value(my_function,0,1,101)
Write(*,*) ave
End program
Real function my_function(x)
Implicit none
Real,intent(in)::x
My_function=3.*x
End function
Operadores e Atribuições definidas pelo
Usuário

Interface Operator(operator_symbol)
module procedure function_1
....
End Interface
Operator_symbol
Qualquer operador intrinsico (+ - / * < > )
Operador definido pela sequência de até 31 letras entre
dois pontos (.inverter.)
Mais de uma função pode ser associada ao mesmo
operador, mas as funções devem obrigatoriamente
se distinguir pelos diferentes tipos de argumentos.
Para funções com dois argumentos (operador binário) o
lado esquerdo do operador corresponde ao primeiro
argumento da função e o lado direito deve
corresponder ao segundo argumento da função.
Operadores intrinsicos (por exemplo +) não podem ter o
seu significado padrão alterado.
Interface assignment (=)
module procedure subroutine_1
...
End interface
Type:: vetor
real:: x
real:: y
real:: z
End type
Interface operator(*)
module procedure cross
End interface
Function cross(vec_1,vec_2)
type (vetor):: cross
type(vetor),intent(in),vec_1,vec_2
cross.x=vec_1%y*vec_2%z-vec_1%z*vec_2%y
cross.y=vec_1%z*vec_2%x-vec_1%x*vec_2%z
cross.z=vec_1%x*vec_2%y-vec_1%y*vec_2%x
End function
Uso da Biblioteca IMSL
A biblioteca IMSL é um conjunto de rotinas matemáticas já
compiladas que podem ser acrescentadas ao código do
programa que está sendo desenvolvido. As vantagens do uso
dessa biblioteca são:
• Não reinventar a roda;
• Rotinas testadas e otimizadas;
• Desenvolvimento do código de forma mais rápida;
• As rotinas podem ser usadas sem maiores dificuldades.
As principais desvantagens do uso da biblioteca IMSL são:
• Rotinas do tipo caixa-preta. A documentação disponível é
restrita ao necessário para saber o método empregado e a
formatação dos parâmetros da rotina;
• As variáveis devem ser adaptadas à forma de armazenamen-
to usada na rotina;
• Nem sempre as rotinas disponíveis são as mais otimizadas
para tratar o problema.
Como verificar os procedimentos disponíveis
program inversa
use msimsl ! Esse comando deve ser colocado imediatamente
! Após o comando program ou o comando de
! declaração de subrotina
implicit none
real(8)::a(2,2),ainv(2,2)
integer,parameter::n=2, lda=2, ldainv=2
integer:: i,j
!
a(1,1)=2.d0; a(1,2)=1.d0; a(2,1)=1.d0; a(2,2)=3.d0
CALL DLINDS (N, A, LDA, AINV, LDAINV)
do i=1,2
write(*,*)(ainv(i,j),j=1,2)
end do
END program
Cuidados no Uso da IMSL
- Colocar o comando USE imsl na posição correta;
- Selecionar a rotina correspondente ao problema em estudo;
- Respeitar a ordem, o tipo e o número de parâmetros da
rotina usada;
- Respeitar a forma de armazenamento de dados indicada
pelos parâmetros da rotina.
Alguns Procedimentos com Rotinas IMSL
- Solução de sistemas de equações lineares;
- Solução de problemas de autovalores;
- Integração;
- Interpolação;

Você também pode gostar