Departamento de Física Aplicada e Termodinâmica
Física Computacional A
DFAT/
FiscompFA
Módulo, Função e Sub-rotina
Professor: Anibal Leonardo Pereira
última atualização: fevereiro 2011
Estagiários:
2004/1 a 2005/2
Luciana Conceição Iecker Lima
2010/1
Magali dos Santos Leodato
2009/1 a 2010/2
Filipe da Fonseca Cordovil
Monitores:
2001/1
Diego Chagas Garcia
2002/2
Erick Azevedo Meirelles
2003/1 a 2003/2
Luciana Maria dos Santos Azevedo
2003/1 a 2003/2
Tatiana Gonçalves Martins
2003/1 a 2005/2
Renato Nascente Júnior
2004/1 a 2005/2
Públio Martins Romano M. Carreiro
2006/1 a 2007/2
Luiz Fernando Rosalba Telles Souza
2006/1 a 2007/2
Paulo Henrique Pfitzner
2008/1 a 2008/2
Filipe da Fonseca Cordovil
2008/1 a 2009/2
Magali dos Santos Leodato
2011/1 a
Filipe da Fonseca Cordovil
1. Introdução
Um programa Fortran pode ser visto como sendo composto de um programa principal e nenhum, um módulo ou
vários módulos.
somente
Um
programa principal
(programa) em Fortran consiste de uma sequência de instruções e construções
colocadas entre as instruções
PROGRAMe
END PROGRAM.
Unidade programa principal
PROGRAM!instruções de especificação
!instruções executáveis
END PROGRAM
Forma recomendada
PROGRAM nome_prog !instruções de especificação !instruções executáveis END PROGRAM nome_prog
Observação: sempre utilize um
nomepara identificar o programa principal
O nome (nome_prog) do programa principal (
programa) é um nome global, por isto não pode ser igual ao nome
de qualquer outra unidade de programa, de qualquer procedimento e nem ser igual ao nome de qualquer variável ou
constante utilizada no programa.
Entre as instruções “PROGRAM nome_prog” e “END PROGRAM nome_prog” são escritos dois grupos principais de
instruções: um grupo contendo instruções de especificação e um grupo contendo instruções executáveis.
O grupo de instruções de especificação é sempre colocado antes do grupo de instruções executáveis e seu
propósito é o de fornecer informações (especificações, definições) para o compilador Fortran sobre as entidades
utilizadas no programa (por isto são colocadas no início).
Instruções executáveis são instruções que produzem ações (ações = comandos) que serão implementadas durante
a execução do programa. Exemplo:
PROGRAM soma_2_numeros
implicit none !conjunto de instruções de especificação real:: x, y
print*,"Entre com 2 números:" !conjunto de instruções executáveis read*, x, y
print*,"A soma de", x, "e", y, "vale", x+y
END PROGRAM soma_2_numeros
2. Módulo
Módulos (unidades de programa módulo) são, primordialmente, usados para compartilhar informações e dados
entre as unidades de programa (todas ou parte das entidades declaradas nos módulos dentro podem ser acessadas).
A grande vantagem do uso de um módulo (mas não a única) decorre do fato das interfaces dos procedimentos
(funções e sub-rotinas) declarados nele (procedimentos módulo) serem sempre explícitas, o que permite que o
compilador Fortran identifique inconsistências (e/ou erros) nos programas quando da sua compilação.
Um módulo (unidade de programa módulo) é identificada pela palavra-chave module. Por exemplo, o módulo
fc_constantes é escrito entre as declarações module fc_constantes e end module fc_constantes.Módulo
module fc_constantes
Por causa de sua grande flexibilidade, módulos devem (
preferencialmente) ser usados para conter dados globais:definições, sub-rotinas e funções.
Nos módulos as instruções de especificações também são colocadas antes dos procedimentos. Módulos não
podem conter instruções executáveis, por este motivo os procedimentos (funções e sub-rotinas) são colocadas depois
da instrução
contains.
module <nome>
!instruções de especificação
contains
!procedimentos módulo
end module <nome>
3. Instrução de Associação de Uso
A instrução de
associação de uso
(
use statement) é utilizada para associar (disponibilizar) o conteúdo público de
um módulo em outra unidade de programa.
Quando utilizada numa unidade de programa (programa principal ou em outro módulo) as variáveis, constantes,
funções, sub-rotinas e definições públicas que estão no módulo que está sendo associado ficarão disponíveis para a
unidade de programa que contém a instrução de associação (a instrução de associação de uso).
A instrução de associação de uso (
use statement), quando utilizada numa unidade de programa, tem que ser a
primeira instrução depois da instrução de definição da unidade de programa, antes da instrução implicit none.
Por exemplo:
Programa principal que usa um módulo
program exemplo_01
!---! Propósito: programa incompleto que ! evidencia a utilização da ! instrução de uso com o módulo modulo_a !---! Arquivo: ex01.f03
! Autor: Anibal L. Pereira 03/11/2009
!---use modulo_a
implicit none
end program exemplo_01
Este não usa
módulo
program exemplo_02
!---! Propósito: programa incompleto que
! não associa (não faz uso) de ! nenhum módulo
!---! Arquivo: ex02.f03
! Autor: Anibal L. Pereira 03/11/2009 !---implicit none
end program exemplo_02
Observe que os comentários, tudo que inicia com uma exclamação ( ! ) não é visto pelo compilador. Então o compilador vê os seguinte códigos:
Programa principal que usa um módulo
program exemplo_01
use modulo_a
implicit none
end program exemplo_01
Não usa módulo
program exemplo_02 implicit none
4. Compilação e Execução de Programa que utiliza Módulo
Quando um programa Fortran é constituído por um principal principal
e um módulo, o processo de compilação é feito assim:
1. compilação do módulo
2. compilação do programa principal com o módulo
Por exemplo, admita que o programa principal seja o programa prog_01 (guardado no
arquivo prog_01.f03) eque o módulo seja o fc_constantes (guardado no
arquivofc_constantes.f03).Compilação do Módulo
•
digite o comando
gfortran -c fc_constantes.f03a chave
-cfaz com que o compilado execute a compilação do módulo
fc_constantesnão existindo erro nos códigos fonte do módulo, este procedimento gera dois arquivos no diretório
atual:
fc_constantes.oe
fc_constantes.modCompilação do Programa
•
digite o comando
gfortran -o prog_01 fc_constantes.o prog_01.f03o comando
gfortranagora é utilizado com a chave
-oa chave
-oé a indicação para o compilador compilar e link-editar o programa principal
a opção
-o prog_01informa ao compilador que ele deve gerar o arquivo executável
prog_01depois da chave
-o prog_01é colocado o arquivo objeto do módulo que será utilizado
gfortran -o prog_01 fc_constantes.o
é importante que o arquivo objeto do módulo esteja antes do programa principal.
depois de identificar o módulo que será utilizado, especifica-se o programa desejado
gfortran -o prog_01 fc_constantes.o prog_01.f03
não existindo erro nos códigos fonte do programa, este procedimento gera o programa executável
chamado
prog_01no diretório atual
5. Procedimento
Um processo computacional especificado por um subprograma função ou por um subprograma sub-rotina (ou
como usualmente falamos: por uma função ou por uma sub-rotina) e que pode ser executado quando necessário é
chamado de procedimento. Em essência, procedimentos são funções e sub-rotinas.
Procedimentos podem ser vistos como sendo de dois tipos:
escrito pelo programador
e
parte da linguagem
Fortran
.
Procedimentos Intrínsecos
Procedimentos Escritos pelo Programador
Os procedimentos escritos pelo programador podem ser classificados em:
•
procedimento módulo
•procedimento interno
Procedimentos Módulo
Um procedimento escritos pelo programador e que guardado num módulo é chamado de procedimento módulo.
Procedimento módulo são funções e/ou sub-rotina guardadas num módulo.
Procedimentos Interno
Procedimento interno é uma função ou uma sub-rotina escrita dentro de um programa principal, dentro de uma
função ou dentro de uma sub-rotina.
Procedimento interno é útil quando utilizado somente no programa que está sendo escrito.
Normalmente usa-se um procedimento interno quando os códigos fontes escritos serão essencialmente utilizado apenas no programa que os contém, isto é, não se intenciona usar o procedimento com outro programa. Se o procedimento é para ser utilizado com outro programa, ele necessita estar dentro de um módulo, não escrito como um procedimento interno.
Um ponto importante a ser destacado é que a função (
function) e a sub-rotina (
subroutine) tem forma diferente
de ser referenciada (chamadas, usadas).
6. Função
Essencialmente, pode-se dizer que o propósito de uma função é pegar um ou mais valores (
argumentos) e gerar
um resultado. Este comportamento fica evidente quando se utiliza, por exemplo, as funções matemáticas intrínsecas
do Fortran:
sin(x)
calcula o valor do seno de x
(valor de x em radianos)
log(x)
calcula o logarítmico neperiano de x
log
e
x
=
ln
x
mod(10,3)
retorna o resto da divisão de 10 por 3
A forma de referenciar (chamar, invocar, executar) uma função é:
nome(argumento)
nome(argumento_1, argumento_2, … )
para dois ou mais argumentos
Uma função é referenciada (executada) simplesmente fazendo-se uso dela numa expressão no lugar de uma
variável ou de uma constante. Então:
y = x + y * log(b)
calcula o
ln
b
e então multiplica por y,
y
⋅
ln
b
, para
depois adicionar x a este valor
x
y
⋅
ln
b
e então atribuir o
resultado final à variável y
x1 = -b + sqrt(b*b – 4.0*a*c)
primeiro calcula
b
2−
4
a c
, depois usa a função raiz quadrada
(
sqrt= square root) para calcular
b
2−
4
a c
e então adiciona
−
b
, depois atribui o resultado final à variável
x1
Várias funções intrínsecas podem usar argumentos de mais de um tipo e neste caso (mas nem sempre) o
resultado será do mesmo tipo do argumento.
Por exemplo:
real :: x, y
y = abs(x)
gera o valor
real absoluto de x
(valor de x sem o sinal) e atribui este valor à
variável real
y
integer :: x, y
y = abs(x)
gera o valor
inteiro absoluto de x
(valor de x sem o sinal) e atribui este valor à
variável inteira
y
A função que possuí esta característica é chamada de
função genérica
(
generic function) porque, na realidade,
ela referencia um conjunto de funções. A função apropriada para o cálculo (a função apropriada que será utilizada pelo
compilador) dependendo do tipo de argumento utilizado.Função escrita pelo programador
As funções intrínsecas do Fortran cobrem a maior parte das funções matemáticas que são de uso frequente.
Entretanto, é usual que o programador escreva sua função própria (função definida pelo programador).
Uma função escrita pelo programador inicia com a instrução função (
function) e termina com a instrução fim de
função (
end function).
Função
FUNCTION nome(lista_argumentos_mudos) . . . .
instruções de especificação . . . . instruções executáveis . . . . END FUNCTION nome
Forma recomendada
TYPE FUNCTION nome(lista_argumentos_mudos) !instruções de especificação !instruções executáveis END FUNCTION nome
Observação: preferencialmente, defina o TIPO da variável resultado da função junto com a instrução
functionA lista de argumentos (lista_argumentos_mudos) contém o que chamamos de
argumentos mudos
(
dummy arguments) que são utilizados para receber os
argumentos reais
(
actual arguments), aqueles escritos quando se
referencia (utiliza) a função.
algumas linguagens de programação chamam os argumentos mudos de: • parâmetros ou então de
• argumentos formais
O tipo (
type) especifica o
tipo do resultado da função
. Por exemplo:
real function raiz_cubica(x)implicit none
real, intent(in):: x !<-- x é um argumento mudo real::y !<-- y é uma variável local
! cálculo da função
y = log(x)
raiz_cubica = exp(y/3.0)
end function raiz_cubica
especifica que a variável resultado da função (variável que tem o mesmo nome da função, neste caso:
raiz_cubica) é
Variável Local
A variável y definida e utilizada na função raiz_cubica não é acessível fora da função, por isto ela é chamada
de
variável local
(variável interna) e não tem existência fora da função. Então o programa (programa principal) ou
outra unidade de programa qualquer pode utilizar o nome y para o que for necessário sem receio de que haja
colisão de nomes (utilização do mesmo nome para duas entidades diferentes). Este isolamento do interior da função do
seu meio externo é uma das características que faz com que uma função (procedimento = função e sub-rotina) se torne
uma ferramenta poderosa.
Intenção dos Argumentos mudos
Chama-se argumento mudo os argumentos que aparecem na definição da função.
A intenção dos argumentos mudos de uma função tem que ser informada. A intenção do argumento mudo
especifica que o argumento mudo será utilizado somente para entrada de dado (
in), somente para saída de dado
(
out) ou então para entrada e saída de dado (
inout) na função.
Então, o atributo intent(in) (na instrução
real,intent(in)::y ) informa ao compilador Fortran que oargumento mudo da função (neste exemplo a variável
x) não pode ser ter seu valor alterado pela função, pois ésomente de entrada.
Somente argumentos mudos podem ter a sua intenção declarada.
Argumento opcional
Argumento opcional é aquele que pode ou não aparecer (ser utilizado) na lista de argumentos reais da função.
Quando se escreve a função, o argumento mudo que será feito opcional tem que ter o atributo optinal
explicitamente escrito na sua definição. Veja o exemplo de uma função que pode somar dois ou então três números,
isto é, pode ser utilizada com assim:
• soma_dois_ou_tres(10.0, 2.0, 3.0)
que, obviamente gera o resultado 15.0
ou seja, 10.0 + 3.0 + 3. 0
• soma_dois_ou_tres(10.0, 2.0)
por sua vez, utilizada assim a função gera o resultado 12.0
porque utiliza apenas dois argumentos na sua lista de argumentos reais: 10.0 + 2.0
real function soma_dois_ou_tres(a, b, c)
real, intent(in):: a, b !<-- argumentos obrigatórios; intenção entrada real, intent(in), optional:: c !<-- argumento opcional; intenção entrada
if(present(c)) then !--- ! soma de três números !---
soma_dois_ou_tres = a + b + c else
!--- ! soma de dois números !--- soma_dois_ou_tres = a + b end if
Observe o uso da função intrínseca
presentutilizada no corpo da função soma_dois_ou_tres. A função
intrínseca
presentpermite verificar se o argumento mudo declarado opcional está presente (sendo utilizado) ou não na
lista de argumentos mudos.
Resultado da função
Forma que pode ser utilizada
A outra forma de definir o tipo da variável resultado da função é:
function raiz_cubica(x) implicit none
real :: raiz_cubica real, intent(in):: x real::y
y = log(x)
raiz_cubica = exp(y/3.0) end function raiz_cubica
entretanto
dê preferência a
real function raiz_cubica(x) implicit none real, intent(in):: x real::y y = log(x) raiz_cubica = exp(y/3.0) end function raiz_cubica
A variável resultado da função tem sempre que ser declarada
, não importa qual é utilizada.
Como exemplo de utilização da função raiz_cubica num programa (a função raiz_cubica está contida no módulo
mod_func
) temos:
program exemplo_raiz_cubica
use mod_func implicit none
real:: num, & ! número fornecido pelo usuário raiz_3 ! raiz cúbica do número
print*,"Entre com um número" read*, num
raiz_3 = raiz_cubica(num) ! aqui a variável num é um argumento real ! porque está sendo usada na chamada da função
print*, "A raiz cúbica de",num, "vale", raiz_3
end program exemplo_raiz_cubica
Quando o resultado da função é uma matriz
Para o caso do resultado da função ser uma matriz, a opção result tem que ser utilizada.
A opção result utilizada na declaração da função possibilita que seja dada um nome diferente ao resultado da
função (que é igual ao nome da função) e (o mais importante) permite que o resultado da função seja uma matriz. Por
outro lado, quando a função é recursiva o uso da opção result é obrigatório.
Por exemplo, considere a função:
real function raiz_cubica(x) implicit none
real, intent(in):: x real::y
! cálculo da função
y = log(x)
raiz_cubica = exp(y/3.0)
Com o uso da opção resultado (result) a declaração do tipo da função pode ser feita assim:
function raiz_cubica(x) result(z) implicit none
real, intent(in):: x real::z
real::y
!--- ! cálculo da função
!--- y = log(x)
z = exp(y/3.0)
end function raiz_cubica
real function raiz_cubica(x) result(z) implicit none
real, intent(in):: x real::y
!--- ! cálculo da função
!--- y = log(x)
z = exp(y/3.0)
end function raiz_cubica
Troca do nome da variável resultado
raiz_cubica para z
tipo declarado no corpo da função
Troca do nome da variável resultado
raiz_cubica para z
tipo declarado na definição da função
Observe que nos exemplos acima a variável resultado é um escalar.
Para o caso da variável resultado ser uma matriz o procedimento deve ser assim:
• function dobra_matriz(a) result(z)
use esta tipo de declaração e não esqueça que a variável resultado tem que ser declarada no corpo da
função
function dobra_matriz(a) result(z) real, dimension(3,3),intent(in):: a
real, dimension(3,3)::z ←
CERTO
• real function dobra_matriz(a) result(z)
← NÃO USE
(
se z é uma matriz, está errado)
para o caso da variável resultado ser uma matriz, não use esta forma.
Não se deve utilizar o tipo na definição da função porque assim pode-se definir que a variável resultado
é uma matriz ao mesmo tempo que se declara o tipo da matriz (como pode-se ver no exemplo que segue)
O tipo da função é o mesmo tipo da variável utilizada em resultado, isto é, o tipo utilizado na variável
result éo tipo da função.
Veja o exemplo completo da função utilizada no exemplo. A função construída aqui é uma função cujo
resultado é uma matriz. Observe que a função simplesmente dobra o valor da matriz.
function dobra_matriz(a) result(z) real, dimension(3,3),intent(in):: a real, dimension(3,3)::z
z = a * 2
end function dobra_matriz
Quando a função é recursiva
Quando se deseja uma função recursiva, a opção
resulttem que ser utilizada (é obrigatório seu uso) e o prefixo
recursivo (recursive) também tem que ser utilizado na definição da função.
Exemplo:
recursive function fatorial(n) result(f) integer, intent(in):: n
integer:: f
if ( n <= 0 ) then f = 1
f = n * fatorial( n-1 ) end if
end function fatorial
Instrução RETURN
O retorno da função (
retorno = a função termina sua execução e passa o controle de volta para a unidade de controle que chamou a função) ocorre quando o procedimento (neste caso a função) encontra a instrução END.Entretanto há ocasiões em que é conveniente (ou necessário) retornar (terminar a execução do procedimento) em
outro ponto dentro do procedimento. Isto pode ser feito usando-se a instrução RETURN.
Quando o procedimento encontra a instrução return ele termina a sua execução e retorna o controle para a
unidade de programa que chamou o procedimento.
Exemplo:
A função s_err faz a adição de dois números inteiro. Entretanto, para a adição 2 + 2, a função
retorna um valor errado. Todas as outras somas do tipo inteiro estarão corretas.
integer function s_err(a, b) integer, intent(in):: a, b
if( (a == 2).and.(B == 2) ) then return s_err = 2
else
s_err = a + b end if
end function s_err
Instrução EXTERNAL e INTRINSIC
A instrução
externalé utilizada (escrita no procedimento) para especificar que o argumento mudo é uma função ou
uma sub-rotina escrita pelo programador (
o que chamamos de procedimento mudo).
Quando um argumento mudo é uma função é obrigatório o uso do atributo
external(e neste caso, o atributo de
intenção – intent – não pode ser usado simultaneamente).
Considere a existência de duas funções:
poli_1e
valor.As 2 funções são definidas pelo programador e estão
colocados no módulo
mod_f01:
module mod_f !
!
contains
real function poli_1(x) implicit none
real, intent(in):: x !<-- argumento mudo: intenção declarada (não é um procedimento)
!---! calcula o valor
poli_1 = 10.0 * ( cos(x) )**2
end function poli_1
real function valor(func,x) implicit none
real, intent(in):: x !<-- argumento mudo (não é procedimento - intenção declarada) real, external:: func !<-- procedimento mudo (é um procedimento, por isto a intenção ! não é declarada)
valor = func(x)
end function valor
end module mod_f
A função
valorrecebe uma função como argumento mudo, por este motivo, é obrigatório o uso do atributo
external
na declaração do argumento
func.
Um exemplo de programa que utiliza a função valor seria:
program exemplo_funcao_no_argumento !
use mod_f implicit none
real:: num, & ! número fornecido pelo usuário val ! valor calculado pela função valor
!---! Entra com dado
print*,"Entre com um número" read*, num
!---! calcula o valor usando a função
val = valor(poli_1, num) !<--poli_1 é uma função e num é um argumento
!---! saída do resultado
print*, "O valor calculado é ",val
end program exemplo_funcao_no_argumento
INTRINSIC
Caso o procedimento mudo seja uma
função intrínseca
, utiliza-se o
atributo
intrinsicna instrução que
especifica o tipo da função
no programa que referencia
(chama)
a função
. Então:
program exemplo_fi !
use mod_f implicit none
real:: num, & ! número fornecido pelo usuário val ! valor calculado pela função valor
real, intrinsic :: sin !<-- especifica que sin é uma função intrínseca
!---! entrada de dado
!--- print*,"Entre com um número"
read*, num
!---! cálculo
val = valor(sin, num) !<-- sin é uma função intrínseca e num é um argumento
!---! saída do resultado
print*, "O valor calculado é ",val
7. Sub-rotina
A diferença entre uma função e uma sub-rotina pode ser encontrada na forma como a sub-rotina é referenciada
(chamada) e como o resultado, se existir, é retornado.
Uma
função
é referenciado do mesmo jeito que uma variável, escrevendo-se seu nome, seguido dos argumentos
entre parenteses. A referencia (utilização) da função causa uma transferência do controle do programa que chama a
função para a função. Os argumentos são utilizados para comunicar valores entre o programa e a função. Depois de
calculado, o resultado da função é retornado ao programa e ele continua do ponto em que se encontrava quando
chamou a função. Por este motivo uma referência à uma função não é uma instrução completa (
não pode aparecer sozinha ou ser utilizada no lado esquerdo de uma instrução de atribuição).Uma
sub-rotina
por sua vez é referenciada (utilizada, chamada, executada) utilizando-se uma instrução
CALL(chama), que contem o nome da sub-rotina e a lista de argumentos reais entre parênteses. A instrução é usada assim:
call nome(arg1, arg2, ... )
A execução da instrução
CALLproduz uma transferência do controle para a sub-rotina especificada e passa os
valores dos argumentos reais para a sub-rotina. Ao retornar (tendo gerado um resultado ou não) a primeira instrução
ou construção executável depois da instrução
CALLé executada.
Não esqueça, diferentemente da função, que sempre retorna um valor ao programa que chamou a função, uma
sub-rotina pode ou não retornar um ou mais valores por meio de seus argumentos.
Exemplo:
subroutine raiz(x, r2, r3, r4, r5) implicit none
real, intent(in)::x !<-- argumento mudo de entrada real, intent(out)::r2, r3, r4, r5 !<-- argumentos mudos de saída real:: lx !<-- variável local
!---! cálculos
lx = log(x)
r2 = sqrt(x) ! raiz quadrada r3 = exp(lx/3.0) ! raiz cúbica r4 = exp(lx/4.0) ! raiz quádrupla r5 = exp(lx/5.0) ! raiz quíntupla !
end subroutine raiz
Variável Local
A variável lx definida na sub-rotina
não
é acessível fora da função
, portanto ela é uma
variável local
e não
tem existência fora da sub-rotina. Observe que variáveis locais não tem declaração de intenção.
Intenção dos Argumentos
Os argumentos mudos são declarados quanto a sua intenção: intent(in), intent(out) ou intent(inout).
Somente argumentos mudos podem ter a sua intenção declarada.
A vantagem de utilizar uma sub-rotina decorre do fato de se poder escrever uma única sub-rotina em vez de
escrever quatro funções (ou melhor, três pois a função raiz quadrada é intrínseca e portanto sempre disponível).
Um exemplo de utilização da sub-rotina raiz (contida no módulo mod_func) é:
program varias_raizes use mod_func
implicit none
real :: num, num_r2, num_r3, num_r4, num_r5
print*,"Entre com um número"
read*, num
! Calcula as raízes
call raiz(num, num_r2, num_r3, num_r4, num_r5) !<-- argumentos reais
! Saída de dados
print*,"A raiz quadrada de", num, "é:", num_r2 print*,"A raiz cúbica vale:", num_r3
print*,"A raiz quádrupla vale:", num_r4 print*,"A raiz quíntupla vale:", num_r5
end program varias_raizes
Quando a sub-rotina é recursiva
Quando se deseja uma sub-rotina recursiva o prefixo recursivo (recursive) tem que ser utilizado.
Exemplo:
recursive subroutine repete(n,x) integer,intent(inout):: x
integer, intent(in):: n
if (x < n) then x = x + 1
print"(a,i2)", 'x = ', x call repete(n,x)
end if
end subroutine repete
Instrução EXTERNAL
Uma sub-rotina pode ser passada como argumento (procedimento mudo) para uma função ou uma sub-rotina.
Quando isto é feito é necessário informar isto ao compilador.
A diferença agora é a impossibilidade do uso do atributo
externalporque sub-rotina não tem TIPO (sub-rotina não
tem variável resultado, portanto não permite o uso da instrução TIPO na sua definição). A forma de especificar que oargumento mudo é uma sub-rotina (procedimento mudo) é usar uma instrução
external(usar uma instrução não uma
especificação de atributo).
Considere a existência da função
poli_3e da sub-rotina
pontocolocadas no módulo
mod_s:
module mod_s !
!
contains !
real function poli_3(func, x) implicit none
real, intent(in):: x !<-- argumento mudo de entrada
external :: func !<-- especifica que é uma sub-rotina muda real::resp !<-- variável local
!--- ! executa a sub-rotina func
!---
call func(x,resp) !<-- x e resp são argumentos reais, porque estão sendo usados na ! chamada da sub-rotina
!--- poli_3 = 3.0 * resp**2
end function poli_3
subroutine ponto(x, re) implicit none
real, intent(in)::x !<-- argumento mudo de entrada real, intent(out)::re !<-- argumento mudo de saída
! implementa os cálculos re = 3.0 * exp(x)
end subroutine ponto !
end module mod_s
A função
poli_3utiliza uma sub-rotina como argumento mudo (
func), por este motivo, é obrigatório o uso da
instrução
external. Um exemplo de programa que utiliza um procedimento mudo é:
program exemplo_sr use mod_s implicit none
real:: num, & ! número fornecido pelo usuário kk ! valor calculado pela função valor
!--- ! entra com dado
!--- print*,"Entre com um número"
read*, num
!--- ! cálculo
!--- kk = poli_3(ponto, num) !<-- argumentos reais
!--- ! mostra resultado
!--- print*, "O valor calculado é ",kk
!---
end program exemplo_sr
8. Ordem das Instruções
A instrução de associação de uso tem que ser escrita depois da instrução inicial de abertura da unidade de
programa (
PROGRAM, FUNCTION, SUBROUTINEou
MODULE) e antes que qualquer outra instrução, conforme
Figura 01 - Ordem das Instruções no Fortran
A instrução
contém
(
contains) consiste de uma única palavra-chave (usada isoladamente) e tem que ser escrita
antes do primeiro procedimento escrito na unidade de programa.
9. Interface Explícita
Todo procedimento módulo tem uma interface explicita (
explicit interface). Isto garante que o compilador
Fortran pode verificar se a referência (chamada) do procedimento (função ou sub-rotina) está sendo feita de forma
apropriada (os argumentos são todos utilizados, estão escritos na ordem correta, são do tipo correto, etc...).
O padrão Fortran 2003 especifica que a interface de um procedimento módulo (escrito no módulo) é sempre
explícita para :
•
os outros procedimentos existentes no módulo
Visualização de Gráficos
10. Gnuplot
O gnuplot é um programa utilizado para a visualização de gráficos (
é muito comum o uso da expressão plotar um gráfico ou função).Por ser muito fácil de usar e muito poderoso será utilizado em nossa disciplina.
Consulte a
DFAT/Nota
Interna/FISCOMP-02 - Visualizador de Gráficos – Gnuplot 4.4
para mais detalhes.
No Linux o programa gnuplot é utilizado executando-se o programa num terminal.
•
Rodando o
gnuplotabra um terminal e digite o comando gnuplot, após algumas mensagens iniciais, o gnuplot irá
disponibilizar o prompt, que deve ser parecido com:
gnuplot> _
a partir deste momento o programa está disponível para uso
•
Finalizando o gnuplot
entre com um dos comandos
exit (escreva exit e depois pressione a tecla <enter>) ou quit (escreva quit e depois pressione a tecla <enter>) ou q (escreva q e depois pressione a tecla <enter>)
•
Os seguintes comandos estão disponíveis diretamente no prompt do gnuplot
pwd (escreva pwd e depois pressione a tecla <enter>)
cd ”dir-name” (muda para o diretório chamado dir-name, aspas obrigatórias)
•
Para executar comandos da shell dentro do gnuplot
entre com um ponto de exclamação e o comando
!ls (escreva !ls e depois pressione a tecla <enter>) !ls -l (escreva !ls -l e depois pressione a tecla <enter>)
•
Construindo um gráfico
para construir o gráfico da função seno digite o comando mostrado na sequência
gnuplot> plot sin(x)
assim mesmo:
plotseguido de
sin(x)este comando irá mostrar numa janela separada o gráfico da função seno
Para treinar: digite e execute os comandos mostrados no quadro que segue:
gnuplot> plot x**2 mostra a função x**2
gnuplot> plot [-20:20] [-1:100] x**2 mostra a função especificando os eixos x e y
gnuplot> f(x)=3*x**2 apenas define a função 3*x**2
•
Gráfico mostrando pontos
gnuplot> plot cos(x) with points lc 8 pt 4 lc => cor pt => símbolo
gnuplot> plot x**2 with points lc 3 pt 3
Abreviações são permitidas
. Os mesmos comandos podem ser escritos assim:
gnuplot> p cos(x) w p lc 8 pt 4
gnuplot> p x**2 w p lc 3 pt 3
gnuplot> p [0:10] [-1:1] cos(x) w p lc 9 pt 2
gnuplot> test Mostra uma tela contendo símbolos, cor e outras informações
Figura 02: Resultado do comando test do gnuplot para um terminal do tipo wxt
Exercício:
construa com linhas e depois com pontos os gráficos das seguintes funções:
y
=
5x
2−
2x
−
50
;y
=
sin
x
2
cos
x
;y
=
2cos
x
sin
2x
sin
4x
2
•
Gráfico com pontos colocados num arquivo
Dispondo-se de um arquivo de dados contendo somente colunas de números, é possível gerar um gráfico especificando-se as colunas com o comando using [ using xcol:ycol ]
using 1:1 => só primeira coluna
using 1:2 => x = primeira coluna y = segunda coluna
using 2:3 => x = segunda coluna y = terceira coluna
-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-arquivo: curvas.dados
contendo apenas valores numéricos
-.
-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-12.49 23.46 34.55 13.30 25.75 37.01 14.70 28.25 38.51 15.20 28.75 39.00
gnuplot> plot "curvas.dados" using 1:1 w lp
gnuplot> plot [0:20] [0:20] "curvas.dados" using 1:1 w lp
•
Script
os comandos utilizados no gnuplot podem ser colocados num arquivo (num script) e executados
posteriormente. Este processo agiliza muito o uso do gnuplot e torna o processo muito simples e bastante
poderoso.
Exemplo: script
aceleracao.plt#---# Propósito: mostrar o gráfico de uma partícula submetida a # uma aceleração descrita por 0.1*x**2-5*x+20 #---# Script: aceleracao.plt
# Autor: Anibal L. Pereira 11/01/2009 #Revisões:
#---reset
set xrange [0:25]
set title "Parabola Teste 1" set xlabel "Tempo (s)"
set ylabel "Aceleracao (m/s2)" f(x)=0.1*x**2-5*x+20
plot f(x) with lines lc 3
Observe que o símbolo # é utilizado para indicar um comentário.
Para executar este script basta carregá-lo com o comando:
gnuplot> load "aceleracao.plt"outro exemplo:
#--- # Propósito: mostrar gráfico com pontos guardados no arquivo # curvas.dados
#--- # Script: pontos.plt
# Autor: Anibal L. Pereira 11/01/2009 #Revisões:
#--- reset
set title "Arquivo curva_1.dados" set xlabel "x (m)"
set ylabel "altura (m)"
plot [10:20] [10:40]"curvas.dados" using 1:2 w p lt 4
reset
o comando reset limpa os ajustes anteriores, permitindo que o gráfico que vai ser construído não receba nenhuma definição anterior, a não ser as default do gnuplot
set title
o comando set title especifica um título para o gráfico
set xlabel e set ylabel
escrevem uma identificação nos eixos x e y
plot
11. Interpolação linear
Interpolação Linear
Interpolação linear é um método que permite ajustar uma curva usando-se um polinômio linear. É uma das
formas mais simples de interpolação.
O gráfico ao lado, mostra a interpolação linear entre
dois pontos
conhecidos.
Dado dois pontos (em vermelhos) a linha(em azul) é a interpolação
entre os dois pontos dados. O valor
x , y
pode ser obtido pelo
processo de interpolação linear.
Considerando os pontos
x
0, y
0
e
x
1, y
1
a linha reta que une
estes dois pontos é a interpolação linear.
Para um valor x no intervalo
x
0, x
1
, y (sobre a reta) é obtido pela
equação:
y
−
y
0x
−
x
0=
y
1−
y
0x
1−
x
0que pode ser facilmente obtido
usando-se a geometria.
Reescrevendo a equação temos:
y
=
y
0
x
−
x
0
y
1−
y
0x
1−
x
0que é a expressão, usualmente usada na fórmula da interpolação linear
no intervalo
x
0, x
1
A equação da interpolação linear pode ser escrita assim:
p
x
=
f
x
0
f
x
1−
f
x
0
x
1−
x
0
x
−
x
0
A interpolação linear é utilizada com muita frequência para obter valores intermediários (que não existem) numa
tabela. Observe que ela
utiliza apenas dois pontos da tabela
para realizar a interpolação.
12. Interpolação de Lagrange
Interpolação de Lagrange
A interpolação usando a fórmula de Lagrange (Joseph Louis Lagrange: 1736-1813) permite encontrar um
polinômio que serve de aproximação da curva definida pelo conjunto de pontos dados numa tabela. O método
usado na interpolação de Lagrange permite determinar o polinômio de menor grau que interpola os pontos dados.
i
x
y = f(x)
0
1
1
1
2
4
2
4
9
3
7
16
Admita que os (n+1) pontos-base
x
i, y
i
,
i
=
0,1 ,2
,
⋯
, n
de uma tabela
estão ordenados em ordem crescente e que o espaçamento entre eles não é
necessariamente
uniformemente espaçado.
A fórmula de interpolação de Lagrange de ordem n é dada pela equação:
P
n
x
=
∑
k=0
n
x
−
x
1
x
−
x
2
x
−
x
n
x
k−
x
1
x
k−
x
2
x
k−
x
n
y
k=
∑
k=0n
[
n
i=0
i≠k
x
−
x
i
x
k−
x
i
]
y
kAtente ao fato
de que a fração
x
−
x
k
x
k−
x
k
não pode aparecer na expressão, porque
assim evita- se que o número zero apareça no denominador
Fazendo-se k = 0, 1, 2, 3, . . . , n é usual definir-se o coeficiente de interpolação de Lagrange como sendo
expresso por:
L
k
x
=
x
−
x
1
x
−
x
2
x
−
x
n
x
k−
x
1
x
k−
x
2
x
k−
x
n
o que possibilita escreva a expressão assim:
P
n
x
=
∑
k=0
n
x
−
x
1
x
−
x
2
x
−
x
n
x
k−
x
1
x
k−
x
2
x
k−
x
n
y
k=
∑
k=0n
L
k
x
y
kUm exemplo torna claro o uso da fórmula.
Considere uma tabela contendo os seguintes pontos
x
i, y
j
,
i
=
0,1,2 ,3
i
x
y = f(x)
0
0
3
1
1
2
2
2
7
ordenados de forma crescente, mas não tendo espaçamento igual (
o intervalo de 2 para 4 é diferente dos outros intervalos).Os coeficientes de Lagrange para este conjunto (n+1 → 4 ponto) são:
L
0
x
=
x
−
x
1
x
−
x
2
x
−
x
3
x
0−
x
1
x
0−
x
2
x
0−
x
3
=
x
−
1
x
−
2
x
−
4
0
−
1
0
−
2
0
−
4
=−
1
8
x
3
−
7
x
2
14
x
−
8
L
1
x
=
x
−
x
0
x
−
x
2
x
−
x
3
x
1−
x
0
x
1−
x
2
x
1−
x
3
=
x
−
0
x
−
2
x
−
4
1
−
0
1
−
2
1
−
4
=
1
3
x
3
−
6
x
2
8
x
L
2
x
=
x
−
x
0
x
−
x
1
x
−
x
3
x
2−
x
0
x
2−
x
1
x
2−
x
3
=
x
−
0
x
−
1
x
−
4
2
−
0
2
−
1
2
−
4
=−
1
4
x
3
−
5
x
2
4
x
L
3
x
=
x
−
x
0
x
−
x
1
x
−
x
2
x
3−
x
0
x
3−
x
1
x
3−
x
2
=
x
−
0
x
−
1
x
−
2
4
−
0
4
−
1
4
−
2
=
1
24
x
3
−
3
x
2
2
x
Então o polinômio de Lagrange
P
n
x
=
∑
k=0
n
L
k
x
y
ké expresso por:
P
3
x
=
∑
k=0 3
L
k
x
y
k=−
3
8
x
3
−
7
x
2
14
x
−
8
2
3
x
3
−
5
x
2
4
x
−
7
4
x
3
−
5
x
2
4
x
59
24
x
3
−
3
x
2
2
x
ou
P
3
x
=
x
3−
2
x
3
.
Usualmente a expressão analítica do polinomial não é escrita, pois não se deseja conhecer a expressão do
polinômio, mas sim calcular um valor da tabela.
Não sendo necessário conhecer a expressão analítica do polinômio, o procedimento então é o de utilizar as
expressões dos coeficientes de Lagrange diretamente nos cálculos, evitando assim o processo (bastante trabalhoso)
de determinar a expressão analítica dos coeficientes de Lagrange.
O valor de y para x=3 (valor que não existe na tabela, portanto tem que ser interpolado), pode ser encontrado
facilmente com o polinômio interpolador de Lagrange (como temos a expressão analítica vamos utilizá-la):
f
3
≈
p
3
3
=
27
−
6
3
=
24
isto é, para x=3 → y=24
É
importante
saber que, na prática, o
grau máximo do polinômio interpolador é igual a 9
. Como o grau do
polinômio é igual ao número de pontos da tabela menos 1 (n+1-1 → n) isto implica em:
•
máximo 10 pontos-base
a tabela que será utilizada no processo de interpolação pode conter no máximo 10 pontos-base (n=9)
•
informar o grau do polinômio
neste caso a tabela de dados pode conter qualquer quantidade de pontos-base, mas é preciso garantir que o
processo utilize-se no máximo 10 pontos-base (mínimo de 2 e máximo de 10: isto vai depender do grau do
polinômio interpolador desejado) quando fizer o processo de interpolaçãoEsta Folha contém
07 Atividades
04 atividades exemplos
03 atividades exemplos com ajustes e/ou acréscimos
00 atividades para serem feitas
00 atividades para serem ajustadas e/ou acrescidas
Seu professor de laboratório (e/ou teoria) poderá alterar esta relação !
Atividade 01
Entregar em meio magnético:
1. programa: prog_fatorial fxxa1.f03
2. módulos: m_procedimentos_001 m_procedimentos_001.f03
3. arquivos: fatorial.dados
Exemplo:
Este programa exemplifica o uso de um procedimento módulo (uma função módulo)
O módulo contém os códigos fontes da função fatorial. A função fatorial não é uma função intrínseca, por isto tem que ser escrita pelo programador. O programa faz uso da função fatorial para calcular o fatorial de um número inteiro igual ou maior que 0 e igual ou menor que 12, depois salva o número fornecido e o fatorial do número num arquivo
Ao ler os códigos fontes da função fatorial, você verá que foi utilizada a instrução RETURN. A instrução return termina a execução da função quando é executada, isto é, no momento em que ela é (no ponto em que ela é) executada
Fatorial:
Fatorial de um número natural n, representado por n! , é o produto de todos os inteiros positivos menores ou iguais a n, ou seja, 5! = 5x4x3x2x1=120
Escreva o programa
prog_fatoriale salve-o no arquivo
fxxa1.f03Escreva o módulo
m_procedimentos_001e salve-o no arquivo
m_procedimentos_001.f03Não deixe de atualizar o cabeçalho de forma adequada.
Código da folha de atividades
Acesse a Home Page da disciplina, entre no link Datas-e-Atividades, para obter o código da folha de atividades. Toda atividade tem que ter o "xx" substituído pelo código indicado. Exemplos: código 02 ► fxxa3.f03 → f02a3.f03
Você pode copiar e colar os códigos fontes,
mas não deixe de ajustar a diagramação dos códigos
fontes segundo o estilo de programação adotado na disciplina
Para compilar e executar o programa:
Admitindo que:
fxxa1.f03 seja f04a1.f03•
depois de ter salvo os arquivos f04a1.f03 e m_procedimentos_001.f03 contendo os códigos fontes
•
compile o módulo
primeiro passo:
use o comando gfortran -c m_procedimentos_001.f03
Observe a chave de compilação -c
Esta chave -c faz somente a compilação do módulo, não cria um programa executável
O arquivo m_procedimentos_001.mod é um arquivo texto (pode ser lido com um editor de texto) e contém
informações que serão usadas pelo compilador quando ele for compilar o programa que usa este módulo
Um exemplo de conteúdo deste tipo de arquivo é mostrado no quadro que segue:
GFORTRAN module version '0' created from m_procedimentos_001.f03 on Sun Feb 20 10:27:54 2011 MD5:82685331b4fe490e4ac5608d99566473 -- If you edit this, you'll get what you deserve.
(() () () () () () () () () () () () () () () () () () () () () () () () () () ())
()
()
()
()
(2 'fatorial' 'm_procedimentos_001' 'fatorial' 1 ((PROCEDURE
UNKNOWN-INTENT MODULE-PROC DECL UNKNOWN FUNCTION) (INTEGER 4 0 0 INTEGER ()) 3 0 (4) () 2 () () () 0 0)
5 'm_procedimentos_001' 'm_procedimentos_001' 'm_procedimentos_001' 1 (
(MODULE UNKNOWN-INTENT UNKNOWN-PROC UNKNOWN UNKNOWN) (UNKNOWN 0 0 0 UNKNOWN ()) 0 0 () () 0 () () () 0 0)
4 'numero' '' 'numero' 3 ((VARIABLE IN UNKNOWN-PROC UNKNOWN UNKNOWN DUMMY) (INTEGER 4 0 0 INTEGER ()) 0 0 () () 0 () () () 0 0)
)
('fatorial' 0 2 'm_procedimentos_001' 0 5)
O segundo arquivo m_procedimentos_001.o contém códigos em linguagem de máquina (portanto não é
compreensível quando aberto num editor de texto. A figura foi feita usando um editor de arquivo binário), queserão necessários para a compilação do programa que usa o módulo
A figura mostra um pedaço do conteúdo do arquivo m_procedimentos_001.o
•
compile o programa
segundo passo:
use o comando gfortran -o f04a1 m_procedimentos_001.o f04a1.f03
Ao terminar você terá o programa executável f04a1
Resumindo:
Para compilar
, execute os comandos :
gfortran -c m_procedimentos_001.f03
gfortran -o f04a1 m_procedimentos_001.o f04a1.f03
Para executar
: f04a1 <enter>
_______________________________________________________________________________________
►
arquivo: fxxa1.f03◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
program prog_fatorial!
!--- ! Propósito: calcula o fatorial de um número entre 0 e 120
!
!--- ! Arquivo: fxxa1.f03
! Autor: Anibal L. Pereira 05/01/2010 !Revisões: Anibal L. Pereira 03/07/2010 !
!--- use m_procedimentos_001
implicit none
integer :: i, & ! número F ! fatorial
!--- ! solicita a entrada de um número entre 0 e 120
! repete a solicitação enquanto o número fornecido for ! menor que 0 e maior que 12
!--- print*
do
print*,"Escolha um número inteiro entre 0 e 12, inclusive" read*, i
if(i < 0 .or. i > 12) then print*
print*,"Escolha um inteiro no intervalo" print*
else print* exit end if end do
!--- ! calcula o fatorial usando a função definida pelo usuário !--- F = fatorial(i)
!--- ! Mostra o valor do fatorial
!--- print"(a,i2,a,i9)","O fatorial de ", i, " vale: ", F
print*
!--- ! Salva o número e o seu fatorial num arquivo
!---
open(unit=20, file="fatorial.dados", status="replace", action="write") write(unit=20,fmt="(i2,a,i9)") i," ", F
close(unit=20)
_______________________________________________________________________________________
►
arquivo: m_procedimentos_001.f03◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
module m_procedimentos_001!
!--- ! Propósito: Contém a função fatorial
!--- ! Arquivo: m_procedimentos_001.f03
! Autor: Anibal L. Pereira 05/01/2010 !Revisões: Anibal L. Pereira 03/07/2010
!--- ! [módulos ] nenhum
! [funções ] fatorial ![sub-rotinas] nenhuma
!---
public :: fatorial
contains
integer function fatorial(numero)
!--- ! Propósito: recebe um número inteiro menor ou igual a 12 e calcula o ! fatorial do número
!--- ! Autor: Anibal L. Pereira 05/01/2010
!Revisões: Anibal L. Pereira 03/07/2010 !
!--- implicit none
integer, intent(in):: numero integer:: i
!--- ! Fatorial de zero
!--- if(numero == 0) then
fatorial = 1 return end if
!--- ! Cálculo do Fatorial para números inteiros de 2 a 12 !--- i = numero
fatorial = numero do
i = i-1
if(i == 0 ) return fatorial = fatorial * i end do
end function fatorial
end module m_procedimentos_001
Atividade 02
Entregar em meio magnético:
1. programa: prog_mdc fxxa2.f03
2. módulos: m_procedimentos_002 m_procedimentos_002.f03
3. arquivos: mdc.dados
Exemplo:
O programa calcula o máximo divisor comum (MDC) entre dois números inteiros positivos usando o método de Euclides.
Método de Euclides:
Dado N1 e N2 onde N1 ≥ N2
PASSO 1: divide-se N1 por N2 para obter o resto R PASSO 2: se R é zero, N2 é o MDC
PASSO 3: se R for diferente de zero, N2 passa a ser N1 e R passa a ser N2, para então voltar ao passo 1
Observe que o processo é repetido até que R se torne zero
Auxílio: mdc(48,30)=6 mdc(20,12)=4
Escreva o programa
prog_mdce salve-o no arquivo
fxxa2.f03Escreva o módulo
m_procedimentos_002e salve-o no arquivo
m_procedimentos_002.f03Não deixe de atualizar o cabeçalho de forma adequada.
_______________________________________________________________________________________
►
arquivo: fxxa2.f03◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄►◄
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
program prog_mdc!
!--- ! Propósito: calcula o máximo divisor comum entre dois números inteiros positivos !--- ! Arquivo: fxxa2.f03
! Autor: Anibal L. Pereira 06/01/2010 !Revisões: Anibal L. Pereira 03/07/2010 !
!--- use m_procedimentos_002
implicit none
integer::n1, & ! primeiro número n2, & ! segundo número m, & ! mdc
prov ! usado para troca, se necessário
!--- ! entra com os dois números
!--- print*
print*,"Entre com dois números inteiros" read*, n1, n2
!--- ! certifica se n1 > n2 : troca se necessário
!--- if(n1 > n2) then
prov = n1 n1 = n2 n2 = prov end if
!--- ! calcula o MDC e mostra o resultado
!--- m = mdc(n1,n2)
!--- ! Mostra o resultado na tela do micro
!--- print*
print"(a,i3)","O Máximo Divisor Comum é", m
!--- ! salva os dados num arquivo
!---