Sie sind auf Seite 1von 165

Fortran 90/95

Joo Batista Aparecido

DEM/FEIS/UNESP
Ilha Solteira, SP/BR Agosto 2013

Fortran 90/95

Caros leitores:
Possveis correes/sugestes devem ser enviadas para JBA em
jbaparecido@dem.feis.unesp.br e/ou jbaparecido@gmail.com. Para efeito de referncia essa
a verso F9095.JBA.22.AGO.2013.
Cheers, JBA

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

Fortran 90/95

CAPTULO 1
INTRODUO LINGUAGEM FORTRAN
O ser humano sempre esteve envolvido com as questes de contar, calcular, e
armazenar informaes. Ao longo do tempo desenvolveu-se os mais variados objetos para
atingir estes objetivos. At uns trinta anos atrs utilizava-se nos cursos de engenharia as
rguas de clculo. Uma das mais importantes invenes deste sculo foi computador
eletrnico que realiza estes objetivos com razovel preciso e com bastante velocidade.
Um programa (ou conjunto de programas) armazenados na memria do computador
informa a ele qual seqncia de clculo necessria e em quais dados executar as instrues.
1.1 O computador
Na Figura 1.1 mostra-se um diagrama de bloco de um computador tpico, constitudo
pela Unidade de Processamento Central (CPU-Central Processing Unit), pela memria
principal, pela memria secundria, e pelas unidades de entrada e sada de dados.
Unidade de processamento central

Unidades de
entrada de
dados

Memria interna (registros)

Unidades
de sada de
dados

Unidade de controle

Memria
principal
Unidade de lgica aritmtica

Memria
secundria

Figura 1.1- Esquema de um computador.

1.1.1. A CPU
A parte principal do computador a Unidade de Processamento Central (CPU-Central
Processing Unit). Ela constituda pela Unidade de Controle, que controla as outras partes do
computador; pela Unidade de Lgica Aritmtica (ALU-Arithmetic Logic Unit); e pelas
memrias internas (tambm conhecidas como registros).
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

Fortran 90/95
A CPU interpreta as instrues dos programas; pega os dados nas unidades de entrada
de dados ou nas memrias principal e secundria e armazena-os nos registros; efetuas as
instrues aritmticas na ALU e armazena o resultado nos registros. Depois que estes dados
no so mais necessrios na CPU eles so armazenados na memria principal ou secundria.
1.1.2 Memria principal.
Como dito anteriormente o computador tem dois tipos principais de memria: a
principal e a secundria. A memria principal constituda em geral de chips semicondutores
e em geral constituda da memria de acesso randmico (RAM-Random Access Memory) e
de uma ou mais memrias Cache. A memria RAM utilizada para armazenar os programas
e os dados. As memrias Cache so de menor dimenso (em bytes), mais rpidas e mais caras,
e servem como repositrios intermedirios de informao entre a memria secundria, em
geral a mais lenta, e a memria RAM. Assim quando a CPU necessita de alguma informao
que no se encontra na memria RAM, ele a procura nas memrias Cache, se tambm no a
encontrar a, ento efetua a procura na memria secundria. Quando o processador encontra a
informao desejada na memria secundria, ele captura um bloco de informaes da
dimenso em bytes da memria Cache que vai armazenar aquelas informaes, assim quando
uma nova informao for necessria e no estiver disponvel na memria RAM, o processador
ir procur-la na memria Cache, uma vez que a esperana estatstica de que ela esteja l
grande. A memria principal, em geral, voltil, isto , quando o computador desligado a
informao ali contida corrompida.
1.1.3 Memria secundria.
A memria secundria em geral lenta, de grandes dimenses em bytes e de baixo
custo por unidade de informao armazenada. Como memria secundria pode-se mencionar:
discos rgidos, fitas magnticas, floppy-disks e discos compactos (CD-compact disk). Estes
acessrios mencionados que funcionam como memria secundria apresentam a capacidade
de armazenar as informaes de forma persistente ou no voltil. Pelo menos enquanto
estiverem funcionando adequadamente, podem ser desligados e a informao permanece sem
corrupo de seu contedo. Em geral so utilizados como uma extenso lgica da memria
principal, porm operando a velocidades bem mais baixas, ou como repositrio de informao
no voltil, como por exemplo o saldo bancrio das pessoas.
1.1.4 Unidades de entrada e sada de dados.
Dados so introduzidos no computador via teclado, microfone, unidades de disco,
unidades de fita, cmeras digitais, scanners, e placas de aquisio de dados.
Os dados podem sair do computador via impressora, tela, projetor multimdia, plotter e
auto-falante.
1.2 Representao de dados em um computador.
A atual tecnologia computacional baseia-se no fato de que uma dada poro de matria
est magnetizada ou no. Assim a atual tecnologia basicamente binria. Especula-se sobre a
explorao de outros princpios fsicos que implicariam em computadores baseados em
sistemas numricos no binrios. Vamos aqui considerar apenas o caso da tecnologia atual
que o binrio. Portanto, a memria de um computador constituda de chaves que podem
estar apenas nos estados ligado ou desligado. Cada chave ento representa apenas um dgito
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

Fortran 90/95
binrio, ligado ou desligado. Esta a menor informao que um computador representa,
conhecida como bit. Se interpretarmos o estado ligado como sendo o nmero um e o estado
desligado como sendo o nmero zero, podemos assim representar os nmeros zero e um. Em
geral precisamos trabalhar com nmeros que no sejam apenas o zero e o um. Pode-se
resolver esta questo juntando vrios bits, podendo representar nmeros maiores em um
sistema binrio.
O menor grupo de bits chamado de byte. Um byte um grupo de 8 bits agrupados em
conjunto para representar um nmero binrio.
O grupo de bits maior ou igual ao byte a palavra (word), que pode usar 1, 2, 4, 8 ou
mais bytes consecutivos para representar um nmero binrio. O tamanho das palavras variam
de computador para computador.
1.2.1 O sistema binrio de nmeros inteiros.
Pode-se representar nmeros inteiros em diferentes bases, por exemplo o nmero 354
no sistema decimal pode ser escrito como segue na bases binria

35410 3 102 5 101 4 100


1 2 8 0 2 7 1 2 6 1 2 5 0 2 4 0 2 3 0 2 2 1 21 0 2 0
O maior nmero que pode ser representado em um byte 11111111 que corresponde ao
nmero 255 (28-1) na base 10. Se transladarmos os nmeros de 0 a 255, 128 unidades para a
esquerda tem-se nmeros variando de 128 a +127. Da mesma forma com dois bytes pode-se
representar nmeros de 32.768 a +32.767 (65.535 = 216-1) e com quatro bytes de
-2147483648 a +2147483647 (4294967295 = 232-1). At o momento discutimos apenas o
armazenamento na memria de nmeros inteiros, na prxima seo veremos outros tipo de
dados.
Quando entramos via teclado com um nmero decimal em um programa Fortran, este
nmero ento convertido para o sistema de armazenamento natural do computador, o
binrio. Quando o computador vai imprimir um nmero, ele converte o nmero que est no
sistema binrio para decimal e imprime.
Como o sistema decimal pode ser convertido em binrio, outros sistemas de nmeros
tambm podem ser convertidos para binrios e vice-versa. Os outros sistemas de nmeros que
o Fortran 90 suporta so o Octal (base 8 = 23) e o Hexadecimal (base 16 = 24). Desta forma o
nmero 77 decimal pode ser representado da seguinte maneira nas diferentes bases
7710 10011012 1158 4D16 .

1.2.2. Tipos bsicos de dados do Fortran 90.


Manipulando-se a quantidade de bytes que se utiliza e o tipo de uso que feito destes
bytes em uma palavra pode-se armazenar na memria outros tipo de dados que no apenas
inteiros. Os tipo comuns de dados que se pode armazenar so: inteiros, reais, alfanumricos,
complexos e lgicos. No momento trataremos apenas dos inteiros, reais e alfanumricos.
Existe tambm os tipos de dados derivados, definidos pelo usurio (UDT-User Defined Type)
a partir destes cinco tipos fundamentais, mais adiante voltaremos aos tipos derivados ou
especiais.
1.2.2.1. Dados do tipo inteiro
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

Fortran 90/95
Como mostrado anteriormente, o tipo de dado inteiro consiste de uma quantidade de
inteiros positivos, uma de inteiros negativos e o zero. O tamanho da palavra para armazenar
inteiros varia de processador a processador (processador = computador + sistema operacional
+ compilador), mas os tamanho mais comuns so palavras de 1, 2, 4 e 8 bytes ou 8, 16, 32 e
64 bits. Em geral o maior e o menor inteiros representados so fornecidos por: maior
inteiro = 2n-1-1, e o menor inteiro = -2n-1, onde n a quantidade de bits da palavra.
1.2.2.2. Dados do tipo real
Os nmeros inteiros no conseguem representar nmeros racionais ou irracionais.
Tambm no representam nmeros muito grandes ou muito pequenos.
Para contornar estas duas deficincias de representao de nmeros no inteiros em uma
quantidade finita de bytes, os processadores incluem o tipo de dado real ou floating-point. O
tipo real armazena dados em um forma de notao cientfica. As duas partes de um nmero
expresso em notao cientfica so chamados de mantissa e expoente. Por exemplo no
nmero 5.7651010, a mantissa 5.765 e o expoente 10. No computador o sistema
semelhante, apenas a base numrica binria ao invs de decimal e os nmeros reais so
normalizados, ou seja o valor absoluto da mantissa maior ou igual a zero e menor que a
unidade. Quanto ao tamanho em bytes, os nmeros reais mais comuns nos processadores so
o tipo real de 4 bytes ou 32 bits. Os bits esto divididos em duas partes, a mantissa com 24
bits e o expoente com 8 bits. A mantissa contm um nmero normalizado e portanto entre
-1 e +1 e o expoente contm uma potncia de 2, suficientes para recuperar, aproximadamente,
o valor do nmero representado, como segue

valor do numero mantissa 2 exp oente .


Este tipo de representao no consegue representar exatamente todos os nmeros entre
zero e a unidade, visto que so infinitos e a quantidade de bits para represent-los finita. Em
conseqncia os dados do tipo real so caracterizados por dois indicadores: a preciso e a
faixa. Preciso a quantidade dgitos significativos que so preservados em um nmero, e a
faixa a diferena entre o maior e o menor nmero que pode ser representado. A preciso
depende do nmero de bits na mantissa e a faixa depende do nmero de bits no expoente.
Uma mantissa com 24 bits pode armazenar nmeros de -223 a +223, aproximadamente.
Convertendo para a base decimal tem nmeros de 107 a +107, ou seja com este tipo de
representao a preciso que se obtm de aproximadamente 7 dgitos decimais. Um
expoente com 8 bits pode representar nmeros entre 2-128 e 2128, ou seja entre 10-38 e 10+38.
Note que o tipo real de dados pode representar nmeros muito maiores ou muito menores que
o tipo inteiro pode, porm no caso de usar 4 bytes tem-se apenas uma preciso de 7 dgitos
decimais. Neste caso impossvel distinguir qualquer diferena entre os nmeros 1234567.1 e
o 1234567.2. Isto ocorre porque quando um nmero com mais de 7 dgitos decimais
armazenado em um tipo real com mantissa de 24 bits, o dgitos alm do stimo estaro
perdidos para sempre. Este o erro de arredondamento (round-off error).
1.2.2.3. Dados alfanumricos
O tipo de dado alfanumrico (character) consiste de caracteres alfanumricos e
smbolos. Um sistema tpico para representao de uma linguagem ocidental deve incluir os
seguintes smbolos:
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

Fortran 90/95
26 letras maisculas de A a Z;
26 letras minsculas de a a z;
10 nmeros 0 a 9;
Smbolos variados, tais como: !@#$%^&*(){}[],<>?/~;
Smbolos especiais requeridos pela linguagem, tais como: .
Uma vez que o nmero de caracteres usando por uma linguagem ocidental no excede a
256 (28) pode-se utilizar um byte para armazenar um dado caracter. Assim para armazenar 10
caracteres sero necessrio 10 bytes, e assim por diante. O conjunto de caracteres mais
utilizado no mundo ocidental o ASCII (American Standard Code for Information
Interchange). Existem outros sistemas semelhantes ao ASCII, tal como o BRASCII. Como
algumas linguagens tal como o Japons e o Chins tm milhares de smbolos
(aproximadamente 4000) faz-se necessrio um sistema com mais caracteres, assim surgiu o
Unicode que armazena cada caracter em 2 bytes podendo assim abrigar 65536 (216)
caracteres. Os primeiros 128 caracteres do Unicode so os mesmos do ASCII, ficando os
blocos restantes designados para as diferentes linguagens: Japons, Chins, Portugus,
Hebreu, Grego, Russo, rabe, etc.
1.3 Linguagens de computador.
Existem vrias camadas de linguagens entre o usurio e a mquina propriamente dita.
Duas delas mais familiares ao usurio so o sistema operacional e o compilador. Vamos nos
ater aqui ao compilador, mas no nos esqueamos que existem vrias outras camadas por trs
at chegar mquina fsica propriamente dita. Isto necessrio porque a mquina s entende
a linguagem dos fenmenos fsicos sobre os quais o computador baseia-se, enquanto os
usurios humanos preferem uma linguagem a mais prxima possvel de sua maneira de se
comunicar. Assim quase todas as linguagens de programao so de alto nvel. Em outras
palavras, quase todas apresentam recursos de alto nvel e algumas apresentam alguns recursos
de baixo nvel. A linguagem Fortran, consequentemente de alto nvel, com poucos recursos
de baixo nvel.
Existem trs famlias de linguagens computacionais: as orientadas a objeto (SmallTalk),
as orientadas a rotina (Fortran, Pascal e C), e as mistas (C++). Em cada um destes grupos
existem inmeras linguagens com as mais diferentes caractersticas. Hoje, as linguagens
dentro de cada grupo so muito parecidas na sua concepo geral, diferindo em detalhes, na
sintaxe e na semntica.
O Fortran existe a mais de 50 anos e uma linguagem projetada para cmputos
cientficos, tendo assim uma larga tradio em resolver problemas de engenharia e cincias
aplicadas em geral. Existem excelentes bibliotecas de rotinas cientficas escritas para esta
linguagem.
1.4 Histria do Fortran
O Fortran o av de todas as linguagens de computao. O nome FORTRAN
derivado de FORmula TRANslation. O Fortran foi criado originalmente na IBM entre 1954 e
1957. Este primeiro Fortran foi o Fortran I. Logo aps em 1958 a IBM lanou o Fortran II. A
evoluo do Fortran continuou rapidamente at o aparecimento do Fortran IV em 1962. Esta
verso do Fortran tinha muitas melhorias e tornou-se o standard da linguagem por 15 anos.
Em 1966 o Fortran IV foi a primeira linguagem a ser padronizada pela ANSI (American
National Standard Institute), sendo ento renomeado para Fortran 66.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

Fortran 90/95
Em 1977 o padro Fortran tem uma nova grande melhoria com sintaxe e comandos que
facilitavam a produo de programas estruturados. Este padro foi um sucesso e passou a ser
conhecido como Fortran 77, em uso corrente at o momento.
Novamente em 1990 o Fortran passou por uma grande mudana. O Fortran 90 um
superconjunto do Fortran 77 e estende a linguagem em novas direes. Entre as novidades
includas no Fortran 90 esto: livre formato do cdigo fonte, novas estruturas de arrays,
operao com arrays completos, tipos de dados derivados, e interfaces explicitas. O Fortran
90 j suportado pelos principais compiladores disponveis no mercado (Absoft, Digital,
Lahey, e Microsoft).
Outro grande aspecto do Fortran 90 suportar processamento paralelo SIMD (Single
Instruction Multiple Data), desde que a CPU tenham dois ou mais processadores.
Em 1995 surgiu uma pequena atualizao do Fortran 90, o Fortran 95. Ainda no
popular no Brasil.
Vamos nos dedicar prioritariamente ao Fortran 90, porm mostrando os aditivos feitos
no Fortran 95.
A forma fixa do cdigo fonte foi abandonada no Fortran90 e declarada obsolescente no
Fortran 95, significando que candidata a ser deletada do padro nas futuras verses do
Fortran.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

Fortran 90/95

CAPTULO 2
ELEMENTOS BSICOS DO FORTRAN 90
Neste captulo apresenta-se os elementos bsicos do Fortran 90. Ao final ser possvel
criar uma programa computacional para efetuar algum clculo simples.
2.1 O conjunto de caracteres do Fortran 90.
Cada linguagem tem um conjunto de caracteres bsicos. Tal como o Chins e o
Portugus, o Fortran 90 possui um conjunto bem definido de smbolos que podem ser usados.
Outros smbolos no so permitidos e causar erro de sintaxe no programa.
O alfabeto do Fortran 90 (Fortran character set) consiste de 59 smbolos mostrados na
Tabela 2.1.
Tabela 2.1 Conjunto de smbolos do Fortran 90.
Quantidade de smbolos
Descrio
Smbolo
26
letras maisculas
A-Z
10
nmeros
0-9
1
underscore
_
5
smbolos aritmticos + - * / **
17
smbolos variados
( ) . = , $ : ! % & ; < > ? branco
As letras minsculas a-z no fazem parte do conjunto de smbolos do Fortran90, mas
so suportadas por, praticamente, todos os compiladores. Em realidade, toda letra minscula
que encontrada pelo compilador convertida para letra maiscula, exceto em variveis do
tipo caracter onde, so consideradas como dados e portanto no so corrompidas. Assim, em
Fortran uma varivel escrita como velocidade a mesma escrita como Velocidade ou
VELOCIDADE.
2.2 A estrutura de uma declarao Fortran 90.
Um programa consiste de uma seqncia de declaraes destinadas a atingir um
determinado objetivo. As declaraes podem ser executveis e no-executveis. Declaraes
executveis descrevem aes que o programa deve realizar quando executado. As declaraes
no executveis provm informaes necessrias ao correto funcionamento do programa.
2.2.1 Formato livre do cdigo fonte.
At o Fortran 77 o formato do cdigo fonte era fixo, e ditado pelo antigo formato dos
cartes perfurados. Quem j utilizou cartes perfurados sabe que tinha 80 colunas, as
declaraes podiam ter no mximo 72 colunas, e deviam comear na stima coluna, e assim
por diante.
No formato livre atual no mais necessrio atender a estas restries. As declaraes
podem comear na primeira coluna e cada linha pode ter at 132 caracteres. Se a declarao
muito longa ento pode colocar o smbolo (&) e continuar a declarao na prxima linha.
Uma declarao pode usar at 40 linhas consecutivas.
No padro do Fortran 77 era praticamente obrigatrio o uso de labels, no Fortran 90 eles
continuam existindo mas so praticamente desnecessrios ou de uso restrito.
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

Fortran 90/95
Qualquer coisa que venha aps o smbolo ! ser interpretado como comentrio pelo
compilador. Este smbolo pode aparecer em qualquer coluna do programa e no apenas na
primeira coluna, como era no padro Fortran 77, neste caso o smbolo para comentrios era a
letra C.
O formato fixo foi declarado obsolescente no Fortran 95, significando que candidato a
ser deletado nas prximas verses do Fortran. Assim no use o formato fixo em qualquer
programa novo. Sempre use o cdigo fonte no formato livre quando escrevendo programas
em Fortran 90/95.
2.3 A estrutura de um programa Fortran 90.
Como dito anteriormente um programa Fortran um conjunto de declaraes
executveis e no executveis organizadas em uma ordem apropriada. Todo programa Fortran
pode ser dividido em at trs sees: declarao, execuo e terminao.
A seo de declarao consiste de um grupo de declaraes no-executveis, no
comeo do programa, que define o nome do programa e as variveis, bem como seus tipos,
que sero referenciados na seo de execuo.
A seo de execuo consiste de um conjunto de declaraes executveis descrevendo
as aes que o programa executar.
A seo de terminao consiste de declaraes parando o processamento do programa e
informando ao compilador onde o programa termina.
2.3.1 Estilo de programao
O Fortran case insensitive, isto , no diferencia entre letras maisculas e minsculas.
Como os compiladores atuais mostram na tela as palavras-chave em cor diferenciada do
restante, vou usar preferencialmente letras minsculas nos programas. Forme nomes para as
variveis que faam algum sentido e que no sejam muito longas. Utilize o underscore para
unir duas palavras, formando uma nica varivel, por exemplo, eixo_principal. Tambm
possvel desenvolver uma notao onde cada nome de varivel tem um radical inicial que
indica o tipo da varivel, por exemplo, int para inteiros, chr para caracter, bol para
lgicas, cpx para complexas, flt para reais (floating point) e assim por diante para outros
tipos de dados definidos pelo usurio. Desta forma, pode-se escrever os nomes int_vel,
chr_nome, bol_teste, cpx_angulo e flt_temperatura, para variveis do tipo inteiro, caracter, lgica,
complexa e real, respectivamente.
De qualquer forma, defina um estilo e siga-o em todo o programa, se possvel tambm
em outros programas que realizar, assim aumentaro as chances de reutilizao do cdigo.
2.3.2. Primeiro programa em Fortran 90
Na Listagem 2.1 apresenta-se um primeiro programa em Fortran 90 que contm os
principais elementos de todo programa Fortran 90.
Listagem 2.1 Um programa Fortran 90 simples.
!programador: joo batista aparecido
!data: 03 de dezembro de 1999
!modificado: 26 de julho de 2001
program primeiro_programa

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

10

Fortran 90/95
!Objetivo:
!Mostrar alguns aspectos bsicos de um programa Fortran 90.
!Somar dois nmeros reais x e y, colocar em uma varivel w, e !imprimir.
!declara variveis
real :: x, y, w
!atribui valores a x e y
x = 2.0
y = 3.0
w=x+y

!soma x e y

!imprime x, y e w
write(*,*) ' x = ',x,' y = ',y,' w = ',w
!termina o programa
stop
end program primeiro_programa

No programa acima percebe-se claramente o incio do programa, as declaraes no


executveis, as declaraes executveis e o final do programa.
2.4 Constantes e Variveis
Uma constante em Fortran um dado que definido antes do programa rodar, ou seja
durante a compilao, e no ser alterado durante a execuo do programa.
Uma varivel em Fortran um dado que pode mudar durante a execuo do programa.
O valor de uma varivel Fortran pode ser ou no ser inicializado antes do programa ser
executado.
Quando o compilador Fortran encontra uma constante ou uma varivel ele reserva um
bloco de memria, de dimenso adequada, para armazen-la.
Uma varivel ou constante em Fortran possui nome nico e duas destas grandezas no
podem ter o mesmo nome. No podero ter nomes que coincidam com palavras reservadas da
linguagem.
Use nomes de variveis com algum significado, sempre que possvel. Crie um
dicionrio de dados (variveis e constantes) para cada programa, visando facilitar a
manuteno.
2.4.1. Constantes e variveis inteiras
Conforme discutido anteriormente o tamanho (kind) de uma constante ou varivel
inteira depende da quantidade de bits utilizado para armazenar a informao. Para declarar
que uma varivel inteira numero_de_alunos procede-se da seguinte maneira
integer :: numero_de_alunos
numero_de_alunos = 30

ou de uma forma mais compacta


integer :: numero_de_alunos = 30

No caso de uma constante inteira, declara-se da seguinte maneira

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

11

Fortran 90/95
integer, parameter :: numero_de_alunos = 30

2.4.2. Constantes e variveis reais


Podem existir variveis e constantes de todos os tipos que o compilador suportar. Por
exemplo, variveis do tipo real podem ter diferentes tamanhos (kinds), mostrados na Tabela
2.2.
Tabela 2.2-Preciso e faixa de nmeros reais em vrios computadores.
nmero de
Computador nmero total nmero de preciso
de bits
bits
na decimal
bits
do
mantissa
expoente
32
24
7
8
VAX
64
56
15
8
32
24
7
8
IBM PC
64
53
15
11
32
24
7
8
Sun Sparc
64
53
15
11
Cray
64
49
14
15

faixa
expoente

do

10-38 a 1038
10-38 a 1038
10-38 a 1038
10-308 a 10308
10-38 a 1038
10-308 a 10308
10-2465 a 102465

Para declarar uma varivel real procede-se da seguinte forma


real :: x
x = 10.33

e no caso de uma constante real, como segue


real, parameter :: y = 10.33

2.4.3. Constantes e variveis lgicas


O Fortran 90 suporta variveis lgicas, as quais s podem assumir dois valores TRUE
ou FALSE. A maneira de declarar o tipo e atribuir valores a uma varivel lgica
logical :: w
w = .true.

ou
logical :: w = .true.

No caso de constantes lgicas, pode-se declar-las como


logical, parameter :: w = .true.

2.4.4. Constantes e variveis alfanumricas


O tipo de dados character consiste de grupos de smbolos alfanumricos. Pode-se
declarar o tipo e atribuir valores a uma varivel caracter das seguintes maneiras
character (len = 14) :: x, y, w

! variaveis com 14 caracteres

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

12

Fortran 90/95
character :: r,s
character(12) :: t,q
x = Joseh da Silva

! variaveis com 1 caracter


! variaveis com 12 caracteres
! atribui valores a x

O termo (len = 14) que aparece logo acima refere-se quantidade de caracteres na
varivel ou constante. Da mesma forma o termo (12) refere-se quantidade de caracteres.
Para se declarar constantes do tipo caracter, procede-se de maneira semelhante aos
casos de dados dos tipos inteiros, reais e lgicas, j comentados acima.
2.4.5. Definindo variveis inteiras ou reais por default ou explicitamente.
Se no for definido o tipo de uma varivel, por default ela ser inteira se comear com
I,J,K,L,M,N e real no restante dos casos. Este default pode ser alterado usando o comando
IMPLICIT.
O mais adequado usar nas declaraes iniciais de um programa a declarao implicit
none que obrigar o programador a definir todas as variveis sendo utilizadas, caso contrrio o
compilador acusar o erro.
2.4.6. Mantendo as constantes consistentes em um programa
Evite ficar definindo uma mesma constante em diferentes posies do programa com
diferentes precises. Por exemplo, suponhamos que existe uma constante chamada um_terco e
que vale um tero, assim evite num local definir um_terco = 0.33 e em outro um_terco =
0.33333.
Mantenha as constantes precisas e consistentes em todo o programa. Para melhorar a
consistncia e o entendimento do cdigo, d um nome cada constante importante e as use
pelo nome em todo o programa.
Mais adiante, em outro captulo, apresenta-se uma outra maneira de se evitar a
duplicidade e corrupo de constante, e mesmo de variveis, utilizando-se mdulos.
2.5 Declarao de atribuio e clculos aritmticos
Clculos so feitos em Fortran 90 utilizando-se declaraes de atribuio do tipo
nome_da_varivel = expresso_aritmtica

por exemplo k = k + 1. Neste caso a varivel k adicionada de uma unidade armazenada na


mesma posio de memria que k ocupava anteriormente soma.
Os operadores aritmticos do Fortran 90 so
+
*
/
**

adio
subtrao
multiplicao
diviso
exponenciao

Os operadores aritmticos mencionados acima so operadores binrios significando


que devem aparecer entre duas variveis tal como
a + b, a b, a*b, a/b, a**b,

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

13

Fortran 90/95
adicionalmente, os smbolos + e podem ocorrer como operadores unrios, significando que
podem ser aplicados a apenas uma varivel, como segue
+a ou b.

2.5.1 Aritmtica inteira


Aritmtica inteira aquela realizada apenas com nmeros inteiros. Aritmtica com
inteiros sempre produz resultados inteiros. Esta regra importante principalmente quando
existe diviso de dois inteiros, o resultado no poder ser fracionrio. Por exemplo
1/3 = 0, 2/3 = 0, 3/3 = 1, 4/3 = 1, 5/3 = 1, 6/3 = 2.

Preste ateno na aritmtica com inteiros. Diviso de inteiros sempre fornece resultados
inesperados.
2.5.2 Aritmtica real
Aritmtica real ou aritmtica de ponto flutuante (floating-point arithmetic) aquela
envolvendo constantes e variveis reais. A aritmtica real produz resultados reais que
geralmente espera-se. Por exemplo
1./3. = 0.333333, 2./3. = 0.666666, 3./3. = 1., 4./3. = 1.333333.

Preste ateno na aritmtica com reais. Devido preciso limitada, duas expresses
teoricamente idnticas podem freqentemente fornecer resultados ligeiramente diferentes.
2.5.3. Hierarquia das operaes
Freqentemente vrias operaes aritmticas ocorrem combinadas em apenas uma
expresso. Para remover qualquer ambigidade que poderia ocorrer se a ordem dos
operadores fosse alterada, Fortran 90 estabelece uma srie de regras que governam a ordem
que as operaes so realizadas em uma expresso. Estas regras so semelhantes s da
lgebra. As operaes so realizadas na seguinte ordem de prioridade
1) O contedo de todos os parnteses so calculados, partindo do mais interno para fora;
2) Todas as exponenciais so calculadas, operando da direita para a esquerda;
3) Todas as multiplicaes e divises so efetuadas, operando da esquerda para a direita;
4) Todas as adies e subtraes so avaliadas, operando da esquerda para a direita.
Se estiver em dvida, use parnteses o suficiente fazer que as equaes fiquem claras e
simples para entender.
2.5.4 Aritmtica mista
Quando operaes aritmticas so realizadas utilizando nmeros reais e nmeros
inteiros, ento diz-se que uma aritmtica mista. Quando somamos dois nmeros inteiros o
resultado ser tambm um inteiro. Quando somamos dois nmeros reais o resultado tambm
ser um nmero real. Mas o que acontecer quando, por exemplo, somamos um real e um
inteiro? Alm do mais existem muitas outras combinaes (em realidade infinitas) onde pode
aparecer reais e inteiros juntos. No caso que propus acima o que vai acontecer que o
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

14

Fortran 90/95
programa vai perceber que se est tentando somar um inteiro e um real, ento no processo de
soma o valor inteiro transformado para real (note que a varivel continua com o valor
inteiro) e somado com o outro real, resultando em um nmero real. Veja abaixo trs exemplos
de diferentes tipos de operaes
Tipo de expresso Operao Resultado Tipo de resultado
Expresso inteira
5/2
2
inteiro
Expresso real
5./2.
2.5
real
Expresso mista
5./2
2.5
real
necessrio muito cuidado em expresses mistas, principalmente onde exista diviso.
Seja o seguinte exemplo
2.0 + 1/3 + 1/5 + 1/7 = 2.0

As divises na expresso acima tem prioridade sobre a soma, os termos de cada diviso
tem apenas inteiros, ento uma aritmtica inteira, e o resultado das trs divises na
expresso sero zero (inteiro), o qual ser ento transformado para zero (real) e adicionado
com o 2.0, com resultado final igual a 2.0. Expresses do tipo misto so perigosas por que so
difceis de entender e podem produzir resultados enganosos. Evite-as sempre que possvel.
Uma soluo para este problema transformar (durante a operao) todos os valores inteiros
para reais. Veremos como fazer isto mais adiante.
2.5.5. Aritmtica mista e exponenciao
Existe uma situao onde a aritmtica mista desejvel, na exponenciao. Se temos
uma expresso
w = y**n

onde y um real negativo e n um inteiro. Os compiladores atuais interpretam esta expresso


como: tome o valor y e multiplique-o por si mesmo n vezes.
Por outro lado se temos a seguinte expresso
w = y**x

onde y real negativo e x tambm real, esta expresso ser calculada internamente no
computador da seguinte forma
w = exp(x*lny),
como y negativo o programa ser descontinuado devido ao erro fatal. Alguns compiladores
(nem todos) tem alguma habilidade em verificar se o real x pode ser representado de forma
exata por um inteiro. Caso a resposta seja positiva a exponenciao efetuada tal como no
caso em que o expoente era inteiro.
Use expoentes inteiros ao invs de expoentes reais, sempre que possvel. Nunca eleve
um nmero negativo a um expoente real.
2.6 Declarao de atribuio e clculos lgicos
Da mesma forma que clculos aritmticos, clculos lgicos tambm so efetuados com
declaraes de atribuio, que em geral tem a forma
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

15

Fortran 90/95
nome_da_varivel_lgica = expresso_lgica

A expresso lgica do lado direito da expresso acima pode ser qualquer combinao de
variveis lgicas, constantes lgicas e operadores lgicos. Um operador lgico um operador
sobre dados numricos, caracter ou lgico, fornecendo um resultado final do tipo lgico.
2.6.1 Operadores relacionais lgicos
Operadores relacionais lgicos so operadores com dois nmeros ou caracteres que
fornecem um resultado do tipo lgico (logical). O resultado depende da relao entre os dois
valores, por isto so chamados operadores relacionais. A forma geral do operador relacional
v1 operador v2
onde v1 e v2 so expresses aritmticas, variveis, constantes ou caracteres, e operador um
dos operadores relacionais mostrado na Tabela 2.3
Tabela 2.3-Operadores relacionais lgicos
Operao
Novo estilo Estilo antigo Significado
==
.eq.
igual a
/=
.ne.
diferente
>
.gt.
maior que
>=
.ge.
maior ou igual a
<
.lt.
menor que
<=
.le.
menor ou igual a
Se a relao entre v1 e v2 verdadeira o operador retorna .TRUE. como resultado, caso
contrrio retornar .FALSE. Por exemplo
3>5 = .false.; 3<5 = .true.; B<D = .true.
2.6.2 Operadores combinatoriais lgicos
Operadores combinatoriais lgicos so operadores com um ou dois operandos lgicos
que fornecem um resultado lgico. Existem quatro operadores combinatoriais binrios: .and.,
.or., .eqv., e .neqv.; e um operador unrio, .not.. A forma geral de uma operao com
combinatorial lgica com operador binrio
w1.operador.w2
onde w1 e w2 so expresses lgicas, variveis ou constantes, e .operador. um dos
operadores combinatoriais mostrados na Tabela 2.4.
Tabela 2.4-Tabela da verdade para operadores combinatoriais lgicos.
w1
w2
w1.and.w2
w1.or.w2
w1.eqv.w2 w1.neqv.w2
.false. .false. .false.
.false.
.true.
.false.
.false. .true. .false.
.true.
.false.
.true.
.true. .false. .false.
.true.
.false.
.true.
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

16

Fortran 90/95
.true.

.true.

.true.

.true.

.true.

.false.

Na Tabela 2.5 apresenta-se a tabela da verdade para o operador unrio .not.


Tabela 2.5- Tabela da verdade para o operador unrio .not.
w1
.not.w1
.false.
.true.
.true.
.false.
Na hierarquia das operaes, os operadores lgicos combinatoriais so calculados
depois das operaes aritmticas e de todos os operadores lgicos relacionais. A ordem na
qual os operadores em uma expresso so executados :
1) Todos os operadores aritmticos so calculados de acordo com a seqncia apresentadas
anteriormente;
2) Todos os operadores relacionais (==, /=, >, >=, <, <=) so calculados, operando da
esquerda para a direita;
3) Todos os operadores .not. so executados;
4) Todos os operadores .and. so executados, operando da esquerda para a direita;
5) Todos os operadores .or. so executados, operando da esquerda para a direita;
6) Todos os operadores .eqv. e .neqv. so executados, operando da esquerda para a direita.
2.7 Declarao de atribuio e variveis do tipo caracter
Manipulaes de variveis do tipo caracter so efetuadas com a seguinte declarao de
atribuio
nome_da_varivel_caracter = expresso_com_variveis_caracter.
Um operador caracter (character operator) aquele que opera em dados que permitem
um resultado do tipo caracter. Se o lado direito da expresso acima menor do que o da
esquerda, algumas posies so ocupados com os caracteres atribudos e o restante
preenchido com brancos.
Porm se o lado direito maior do que o da esquerda, os caracteres em excesso sero
descartados. Por exemplo, a declarao
character (len = 5) :: x
x = ijk

armazena o valor ijk na varivel x, enquanto que


character (len = 2) :: x
x = ijk

armazena o valor ij na varivel x.


2.7.1 Especificao de sub-caracteres
A especificao de sub-caracteres seleciona uma parte de uma varivel caracter e a trata
como se fosse uma varivel independente. Esta especificao de sub-caracteres definida
colocando-se valores inteiros que representem o incio e o final dos caracteres selecionados,
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

17

Fortran 90/95
colocando-os entre parentes e separados por vrgula, logo aps o nome da varivel. Por
exemplo se
a = abC4567
b = a(3:5)

ento b = C45.
2.7.2 Operador de concatenao
O operador (//) combina duas ou mais variveis caracter para formar ou outra. Por
exemplo, a seguinte seqncia
a = abcdef
b = 1234567
c = a(1:2)//b(3:4)//a(3:6)

ir produzir o resultado c = ab34cdef.


2.7.3. Operadores relacionais lgicos com variveis do tipo caracter
Como j se disse anteriormente, existem certos padres normalizados de dados do tipo
caracter, por exemplo o ASCII. Se um caracter igual ou diferente de outro fcil. No
entanto difcil dizer se um caracter , por exemplo, maior que outro. A seguinte expresso
a<A verdadeira ou falsa? Dentro do padro ASCII a expresso falsa, por que o A o
elemento de nmero 65, e a o de nmero 97. Por esta conveno a maior que A. Isto
pode levar a resultados surpreendentes se o usurio mover o seu programa de um local com
padro para outro com outro padro. A seqncia de caracteres pode variar de forma
catastrfica.
Uma segunda pergunta interessante : Como comparar variveis do tipo caracter com
vrios caracteres. Por exemplo: BBBCFR maior ou menor que BBC? O algoritmo usado
no compilador Fortran 90 compara o primeiro caracter de cada varivel, no caso so iguais, a
compara-se os segundos caracteres, tambm so iguais; ento compara-se os terceiros
caracteres que so diferentes, o C maior que o B, ento BBC>BBBCFR.
Evite usar operadores lgicos relacionais operando em variveis do tipo caracter.
2.8 Funes intrnsecas
Existe um subconjunto das funes matemticas que associa a um ou mais argumentos
um nico resultado. Nos clculos tcnicos e cientficos faz-se necessrio calcular diferentes
tipos de funes. Estas funes podem muitas vezes ser escritas como combinao de outras
funes mais bsicas. O compilador Fortran 90 apresenta um conjunto, aproximadamente
112, destas funes bsicas, chamadas funes intrnsecas (intrinsic functions).
Caso o usurio no consiga reduzir sua funo de interesse a combinaes das funes
intrnsecas, ser necessrio desenvolver uma nova, a partir dos fundamentos do clculo.
Funes criadas pelo prprio usurio podem ser definidas como funes externas (external
function)ou funes internas (internal function). Retornaremos a este assunto mais adiante.
Abaixo, na Tabela 2.6, apresenta-se algumas das funes intrnsecas suportadas pelo Fortran
90/95.
Tabela 2.6 Vinte funes intrnsecas suportadas pelo Fortran 90/95.
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

18

Fortran 90/95
Funo
e Definio
argumentos
matemtica
sqrt(x)
x
abs(x)
|x|
achar(i)
sin(x)
sin(x)
cos(x)
cos(x)
tan(x)
tan(x)
exp(x)
ex
log(x)
loge(x)
log10(x)
log10(x)
iachar(c)
int(x)
nint(x)
real(i)
mod(a,b)
a-p*int(a/p)
max(a,b)
min(a,b)
asin(x)
sin-1(x)
acos(x)
cos-1(x)
atan(x)
tan-1(x)

Tipo
de
argumento
real
real/inteiro
inteiro
real
real
real
real
real
real
char(1)
real
real
inteiro
real/inteiro
real/inteiro
real/inteiro
real
real
real

Tipo
de
resultado
real
real/inteiro
char(1)
real
real
real
real
real
real
inteiro
inteiro
inteiro
real
real/inteiro
real/inteiro
real/inteiro
real
real
real

Comentrios
raiz quadrada de x
valor absoluto de x
retorna caracter ASCII
seno de x
co-seno de x
tangente de x
exponencial de x
logaritmo natural de x
logaritmo base 10 de x
posio de c no ASCII
parte inteira de x
inteiro prximo de x
converte inteiro para real
resto de a/b
pega o maior de a e b
pega o menor de a e b
inverso do seno de x
inverso do co-seno de x
inverso da tangente de x

Note que na tabela acima tem uma funo para converter inteiros em reais, evitando
assim os inconvenientes da aritmtica mista. Esta funo a real(i). Assim a expresso
2.0 + 1/5 = 2.0

pode ser re-escrita como


2.0 + real(1)/real(5) = 2.2.

2.9 Declaraes de entrada e sada de dados


Uma declarao de entrada de dados l um ou mais dados de um equipamento de
entrada de dados. Da mesma forma uma declarao de sada de dados escreve um ou mais
dados em um equipamento de sada de dados.
Uma forma simplificada de declarao de entrada de dados
read(*,*) lista_de_variveis.
Analogamente, uma declarao de sada de dados
write(*,*) lista_de_variveis.
Abaixo apresenta-se um exemplo que l duas variveis inteiras e imprime as duas
inteiras e mais duas reais j definidas no programa
Listagem 2.2 Programa para demonstrar capacidades mnimas de entrada e sada de dados.
program entrada_saida
integer :: i,j

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

19

Fortran 90/95
real

:: p = 1.0, q = 7.0

write(*,*)'digite i e j'
read(*,*)i,j
write(*,*)i,j,p,q
stop
end entrada_saida

Imprima na tela, quando possvel, todas as variveis que so lidas por um programa,
para certificar que foram digitadas e processadas corretamente.
2.10 Inicializao de variveis
Considere o seguinte programa
program inicializa
integer :: m
real :: x
write(*,*) m,x
end program inicializa

Uma vez que as variveis m e x no foram inicializadas, quando so impressas podem


conter qualquer valor que represente o estado dos bits daquelas posies de memria que o
compilador lhes atribuiu. Alguns compiladores zeram as variveis no inicializadas. Em todo
o caso os resultados podem ser catastrficos.
Sempre que possvel, inicialize todas as variveis de um programa antes de us-las.
2.11 Declarao implicit none
Uma declarao no executvel de muita utilidade a implicit none. Quando utiliza-se
implicit none todos os defaults de digitao so desabilitados e o programador ter
obrigatoriamente que definir todas as variveis utilizadas. Se algumas varivel foi digitadas
errada, quando da compilao o compilador emitir um erro indicando que existe uma
varivel no declarada. A declarao implicit none dever aparecer logo aps a declarao
program e antes das declaraes de tipos de variveis.
Defina sempre e explicitamente todas as variveis do programa e use a declarao
implicit none para ajudar a localizar variveis no declaradas e variveis digitadas
incorretamente.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

20

Fortran 90/95

CAPTULO 3
ESTRUTURAS DE CONTROLE
Um programa Fortran pode ser apenas seqencial, como nas listagens apresentadas no
Captulo 2, onde todos os comandos vo sendo executados um aps o outro at chegar ao final
do programa, sem haver nenhuma iterao ou desvio. Entretanto existem problemas onde,
dependendo dos dados, deseja-se executar apenas uma parte do programa deixando o restante
sem executar. Para criar este efeito necessita-se de estruturas de programao mais complexas
do que as vistas at o momento. Estas estruturas de controle podem ser classificadas em dois
grupos: laos (ciclos, loops), onde o programa fica executando um conjunto de declaraes
ciclicamente; e bifurcaes (branches), onde o programa chega a um determinado ponto da
execuo e toma a deciso em dos qual dos ramos da bifurcao o processamento continuar.
Este captulo trata basicamente das implementaes no compilador Fortran 90, destes dois
conceitos: laos e bifurcaes.
3.1 Bifurcaes
Como estabelecido acima as bifurcaes selecionam pores de cdigo que sero
executadas, enquanto salta outras pores que no sero executadas. Basicamente, tem-se
algumas variantes da declarao IF, e a declarao SELECT CASE.
3.1.1. Estrutura do tipo bloco IF
A forma mais comum de declarao IF o bloco IF. Esta estrutura define que um
determinado bloco de cdigo s ser executado se uma determinada expresso lgica for
verdadeira. Caso contrrio o bloco de cdigo ser saltado e portanto no executado. A forma
do bloco IF
if (expresso_lgica) then
declaraes_executveis
end if

Sempre indente o corpo de um bloco IF de alguns espaos para melhorar a leitura do


cdigo.
3.1.2. Estrutura do tipo ELSE e ELSE IF
Na estrutura bloco IF mostrada acima uma poro do programa executada se uma
expresso lgica verdadeira. Se for falsa o bloco de declaraes simplesmente pulado. No
entanto existem situaes onde deseja-se executar um bloco de declaraes se a expresso
lgica for verdadeira, e um outro bloco se a expresso lgica for falsa. Uma declarao ELSE
seguida de nenhuma, uma ou mais declaraes ELSE IF podem ser adicionadas ao bloco IF,
para satisfazer este tipo de necessidade.
O bloco IF com declaraes ELSE e ELSE IF tem, por exemplo, a seguinte forma
if (expresso_lgica_1) then
declaraes_executveis_1
else if (expresso_lgica_2) then
declaraes_executveis_2
else

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

21

Fortran 90/95
declaraes_executveis_3
end if

Na estrutura mostrada acima se a expresso_lgica_01 for verdadeira executa-se ento


declaraes_executveis_1 e a estrutura completa sua tarefa. Se a expresso_lgica_1 for falsa o
programa verifica se a expresso_lgica_2 verdadeira ou falsa. Se for verdadeira executa-se
declaraes_executveis_2, se for falsa executa-se declaraes_executveis_3.
A forma mais simples da estrutura ELSE
if (expresso_lgica_1) then
declaraes_executveis_1
else
declaraes_executveis_2
end if

3.1.3. Estrutura do tipo IF, nomeado


Todas as formas de declarao IF podem ser nomeadas. Isto , pode-se dar nomes a
cada uma destas estruturas. A forma do bloco IF nomeada ser ento
nome: if (expresso_lgica) then
declaraes_executveis
end if nome

O bloco IF com declaraes ELSE e ELSE IF nomeado tem a seguinte forma


nome: if (expresso_lgica_1) then
declaraes_executveis_1
else if (expresso_lgica_2) then
declaraes_executveis_2
else
declaraes_executveis_3
end if nome

Quando tem-se estruturas com muitos laos e bifurcaes indentados uns dentro dos
outros, caso ao digitar seja esquecido alguma declarao end, o compilador acusar um erro
que muitas vezes difcil de encontrar. A nomeao destas estruturas opcional mas pode ser
usada para evitar ambigidades e facilitar a leitura e a manuteno do cdigo.
Destine um nome a todas as estruturas grandes e complicadas de IFs do programa, para
facilitar a leitura e a manuteno.
Abaixo apresenta-se um programa exemplo deste tipo IF nomeado
program if_nomeado
logical :: l1 = .true., l2 = .false., l3 = .true.
integer :: i
externo: if(l1) then
i=1
medio: if(l2) then
i=2
interno: if(l3) then
i=3
end if interno
end if medio

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

22

Fortran 90/95
end if externo
stop
end program if_nomeado

3.1.4 Declarao IF lgico


Quando a estrutura bloco IF tem apenas uma declarao executvel ento ela assume
uma forma especial mais simplificada. Torna-se ento uma declarao de apenas uma linha,
como segue
if(expresso_lgica) declarao_executvel

3.1.5 A estrutura CASE


A estrutura CASE uma forma de implementar mltiplas bifurcaes simultneas.
Permite ao programador escolher um determinado bloco de cdigo a ser executado, entre
vrios, baseando em uma expresso envolvendo dados dos tipos inteiro, caracter e lgico. A
forma geral da estrutura CASE
nome: select case (expresso_case)
case (seletor_case_1) nome
declaraes_executveis_1
case (seletor_case_2) nome
declaraes_executveis_2
case (selector_case_3) nome
declaraes_case_3

case default nome


declaraes_default
end select nome

Se

expresso_case
estiver de acordo com o seletor_case_1 as
declaraces_executveis_1 sero executadas e o restante ser pulado. O mesmo acontece se a
expresso_case estiver de acordo com o seletor_case_2 as declaracaoes_executveis_2 sero

executadas e o restante ser pulado. E assim por diante.


Se a expresso_case no estiver de acordo com nenhum dos seletor_case, ento as
declaraes_default sero executadas. O case default opcional, e ser executado quando a
expresso_case no coincidir com nenhum seletor_case. Caso no exista o case default e a
expresso_case no atenda nenhum dos seletor_case, ento nenhum dos blocos ser executado.
Abaixo apresenta-se um exemplo de utilizao da declarao select case
! Objetivo: Demonstrar a utilidade da declarao CASE
! Distingue entre as palavras faca, garfo, e colher.
program select_case
character(6) :: x
write(*,*)'Digite o talher!'
read(*,*)x
select case(x)
case ('faca')
write(*,*)'O talher uma faca'

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

23

Fortran 90/95
case ('garfo')
write(*,*)'O talher um garfo'
case ('colher')
write(*,*)'O talher uma colher'
case default
write(*,*)'No faca, nem colher, muito menos um garfo.'
end select
stop
end program select_case

3.2 Laos
Laos so estruturas de controle que permitem a execuo de um bloco de cdigo vrias
vezes em seqncia. As duas formas bsicas de laos so: laos com terminao indefinida, e
laos com terminao bem definida. No existe um lao puro, uma vez que o mesmo se
repetiria eternamente. Assim todo lao possui na sua estrutura (implcita ou explicitamente)
uma bifurcao responsvel pela sada do lao. Nos laos de terminao indefinida, o lao
continua indefinidamente at que uma da condio de controle seja atendida e completa-se a
execuo do lao. Se no for bem projetado este tipo de lao pode continuar indefinidamente.
Por outro lado o lao com terminao bem definida, executa uma quantidade finita de laos e
termina sua execuo. Neste caso no h o risco da execuo continuar indefinidamente.
3.2.1. O lao com terminao indefinida
Como falado acima, este tipo de lao executa um bloco de declaraes indefinidamente
at que uma determinada condio seja atingida. A forma geral desta declarao em Fortran
90/95
do
declaraes_executveis_1
if(expresso_lgica) exit
declaraes_executveis_2
end do

Abaixo apresenta-se um exemplo deste tipo de lao


! Testando um lao indefinido
program looping
integer :: i = 0
do
i = i+1
if(i >= 10) exit
write(*,*) i
end do
stop
end program looping

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

24

Fortran 90/95
Na estrutura acima o bloco de declaraes executveis entre do e end do ser executado
indefinidamente at que a expresso_lgica seja verdadeira. Existe a possibilidade de que este
tipo de laos nunca atinja terminao. Embora, neste caso seja claro que a terminao do lao
seja atingida, entretanto em caso em que a expresso_lgica seja complexa difcil de se saber.
3.2.2. Outra implementao do lao com terminao indefinida
O compilador do Fortran 90/95 tem uma forma alternativa, mais simples, de
implementar a estrutura mostrada no item anterior. Este caso eqivale ao mostrado acima
onde no se tenha nenhuma declarao no sub-bloco declaraes_executveis_1, assim esta
implementao alternativa, chamada de do while tem a seguinte forma
do while (expresso_lgica)
declaraes_executveis
end do

Nesta estrutura acima o bloco de declaraes_executveis ser executada


indefinidamente, enquanto a expresso_lgica for verdadeira. Neste tipo de estrutura tambm
possvel que o lao no atinja terminao.
3.2.3. O lao com terminao bem definida
Este tipo de lao tem terminao garantida porque o lao ser executado uma
quantidade bem definida de vez e ento terminar. s vezes este tipo de lao pode ser
chamado tambm de lao iterativo ou lao com contagem. O lao com contagem construdo
da seguinte forma
do index = i_start, i_end, i_incr
declaraes_executveis
end do

onde index uma varivel do tipo inteiro usada como um contador do lao. A variveis
inteiras i_start, i_end e i_incr so parmetros do lao de contagem, elas controlam os valores
assumidos por index durante a execuo do lao. O parmetro i_incr opcional e o seu valor
default a unidade. Os valores assumidos por index comeam com o valor i_start, vai sendo
acrescido de i_incr, at atingir o valor i_end, inclusive. O critrio de parada do lao em
realidade index*i_incr > i_end*i_incr, definido desta forma esta mais apto a tratar de casos
patolgicos. Entretanto, testando o caso patolgico onde i_incr = 0, o compilador (Microsoft
V4) no acusou erro e o programa quando rodou foi descontinuado por erro fatal. O nmero
total de iteraes (i_iter) que ser executado em um lao de contagem pode ser obtido
aproximadamente por i_iter = (i_end-i_start+i_incr)/i_incr.
A varivel de controle index tem um escopo interno do lao, no devendo ser
modificada (externamente) durante a execuo do lao.
Pode ser inserido um comando IF (expresso_lgica) EXIT no interior deste tipo de lao
para provocar uma interrupo precoce quando a expresso_lgica for verdadeira.
Aps o trmino do lao DO o valor da varivel de controle index indefinido
(dependendo de cada implementao de compilador), na maioria dos casos seu valor (i_end
+ 1). Portanto, nunca dependa do valor de uma varivel de controle de lao de DO depois que
o lao termina.
proibido fazer um desvio incondicional (go to) de fora para dentro de um lao DO.
A seguir tem-se uma implementao deste tipo de lao
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

25

Fortran 90/95
! Testando um lao definido
program looping_2
integer :: i = 0, i_start = 1, i_end = 10, i_incr = 1
do i = i_start, i_end, i_incr
write(*,*) i
end do
stop
end program looping_2

Nunca use incremento nulo em laos de contagem e nunca modifique o valor da


varivel de controle de lao DO enquanto o lao est sendo executado.
O uso de varivel real como varivel de controle de lao de DO foi declarado
obsolescente no Fortran 90 e foi deletado do Fortran 95.

3.2.4. As declaraes CYCLE e EXIT


Pode-se utilizar adicionalmente as declaraes cicle e exit para controlar as operaes
enquanto executa-se algum tipo de lao.
Se a declarao cicle for usada dentro de um lao a execuo ser parada e o controle
retornar ao comeo do lao. A varivel de controle ento ser incrementada e o
processamento continuar. Abaixo mostra-se um exemplo de tal aplicao
program cycling
integer :: i, m = 10
do i = 1, m, 1
if(i == 5) cycle
write(*,*) i
end do
stop
end program cycling

Quando a declarao EXIT utilizada dentro de um lao de DO a execuo do lao ser


interrompida e o controle da execuo ser passada para a primeira declarao executvel
aps o lao. Adaptando-se o exemplo acima para testar o efeito da declarao EXIT tem-se
program exiting
integer :: i, m = 10
do i = 1, m, 1
if(i == 5) exit
write(*,*) i
end do
stop
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

26

Fortran 90/95
end program exiting

3.2.5 Laos nomeados


Da mesma maneira que as bifurcaes (IFs) podem ser nomeadas, os laos (DOs e
WHILEs) tambm podem. Os dois tipos principais de laos podem ser nomeados da seguinte
maneira
nome: do
declaraes_executveis_1
if(expresso_lgica_1) cycle nome
declaraes_executveis_2
if(expresso_lgica_2) exit nome
declaraes_executveis_3
end do nome
nome: do index = i_start, i_end, i_incr
declaraes_executveis_1
if(expresso_lgica_1) cycle {nome}
declaraes_executveis_2
if(expresso_lgica_2) exit {nome}
declaraes_executveis_3
end do nome

D nomes aos principais laos no programa para deixar claro quais declaraes
executveis pertencem a um determinado lao.

3.4.6. Ninho de laos


Quando vrios laos esto um dentro do outro, diz-se que o laos esto aninhados ou
que formam um ninho de laos. Abaixo tem-se um exemplo deste tipo de ninho de laos
nome_2: do
declaraes_executveis_1
nome1: do
declaraes_executveis_2
if(expresso_lgica_1) cycle nome_1
declaraes_executveis_3
if(expresso_lgica_2) exit nome_2
declaraes_executveis_4
end do nome_1
declaraes_executveis_5
end do nome_2

As declaraes cycle e exit que aparecem acima tm que referir a qual lao a
declarao se aplica quando existe mais de um lao. Se estas declaraes no tiverem
referncias a qual lao se aplicam, ento se aplicaro ao lao externo mais imediato no sentido
de dentro para fora.
Use declaraes CYCLE e EXIT nomeadas em ninho de laos para deixar claro que a
declarao afete o lao correto.
3.3 A declarao GO TO
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

27

Fortran 90/95
Muitos dizem: programas que contm GO TO no so bons programas. Esta afirmao
no necessariamente verdadeira. Conceitualmente, o GO TO importante, alm do mais
necessrio. Prova disto que todas as linguagens possuem o conceito de GO TO. O uso
excessivo de GO TO deve ser evitado porque tende a produzir cdigos difceis de entender e
de manter, no entanto existem situaes onde seu uso necessrio. O GO TO em realidade
um desvio incondicional, sob este ngulo as declaraes CYCLE e EXIT cumprem o mesmo
papel, porm de uma forma menos selvagem uma vez que seu desvio incondicional para
alguma posio bem sabida, evitando assim programas com lgica desnecessariamente
complexa. Evite usar, na medida do possvel, GO TO em programas, use as estruturas IF, CASE
SELECT, CYCLE, EXIT, que na maioria das vezes vai produzir o mesmo efeito, porm com um
melhor controle do cdigo. No use outros formatos de GO TO, pois esto destinados a
desaparecer da linguagem, restar apenas o GO TO simples.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

28

Fortran 90/95

CAPTULO 4
CONCEITOS BSICOS DE ENTRADA E SADA DE DADOS
No captulo anterior utilizou-se as declaraes read(*,*) e write(*,*). Este formato o
formato default destas declaraes. As estrelas (*,*) que aparecem nas declaraes
significam: no estou lhe passando nenhuma informao adicional, faa um procedimento
padro. O compilador Fortran 90 suporta vrios tipos de formataes, que veremos neste
captulo.
4.1 Descritores de formato
Existem vrios descritores de formato utilizado na entrada e/ou sada de dados. Na
Tabela 4.1 tm-se os tipos mais comuns de smbolos auxiliares dos descritores de formato
usados, juntamente com seus significados.
Tabela 4.1-Simbolos usados com os descritores de formato.
Smbolo
Significado
c
Nmero da coluna
d
Nmero de dgitos direita do ponto decimal
m
Nmero mnimo de dgitos a ser apresentado
n
Nmero de espaos para pular
r
Nmero de vezes que o formato repetido
w
Nmero de caracteres a ser usado

4.1.1 Sada de dados inteiros: O descritor I


O descritor usado para formatar a apresentao de inteiros o descritor I. Sua forma
geral
r(Iw)

ou r(Iw.m)

onde r, w e m tem os significados mostrados na Tabela 4.1.


Abaixo tem-se um pequeno exemplo do uso da formatao para inteiros.
program formato_inteiro
implicit none
integer :: i = 0, j = 17, k = 254, l = 7689
write(*,1)i, j, k, l
1 format(4(1x,i3.3))
stop
end program formato_inteiro

O resultado da impresso acima ser algo do tipo


000 017 254 ***

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

29

Fortran 90/95
As estrelas que aparecem acima significam que o formato foi insuficiente para imprimir
o dado.
4.1.2 Sada de dados reais: O descritor F
Um dos descritores usados para formatar dados reais o F. Sua forma geral
r(Fw.d)

Abaixo apresenta-se um programa com algumas impresses usando o formato F.


program formato_real_F
implicit none
real :: i = 1., j = 1./3., k = 21.123456789, l = 1234.567
write(*,1)i, j, k, l
1 format(4(1x,F7.4))
stop
end program formato_real_F

O resultado do programa acima ser


01.0000 .3333 21.1234 *******

4.1.3 Sada de dados reais: O descritor E


Muitas vezes dados do tipo real variam muito de faixa e torna-se difcil imprimi-los
usando o descritor F. Um outro descritor para nmeros reais o descritor E, tambm
conhecido como notao exponencial. Esta formatao consiste em imprimir um nmero
normalizado entre 0 e 1, multiplicado por uma potncia de 10. O formato geral do descritor E

r(Ew.d)

Alterando o programa anterior para usar a formatao E tem-se


program formato_real_E
implicit none
real :: i = 1., j = 1./3., k = 21.123456789, l = 1234.567
write(*,1)i, j, k, l
1 format(4(1x,E14.7))
stop
end program formato_real_E

O resultado deste programa ser


.1000000E+01 .3333333E+00 .2112346E+02 .1234567E+02

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

30

Fortran 90/95
Percebe-se que este formato mais adequado que o formato F quando deseja-se ler ou
imprimir nmeros ou muito pequenos ou muito grandes.
Para este tipo de formato necessrio que
w d+7

4.1.4 Sada de dados reais: O descritor ES


O descritor ES muito semelhante ao descritor E. Esta formatao consiste em
imprimir um nmero normalizado entre 1 e 10 (lembre-se que no descritor E este nmero era
entre 0 e 1), multiplicado por um potncia de 10. O formato geral do descritor ES
r(ESw.d)

Alterando o programa anterior para usar a formatao ES tem-se


program formato_real_ES
implicit none
real :: i = 1., j = 1./3., k = 21.123456789, l = 1234.567
write(*,1)i, j, k, l
1 format(4(1x,ES14.7))
stop
end program formato_real_ES

O resultado deste programa ser


1.0000000E+00 3.33333330E-01 2.1123460E+01 1.2345670E+03

Quando imprimindo dados do tipo real muito grandes ou muito pequenos, utilize o
descritor ES, porque idntico notao cientfica e os resultados podero ser entendidos
mais facilmente pelo usurio.
4.1.5 Sada de dados lgicos: O descritor L
O descritor L usado para formatar dados do tipo lgico, e sua forma geral
r(Lw)
O programa abaixo
program formato_logico_L
implicit none
logical :: x = .true., y = .false.
write(*,1)x, y
1 format(2(1x,L1))
stop
end program formato_logico_L

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

31

Fortran 90/95
ir produzir o seguinte resultado
TF

4.1.5 Sada de dados caracter: O descritor A


Dados do tipo caracter so formatados com o descritor A, que tem a seguinte forma
geral
r(A)

ou r(Aw)

Abaixo apresenta-se um programa que explora o descritor A


program formato_caracter_A
implicit none
character(len = 15) :: x = 'Como vo vocs?'
write(*,1)x
write(*,2)x
write(*,3)x
write(*,4)x
write(*,5)x
1 format(1x,A)
2 format(1x,A1)
3 format(1x,A5)
4 format(1x,A15)
5 format(1x,A20)
stop
end program formato_caracter_A

Este programa quando executado fornece o seguinte resultado


Como vo vocs?
C
Como
Como vo vocs?
Como vo vocs?

4.1.6 Posicionamento horizontal: Os descritores X e T


Estes dois descritores operam quando os dados j esto no buffer. O descritor X insere
brancos nos locais designados, e o T tabula a coluna para onde se deve ir.
O descritor X tem o seguinte formato
nX
onde n a quantidade de branco que se quer inserir em um determinado local. Lembre-se que
nos programas anteriores utilizou-se o descritor X, atravs de declaraes do tipo 1X,
destinadas a inserir um branco na primeira coluna e assim informar ao compilador que se
desejava espaamento simples.
O descritor T tem a forma
Tc
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

32

Fortran 90/95
onde c o nmero da coluna para onde deve-se ir. O efeito que o descritor T causa ficar
saltando de um coluna para outra durante a impresso. Veja o exemplo abaixo
program formato_XT
implicit none
integer :: i = 1, j = 2, k = 3
write(*,1)i, j, k
1 format(1x,4x,i1,t4,i1,t2,i1)
stop
end program formato_XT

cujo resultado final ser


321

Quando utilizando descritor T seja cuidadoso para no produzir resultados


aparentemente falsos, como o mostrado acima.
4.1.6 Trocando as linhas de sada: O descritor slash (/)
O descritor / (slash) quando encontrado em uma declarao format envia o contedo do
buffer para a impressora e inicia um novo buffer, isto eqivale a dizer que o descritor /
inicializa uma nova linha de impresso. Se colocarmos vrios slashes seguidos o efeito ser
pular vrias linhas de impresso.
No programa abaixo mostra-se o efeito causado pelo descritor slash
program formato_slash
implicit none
logical :: x = .true., y = .false.
write(*,1)x, y
1 format(2(1x,L1//))
stop
end program formato_slash

O resultado impresso deste programa


T
F

Esteja certo que exista uma relao um-para-um entre os tipos de dados em uma
declarao write e os tipos de formato especificados na declarao format correspondente.
Caso isto no ocorra o programa ir falhar durante a execuo.

4.2. Declaraes READ formatadas


Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

33

Fortran 90/95
As regras de formatao de declaraes READ so semelhantes s de declaraes
WRITE.

4.2. Introduo a arquivos e processamento de arquivos


Em todos programas mostrados at o momento as entradas de dados foram pelo teclado
e a sada na tela. A quantidade de dados de entrada e de sada eram pequenas.
Freqentemente, necessita-se ler grandes arquivos armazenados em disco, e tambm gravar
grandes arquivos em disco. Nos computadores esta entidade que armazena dados em disco
(ou mesmo em fitas ou outros dispositivas de armazenamento de dados) conhecida como
FILE. Todo file constitudo de um conjunto de linhas chamadas de RECORD. O Fortran
capaz de ler ou escrever informaes em um file, um record por vez.
Quando se l dados em um arquivo, um record de cada vez, em ordem consecutiva, dizse que este o acesso seqencial. Este tipo de acesso mais usado em unidades de fita
magntica. Quando salta-se livremente de um record para outro sem ordem especfica, diz-se
que este um acesso direto.
A maneira de direcionar uma declarao read ou write para um determinado
dispositivo de entrada ou sada de dados feita colocando o nmero correspondente daquela
unidade no lugar do primeiro asterisco que aparece nas declaraes read e write usadas nos
programas mostrados anteriormente.
Vrias declaraes do Fortran so destinadas ao controle deste processo de ler ou
escrever dados em um arquivo (file). As discutidas neste captulo esto na Tabela 4.2.
Tabela 4.2-Declaraes Fortran de entrada e sada de dados
Declarao de entrada ou sada Funo
Associa um arquivo em disco com um nmero de
open
entrada ou sada.
Termina a associao iniciada com a declarao
close
open
L dados de uma unidade de entrada de dados
read
especificada
Escreve dados em uma unidade de sada de dados
write
especificada
Move o ponteiro para o comeo do arquivo
rewind
Move o ponteiro um record para traz em um
backspace
arquivo

4.2.1 A declarao OPEN


A declarao open associa um arquivo (file) com um nmero dado de unidade de
entrada ou sada de dados. Sua forma
open(lista_open)

onde lista_open contm uma srie de especificaes sobre a unidade de entrada ou sada de
dados, o nome do arquivo, e informaes de como acessar o arquivo. As vrias especificaes
dentro da lista_open so separadas por vrgulas. Veremos neste captulo algumas destas

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

34

Fortran 90/95
especificaes, outras apenas em outros captulos mais adiante. As cinco especificaes mais
importantes so:
1) UNIT = expresso_inteira: Esta especificao indica qual o nmero inteiro que vai se
usar para associar com arquivo.
2) FILE = expresso_caracter: Esta especificao estabelece o nome do arquivo a ser
aberto.
3) STATUS = expresso_caracter: onde expresso_caracter pode assumir os seguintes
valores: OLD, NEW, REPLACE, SCRATCH, e UNKNOWN. A expresso old
refere-se a arquivos j existentes, new refere-se a arquivos novos, unknown refere-se
tanto a arquivos antigos quanto novos, scratch refere-se a arquivos que sero deletados
pelo sistema quando a execuo do programa terminar, e replace significa que um
arquivo vai ser aberto para sada de dados, independente da existncia de outro arquivo
com o mesmo nome.
4) ACTION = expresso_caracter: Esta especificao indica se o arquivo deve ser aberto
apenas para leitura, apenas para escrita, ou para a leitura e escrita. Nestes trs casos a
expresso_caracter assume os seguintes valores: READ, WRITE, e
READWRITE. Os prprios ttulos so auto-explicativos.
5) IOSTAT = varivel_inteira: Esta especificao indica o nome de uma varivel inteira na
qual o status da operao open ser retornado. Se a abertura do arquivo bem sucedida o
valor zero (inteiro) ser retornado na varivel_inteira. Se o processo no for bem
sucedido o sistema retornar em varivel_inteira um nmero positivo correspondente ao
cdigo de mensagem de erro.
Abaixo segue alguns fragmentos de cdigo mostrando alguns casos de declaraes open
integer :: i_error
open (UNIT = 8, FILE = exemplo.dat, STATUS = old, ACTION = read, IOSTAT = i_error)
integer :: i_error, unit
character(len = 5) :: file_name
unit = 25
file_name = saida
open (UNIT = unit, FILE = file_name, STATUS= REPLACE, &
ACTION = WRITE, IOSTAT = i_error)

Sempre tenha cuidado ao especificar os argumentos da declarao OPEN, dependendo


se est lendo ou escrevendo no arquivo. Esta prtica vai prevenir erros tais como escrever em
cima de um arquivo que deseja-se preservar.
4.2.2 A declarao CLOSE
A declarao CLOSE fecha o arquivo e libera o nmero de entrada e sada que estava
associado com aquele arquivo. O formato desta declarao
close(lista_close)

onde a lista_close deve conter o nmero de entrada e sada associado ao arquivo que se deseja
fechar. Pode existir nesta lista outros argumentos que sero discutidos em outro captulo. Um
exemplo o que fecha o arquivo associado ao nmero de entrado e sada igual a oito, como
segue
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

35

Fortran 90/95
close(UNIT = 8)

ou simplesmente close(8)

4.2.3 READs e WRITEs a arquivos em disco


Uma vez que um arquivo foi conectado a um nmero de entrada e sada de dados
atravs de um declarao open ser possvel ler do arquivo ou escrever no arquivo utilizando
as declaraes read e write j utilizadas anteriormente. Por exemplo o seguinte bloco de
declaraes
real :: x, y, z
open (UNIT = 8, FILE = exemplo.dat, STATUS = OLD, IOSTAT = i_error)
read (8,*) x, y, x

ir ler no arquivo exemplo.dat, j existente os dados reais x, y, z em formato livre.

4.2.4 O uso da especificao IOSTAT= nas declaraes READ


A especificao IOSTAT= pode ser usada juntamente com a declarao READ (ou mesmo
com WRITE) quando se estiver operando com arquivos em disco. A declarao read ficar
ento com o seguinte aspecto
integer :: i_err, i
read(7,10,IOSTAT = i_err) i

Neste caso a declarao read tentar ler a varivel inteira i no arquivo que estiver
vinculado ao nmero 7 de entrada e sada de dados. O nmero 10 o label da declarao
format que especificar a formatao de leitura. Tudo isto j se fazia antes. Da forma anterior,
quando a leitura era bem sucedida o programa continuava a execuo. Quando a leitura era
malsucedida o programa descontinuava. Com a introduo deste novo argumento IOSTAT =
i_err, quando a leitura bem sucedida o sistema ir retornar um valor zero para i_err, e o
programa continuar. Se a leitura for malsucedida o programa no descontinuar e retornar
um valor no nulo para i_err, utilizando um IF est situao pode ser detectada e alguma
providncia tomada para resolver o problema ou fazer uma terminao elegante do programa
ao invs das terminao selvagens que ocorre quando este recurso no usado.
Sempre inclua a especificao IOSTAT = quando lendo (ou mesmo escrevendo) um
arquivo de disco. Isto prov um meio gracioso de detectar excepcionalidades em operaes
com arquivos.
4.2.5 Posicionamento em arquivos
Conforme escrito anteriormente um dos tipos de arquivos em Fortran so os
seqenciais, que devem ser lidos ou escritos um record aps o outro em uma ordem
consecutiva. s vezes necessrio ler um mesmo dado duas vezes, ou escrever duas vezes na
mesma posio. O Fortran apresenta duas declaraes para resolver este tipo de problema. O
BACKSPACE que move o ponteiro um record para trs de cada vez, e o REWIND que
reposiciona o ponteiro no incio do arquivo. As formas destas duas declaraes so como
segue
backspace (UNIT = unit_number)

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

36

Fortran 90/95
e
rewind (UNIT = unit_number)

onde unit_number o nmero da unidade de entrada e sada qual est associado o arquivo.
Estas duas declaraes podem ainda estar munidas da especificao IOSTAT=, para
detectar possveis erros no posicionamento do arquivo, sem causar a descontinuao.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

37

Fortran 90/95

CAPTULO 5
ARRAYS
Para facilitar as operaes sobre os dados de um programa, em geral interessante
ordenar estes dados de alguma forma especial e dar-lhes um nome de tal forma que possam
ser referenciados facilmente. Da matemtica tem-se os conceitos de vetor, matriz e tensor.
Um vetor (tensor de ordem 1) uma entidade composta de vrios escalares com um definida
ordem. Os vetores tm, digamos, um aspecto unidimensional, os dados so colocados em
linha. Uma matriz (tensor de ordem 2) tambm tem seus componentes bsicos organizados,
porm esto organizados com um aspecto bidimensional, os dados esto dispostos como se
estivessem em um plano retangular. Estes tipos de estruturas quando esto dispostos de uma
forma em que as dimenses sejam maiores que 2 em geral so chamados de tensores.
Existe um paralelismo entre estes conceitos da matemtica e algumas formas de
organizar dados em computao. Para evitar a proliferao de nomes, vamos aqui chamar
estas formas organizadas de dados simplesmente de arrays. Os vetores computacionais seriam
arrays unidimensionais (ou arrays com rank 1), as matrizes seriam arrays bidimensionais (ou
arrays com rank 2), e assim por diante at o conceito de arrays n-dimensionais (ou arrays
com rank n). Os componentes de um array so os elementos do array. Cada array
identificado por um nome, e seus elementos por ndices que indicam a sua posio dentro do
array. Desta forma as expresses
a(7), b(6,9) e c(1,9,100)

referem-se ao stimo elemento do array a, ao elemento na posio (6,9) do array b, e ao


elemento (1,9,100) do array c. Nos arrays com rank 1 os dados subsequentes so
armazenados em posies subsequentes na memria do computador. Em arrays com rank 2 o
armazenamento do array faz-se seqencialmente pela primeira coluna (como em um array de
rank 1), depois empilha-se seqencialmente a segunda coluna, e assim por diante at a ltima
coluna. Olhando de outra forma, congela-se o ndice direito do array e varia o da esquerda,
depois incrementa-se o ndice da direita e varia o da esquerda mais rpido, e assim
sucessivamente, produz-se ento o mesmo efeito de empilhar as colunas. Generalizando para
arrays n-dimensionais, isto pode ser dito ainda da seguinte forma: se imaginarmos os ndices
do array como componentes de um ninho de DOs, tudo se passa como se os ndices mais
direita fossem colocados nos laos mais externos dos DOs, de tal forma que o ndice mais
direita correspondesse ao lao mais externo e o ndice mais esquerda correspondesse ao lao
mais interno.
O conceito e o uso de arrays facilita tremendamente a execuo das operaes de
lgebra linear sobre um dado conjunto de dados.
5.1 Declarando arrays
Antes de comear a usar um array necessrio declar-lo, quanto ao tipo e quantidade
de elementos que possui, para informar ao compilador que tipo de dado ser armazenado e
quanto ser usado de memria. Abaixo apresenta-se algumas declaraes de arrays:
real, dimension(16) :: x

nesta declarao tem-se um vetor x com 16 elementos do tipo real;


character(len = 25), dimension(100) :: y

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

38

Fortran 90/95
nesta tem-se um vetor y com 100 elementos do tipo character(25);
integer, dimension(10, 20, 30) :: i

aqui tem-se um array de rank 3 x com 102030 elementos do tipo integer.


O nmero de elementos do array em uma dada direo chama-se extenso do array
naquela direo. A forma de um array definida pelo seu rank e pelas extenses do array nas
vrias direes. Dois arrays tem a mesma forma se possuem o mesmo rank e as mesmas
extenses em cada direo. O tamanho de um array o total de elementos declarados naquele
array.
Pode-se definir arrays constantes. Um array constante aquele que possui todos seus
elementos constantes. Inicializa-se um array constante ou no, usando um construtor de
arrays. Abaixo apresenta-se um exemplo de uso do construtor de array
real, dimension(5) :: w
w = (/1.,2.,3.,4.,5./)

as duas /s existentes no exemplo acima funcionam como o incio e o final dos dados do array
sendo inicializado.
Para um array constante o cdigo acima seria modificado para
real, parameter, dimension(5) :: w = (/1.,2.,3.,4.,5./)

5.2 Usando elementos de array em declaraes Fortran


Aqui apresenta-se algumas informaes de como utilizar elementos de arrays em
declaraes Fortran.
5.2.1 Elementos de array
Cada elemento de um array uma varivel tal como todas as outras j apresentadas at
o momento nos captulos anteriores, e portanto podem ser inseridas em qualquer expresso
aritmtica ou lgica.
5.2.2 Inicializando elementos de array
Os elementos de um array podem ser inicializados por declarao de atribuio. Abaixo
apresenta-se alguns exemplos
integer, dimension(3) :: k
k(1) = 5
k(2) = 4
k(3) = 1

neste caso o array k, com elementos inteiros, foi inicializado utilizando um declarao para
cada elemento. Para arrays pequenos isto possvel, para arrays grandes melhor utilizar
estruturas de laos para efetuar tal tarefa. Assim vejamos o seguinte exemplo
integer, dimension(1000) :: k
integer :: i

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

39

Fortran 90/95
do i = 1, 1000
k(i) = i*i
end do

Sempre inicialize os elementos de um array antes de utiliz-lo.


O bloco de programa acima tambm poderia ter sido inicializado utilizando-se um lao
implcito (uma forma especial de lao do tipo DO). Como segue
integer, dimension(1000) :: k = (/(i*i, i = 1,1000)/)

tambm possvel fazer operaes mais complexas, como


integer, dimension(10) :: k = (/(0, i = 1,5), j = 1,5/)

se todos os elementos de um array assumem o mesmo valor possvel, simplesmente,


escrever-se
real, dimension(55) :: t
t = 7.0

5.2.3 Modificando a faixa de subscritos de um array


Os elementos de um array rank 1 so endereados normalmente numerando o primeiro
de 1, o segundo de 2, e o n-simo de n. Isto pode ser diferente. Imagine um array com 11
elementos, seus elementos seriam normalmente numerados de 1 a 11. No entanto tambm
poderamos numer-los de 5 a 5, que a quantidade de elementos seria os mesmos 11. O
Fortran suporta este tipo de nomenclatura que expressa da seguinte forma para um array
rank 1
real, dimension (valor_baixo : valor_alto) :: x

ou para um array rank 2


real, dimension (valor_baixo_1 : valor_alto_1, valor_baixo_2 : valor_alto_2) :: x

para ranks maiores procede-se de maneira semelhante ao rank 2.


A dimenso numa dada direo (i) obtida por
extensao_i = valor_alto_i valor_baixo_i + 1

5.2.4 Subscritos de array fora da faixa de definio


Para um array rank 1 com, digamos 10 elementos, ao se tentar acessar o suposto dcimo
quinto elemento, o que acontecer? Isto depende de processador para processador. Em alguns
o programa rodando verificar se todos os elementos usados esto na faixa adequada. Caso
seja identificado casos fora da faixa, o programa emitir um mensagem e descontinuar a
execuo. Entretanto este processo torna os programas mais lentos. Assim em geral esta
capacidade de fazer a verificao de limites de array opcional nos compiladores. Desta
forma aconselhvel que esta capacidade fique ligada quando o programa estiver sendo
criado e compilador. Quando o programa estiver na forma final desejvel que a verso final
seja compilada com a verificao de limites de array desligada.
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

40

Fortran 90/95
5.2.5 O uso de constantes na declarao de arrays
O uso de constantes pode ser utilizado para melhorar e tornar mais claro a declarao da
extenso de arrays em cada direo. Alm disto o uso de constantes protege a grandeza contra
a corrupo de seu valor. Abaixo mostra-se alguns exemplos de tal uso
integer, parameter :: tamanho = 1000
real :: array1(tamanho)
real :: array2(tamanho+5)
real :: array3(tamanho*tamanho)
real :: array4(tamanho,tamanho)

Sempre use constantes para declarar o tamanho de arrays em programas Fortran,


visando torn-los fceis de ler, e de modificar. Em outro captulo apresenta-se uma outra
forma ainda mais elaborada de encapsular os dados, utilizando mdulos.
5.3 Usando arrays completos e sub-conjuntos de arrays
Conforme mencionado anteriormente possvel fazer as operaes clssicas da lgebra
sobre os elementos de um array, numa estratgia elemento-a-elemento. Vamos ver nesta
seo como fazer operaes sobre arrays completos ou sobre subconjuntos de arrays.
5.3.1 Operaes com arrays completos
Sob certas circunstncias possvel efetuar operaes sobre arrays completos com uma
notao similar quela usada para variveis escalares. Se dois arrays tem a mesma forma,
eles podem ser usados em algumas operaes aritmticas como se fossem escalares. Algumas
funes intrnsecas aplicam-se a arrays completos. Abaixo mostra-se dois programas, um
escrito na forma tradicional, ou escrito usando operaes sobre arrays completos.
Forma tradicional
! Este programa mostra operaes sobre arrays, escritas da forma tradicional
! usando laos de DO
!
program operacao_sobre_arrays
implicit none
! declaraes de variveis
integer, parameter :: i_max = 100
integer :: i, j
character(1) :: word
real, dimension(i_max,i_max) :: array1, array2, array3
! inicializao dos arrays
do i = 1, i_max
do j = 1, i_max
array1(i,j) = 1.5
array2(i,j) = 2.5
array3(i,j) = 0.0
end do
end do
!somando o array1 com o array2 e colocando no array3

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

41

Fortran 90/95
do i = 1, i_max
do j = 1, i_max
array3(i,j) = array1(i,j) + array2(i,j)
end do
end do
!calculando a raiz quadrada de dos elementos de array3
do i = 1, i_max
do j = 1, i_max
array3(i,j) = sqrt(array3(i,j))
end do
end do
!imprimindo os resultados
do i = 1, i_max
do j = 1, i_max
write(*,*)array3(i,j)
end do
end do
!criando um efeito pause
write(*,*)'Digite algo!'
read(*,*)word
!terminao do programa
stop
end program operacao_sobre_arrays

Forma usando operaes arrays completos


! Este programa mostra operaes sobre arrays, escritas da forma usando
! operaes sobre arrays completos
!
program operacao_sobre_arrays
implicit none
! declaraes de variveis
integer, parameter :: i_max = 100
character(1) :: word
real, dimension(i_max, i_max) :: array1, array2, array3
! inicializao dos arrays
array1 = 1.5
array2 = 2.5
array3 = 0.0
!somando o array1 com o array2 e colocando no array3
array3 = array1 + array2
!calculando a raiz quadrada de dos elementos de array3
array3 = sqrt(array3)
!imprimindo os resultados
write(*,*)array3
!criando um efeito pause
write(*,*)'Digite algo!'
read(*,*)word
!terminao do programa

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

42

Fortran 90/95
stop
end program operacao_sobre_arrays

Fica claro que todos os resultados impressos so iguais a 2.0.


Na operao com arrays completos basta que os arrays envolvidos numa operao
tenha a mesma forma, no importando se as faixas das extenses de cada array em cada
direo usem notao diferenciada. Se dois arrays no tem a mesma forma ento no podero
executar operaes do tipo array completo.
Quando se faz um lao de DO para se somar dois arrays, est-se informando ao
compilador que a soma deve ser feita naquela seqncia, um elemento aps outro. Quando se
utiliza a notao compacta de operaes sobre arrays completos, est-se informando ao
compilador que a soma dos elementos pode ser efetuada de uma maneira no necessariamente
seqencial. Conforme j mencionado no Captulo 1 o Fortran90/95 capaz de efetuar por si
s processamento paralelo do tipo SIMD, nas estruturas passveis deste tipo de paralelismo e
quando o computador tiver dois ou mais processadores. Assim a notao de operaes sobre
arrays completos tambm leva a processamento paralelo do tipo SIMD quando houver suporte
para tal.
5.3.2 Definindo e operando com subconjuntos de arrays
Para definir um subconjunto de um array ou seo de array (array section) faz-se
necessrio usar uma trinca de ndices que tem a forma geral
indice_1 : indice_2 : incr

onde indice_1 o primeiro subscrito a ser includo no subconjunto do array; indice_2, o


ltimo subscrito a ser includo; e incr o incremento que se far ao longo do array completo.
Esta definio pode ser aplicada para cada direo do array. Abaixo apresenta-se alguns
exemplos de definio de subconjuntos de arrays.
Sejam os seguintes arrays originais
integer, dimension(7) :: array1 = (/1,2,3,4,5,6,7/)
integer, dimension(4,4) :: array2 = (/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16/)

assim pode-se definir os seguintes exemplos de subconjuntos de arrays


integer, dimension(7) :: array1 = (/1,2,3,4,5,6,7/)
integer, dimension(4) :: array3 = array1(1:7:2)
integer, dimension(5) :: array4 = array1(1:5:1)
integer, dimension(4,4) :: array2 = (/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16/)
integer, dimension(2,2) :: array5 = array2(1:2:1,3:4:1)
integer, dimension(3,2) :: array6 = array2(1:3:1,1:2:1)

Um ou todos os elementos da trinca podem ser default. Se indice_1 no aparece na trinca


o seu default o primeiro ndice de elemento para aquela direo. Se indice_2 no aparece na
trinca o seu default o ltimo ndice de elemento para aquela direo, e incr quando no
aparece na trinca, o seu default a unidade. Todas as combinaes abaixo so possveis e
legais
indice_1 : indice_2 : incr
indice_1 : indice_2

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

43

Fortran 90/95
indice_1 :
indice_1 :: incr
: indice_2
: indice_2 : incr
:: incr
:

5.3.3 Reformatando arrays


Um array rank 1 com cem elementos pode ser reformatado para, por exemplo, para um
array rank 2 (1010) ou mesmo um array rank 2 (520), mantendo os valores e o mesmo
nome. Para tal utiliza-se a funo intrnseca RESHAPE cuja formato
array3 = reshape(array1, array2)

onde array1 contm os dados para reformatar e array2 um array rank 1 descrevendo a nova
forma. O nmero de elementos em array2 igual ao nmero de dimenses no array de sada e
os seus valores so iguais dimenso em cada direo. O nmero de elementos em array1
deve o mesmo nmero de elemento para forma especificada para array2, caso contrrio a
declarao reshape ir falhar. O array3 o resultado da reformatao, quando bem sucedida.
Abaixo apresenta-se um programa que reformata um vetor com cem elementos para
uma matriz quadrada (1010).
! Este programa mostra a reformatao de arrays.
!
program reformatacao_de_arrays
implicit none
! declaraes de variveis
integer, parameter :: i_max = 100, j_max = 10, rank = 2
integer :: i
real, dimension(i_max) :: array1
real, dimension(j_max, j_max) :: array3
integer, dimension(rank) :: array2 = (/10,10/)
! inicializao do array1
do i = 1, i_max
array1(i) = i
end do
!reformatando o array1 para array3
array3 = reshape(array1, array2)
stop
end program reformatacao_de_arrays

Como o construtor de arrays s funciona com arrays rank 1, a declarao reshape serve
para transformar arrays criados rank 1 em arrays que no sejam rank 1.
5.4 Usando funes intrnsecas Fortran com arrays
O Fortran 90/95 tm trs tipos de funes intrnsecas: funes elementares (elemental
functions), funes de questionamento (inquiry functions), e funes de transformao
(transformational functions). Algumas funes de cada um destes grupos so projetadas para
operar com arrays.
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

44

Fortran 90/95
5.4.1 Funes intrnsecas elementares
So funes que projetadas para operar com escalares trabalham tambm com arrays.
Se o argumento de uma funo elementar um escalar o resultado ser um escalar, se o
argumento um array o resultado ser tambm um array. Estes dois arrays devero ter o
mesmo formato. A maioria das funes intrnsecas que aceitam escalares como argumentos
tambm aceitam arrays. Alguns exemplos so
y = sin(x)
y = cos(x)
y = sqrt(x)

onde x e y ou so ambos escalares ou so dois arrays de mesmo formato.


5.4.2 Funes intrnsecas de questionamento
Funes intrnsecas de questionamento so funes cujo resultado depende do formato e
da natureza do argumento. Por exemplo LBOUND(force) uma funo de questionamento que
retorna o menor subscrito do array force. Na Tabela 5.1 apresenta-se algumas destas funes
mais usadas.

Tabela 5.1-Algumas funes comuns de questionamento


Funo e seus argumentos Utilidade
allocated(array)
Determina se um array alocvel est alocado ou no.
lbound(array,dim)
Retorna todos os limites inferiores das dimenses de um
array se dim no est presente (o retorno um array). Se
dim est presente retornar o menor dos limites inferiores
(o retorno um escalar)
shape(array)
Retorna a forma de um array
size(array,dim)
Retorna a dimenso do array em cada direo se dim est
presente. Caso contrrio retorna o tamanho do array
ubound(array,dim)
Retorna todos os limites superiores das dimenses de um
array se dim no est presente (o retorno um array). Se
dim est presente retornar o maior dos limites superiores
(o retorno um escalar)

5.4.3 Funes intrnsecas de transformao


Funes intrnsecas de transformao so funes que tem um ou mais arrays como
argumento ou um array como resultado. Este tipo de funes no operam sobre escalares,
apenas sobre arrays completos. Freqentemente o resultado deste tipo de funo um array
com formato diferente dos arrays de entrada.
O Fortran 90/95 tm muitas funes intrnsecas de transformao, algumas so
apresentadas na Tabela 5.2.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

45

Fortran 90/95
Tabela 5.2-Algumas funes de transformao comuns.
Funo e argumentos
Utilidade
all(mask)
Funo lgica, retorna TRUE se todos os valores no
array mask so TRUE
any(mask)
Funo lgica, retorna TRUE se qualquer dos valores
no array mask TRUE
count(mask)
Retorna a quantidade de elementos TRUE em mask
dot_product(vet_1,vet_2)
Calcula o produto interno de dois arrays rank 1 de
mesmo formato
matmul(matriz_1,matriz_2) Multiplica duas matrizes conformveis
maxloc(array,mask)
Retorna o local onde ocorre o elemento de maior valor
entre aqueles para os quais MASK TRUE. O
resultado um array rank 1 contendo os subscritos da
posio.
minloc(array,mask)
Retorna o local onde ocorre o elemento de menor valor
entre aqueles para os quais MASK TRUE. O
resultado um array rank 1 contendo os subscritos da
posio.
minval(array,mask)
Retorna o menor valor no array entre aqueles para os
quais MASK TRUE. (mask opcional)
product(array,mask)
Calcula o produto dos elementos de um array para os
quais MASK TRUE. MASK opcional, se no
estiver presente o produto feito com todos os
elementos do array.
reshape(array1,array2)
Constri um novo array a partir do array1 e das
informaes do novo array contidas em array2 rank 1.
sum(array,mask)
Calcula a soma dos elementos de um array para os
quais MASK TRUE. MASK opcional, se no
estiver presente a soma feito com todos os elementos
do array.
transpose(matriz)
retorna a transposta de um array rank 2.
maxval(array,mask)
Retorna o maior valor no array entre aqueles para os
quais MASK TRUE. (mask opcional)

5.5 Atribuio de arrays com mscara: a estrutura WHERE


Considere a necessidade de se fazer algum tipo de operao apenas sobre alguns
elementos de um array e outro tipo sobre os restantes. O Fortran 90/95 suporta operao
sobre array considerando uma mscara que informa sobre quais elementos deve-se fazer ama
operao e quais devem ficar com a outra operao. Esta mscara em realidade um array
lgico com o mesmo formato do array a ser operado. Deve-se colocar nesta mscara, nas
posies correspondentes s quais deseja-se fazer a primeira operao no array, valores igual
a TRUE, e no restante das posies coloca-se FALSE.
5.5.1 A estrutura WHERE do Fortran 90
A forma geral da estrutura WHERE do Fortran
nome: where (mask)

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

46

Fortran 90/95
declaraes_1_com_array
elsewhere nome
declaraes_2_com_array
end where nome

No cdigo acima faz-se declaraes_1_com_array sobre todos os elementos do array


para os quais os elementos correspondentes de mask TRUE. Para aquelas posies
correspondentes
aos
elementos
com
valor
FALSE
em
mask
aplica-se
declaraes_2_com_array.
Use a estrutura WHERE para modificar somente os elementos de um array que passem
em um determinado teste.
5.5.2 A estrutura WHERE do Fortran 95
O Fortran 95 apresenta uma forma mais complexa de estrutura WHERE, onde permite-se
o uso de vrios ELSEWHERE com mscara e apenas um ELSEWHERE sem mscara. A forma
geral da estrutura WHERE do Fortran 95
nome: where (mask_1)
declaracoes_com_array_1
elsewhere (mask_2) nome
declaracoes_com_array_2
elsewhere nome
declaracoes_com_array_3
end where nome

5.5.3 A declarao WHERE


O Fortran 90/95 tambm tem uma estrutura WHERE com apenas um linha de
declarao. Sua forma
where(mask) declaraes_com_array

neste caso ser feito determinado conjunto de operaes apenas sobre os elementos do array
que correspondem aos elementos com valores TRUE em mask.
5.6. A estrutura FORALL
O Fortran 95 apresenta um novo tipo de estrutura, o FORALL, que foi projetado para
permitir um conjunto de operaes a serem aplicadas a um conjunto de elementos de um
array. Os elementos a serem operados so definidos pelos ndices e tambm por uma
expresso lgica. As operaes ocorrero apenas sobre os elementos do array que atendam as
restries contidas nos ndices bem como aquela contida numa expresso lgica.
5.6. A forma da estrutura FORALL
A forma geral da estrutura FORALL
nome: forall (in_1 = trinca_1, in_2 = trinca_2,, expresso_lgica)
declaraes_executveis
end forall nome

Cada ndice na declarao FORALL especificado por uma trinca, na forma


Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

47

Fortran 90/95
trinca_1 = indice_1 : indice_2 : incr

j definidos anteriormente quando tratamos de subconjuntos de arrays.


5.7. Arrays alocveis
Todos os arrays utilizados at o momento tiveram suas dimenses definidas durante o
perodo de compilao e no podem ser alteradas durante a execuo do programa. Esta a
chamada alocao esttica de memria, uma vez que o tamanho dos arrays nunca so
definidos durante a execuo do programa. desejvel que o tamanho de um array seja
definido durante a execuo para se moldar s necessidades de armazenamento, que variam
de caso a caso sendo executado. Uma melhor soluo desenvolver um programa que use
alocao dinmica de memria. Neste caso o programa define automaticamente o tamanho
dos arrays de acordo com a necessidade e durante o perodo de execuo.
Um array em Fortran que ter suas dimenses definidas dinamicamente, dever ser
declarado alocvel usando o atributo ALLOCATABLE na declarao de tipo de varivel, e
alocado usando a declarao executvel ALLOCATE. Quando um array alocvel no vai mais
ser utilizado, deve-se liberar a memria que ele ocupava, utilizando a declarao executvel
DEALLOCATE. Para dotar um array de reais com o atributo de alocvel procede-se como
segue
real, allocatable, dimension(:,:) :: array1

note que na declarao acima o tipo do array fica definido, mas no o seu tamanho.
Para o programa definir durante a execuo o tamanho do array necessrio o uso da
declarao executvel ALLOCATE que tem a seguinte forma
allocate (lista_de_arrays_para_alocar, STAT = status)

Um exemplo tpico
allocate(array1(50,-10:50), STAT = status)

que um array de 5061 elementos.


Sempre inclua a especificao STAT = em qualquer declarao ALLOCATE, e sempre
verifique o valor retornado, de tal forma que o programa termine de maneira elegante sempre
que a memria a alocar para os arrays seja insuficiente.
Caso se tenha dvida se um array alocvel j est alocado, pode-se descobrir esta
informao usando a funo de questionamento ALLOCATED(array). Se array j estiver alocado
o retorno ser TRUE, caso contrrio ser FALSE.
Aps utilizar um array alocvel necessrio desaloc-lo para liberar memria til para
outros propsitos. Isto pode ser feito usando a declarao executvel DEALLOCATE. A forma
geral desta declarao
deallocate (lista_de_arrays_para_desalocar, STAT = status)

Um exemplo caracterstico

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

48

Fortran 90/95
deallocate(array1, STAT = status)

onde a especificao STAT = tem o mesmo significado daquela usado na declarao


ALLOCATE.
Abaixo apresenta-se um programa que faz a alocao dinmica de uma matriz.
!Programa para mostrar a alocacao dinmica de arrays.
!
! Programador: Joo Batista Aparecido
! Ilha Solteira, Criado em 9/12/1999
!
Modificado em 27/07/2001.
!
program alocacao_dinamica
implicit none
!declara variveis
integer :: i, status
real, allocatable, dimension(:,:) :: x !array alocvel
!Entra com o inteiro i
write(*,*)'Digite i (inteiro) = '
read(*,*)i
!Faz a alocacao de memria para o array x
allocate(x(i,i), stat = status)
!Teste para verificar se a alocao foi bem sucedida
if(status /= 0) then
write(*,*) A alocao falhou!
stop
end if
!Atribui valores ao elementos do array x
x = 5.0
!Desaloca a memria ocupada por x
deallocate(x, stat = status)
!Teste para verificar se a desalocao foi bem sucedida
if(status /= 0) then
write(*,*) A desalocao falhou!
stop
end if
!Terminao do programa
stop
end program alocacao_dinamica

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

49

Fortran 90/95

CAPTULO 6
FUNES E SUBROTINAS
No primeiro livro considerado de cincia poltica, escrito no entorno de 1500, o autor
Nicolau Maquiavel, j ensinava: dividir para conquistar. Em mtodos numricos esta idia
muito utilizada. Talvez seria melhor neste caso adapt-la para: dividir para calcular. E
fazendo um paralelo na rea de programao computacional, poderamos tambm dizer:
dividir para programar. A questo ento como dividir um programa? Em Fortran tem-se o
programa principal (nico) e programas auxiliares, tambm chamados de sub-programas.
Estes programas so usados da seguinte maneira: Quando o programa principal vai sendo
executado e encontra uma referncia a um sub-programa, este invocado, o programa
principal passa-lhe as variveis necessrias, o sub-programa recebe o controle da execuo,
executa as declaraes, termina a execuo, e passa de volta o controle da execuo ao
programa principal. E assim sucessivamente tantos quantos sub-programas sejam encontrados
pelo programa principal durante a execuo.
Existem dois tipos principais de sub-programas: as funes (functions) e as subrotinas
(subroutines). As funes recebem um ou mais argumentos do programa e retornam apenas
um argumento, podendo ser um array. As subrotinas recebem um ou mais argumentos do
programa e retornam um ou mais argumentos para o programa. Pode-se ter subrotinas que no
retornem nenhum argumento para o programa. Subrotinas e funes podem chamar outras
subrotinas e funes.
O uso de subrotinas e funes vantajoso porque permite dividir um programa que seria
muito grande em partes modulares. Estas partes podem ser desenvolvidas de um maneira
razoavelmente independente, podendo ser editadas e compiladas separadamente.
O debugamento destas rotinas em separado torna-se mais fcil do que se estivessem em
um programa nico. Uma outra vantagem que isto facilita o trabalho em equipe, divide-se
tarefas para diferentes programadores e depois vai-se integrando o resultado final. Pode-se ter
elementos de grupos de trabalhos mesmo em pases diferentes. Para estes grandes grupos
naturalmente necessrio a existncia de um gerente de projeto.
O uso de subrotinas e funes tambm facilitam a manuteno do programa.
Se as subrotinas e funes estiverem bem desenvolvidas, robustas e precisas, podero
ser reusadas em qualquer outro programa que seja necessrio, sem necessidade de
desenvolv-las de novo.
Devido ao fato de que as variveis de uma function ou subroutine so na sua maioria
locais, isto produz um certo grau de encapsulamento dos dados, evitando em parte que a
execuo de um subrotina ou funo corrompa os dados do programa principal ou mesmo de
outras subrotinas ou funes.
Para invocar functions dentro de um programa Fortran basta mencionar seu nome em
uma expresso aritmtica ou lgica. Para invocar subroutines necessrio utilizar a
declarao CALL antes do nome da subrotina.
6.1 Subrotinas
Uma subrotina um sub-programa Fortran que invocado utilizando a declarao
CALL antes do nome da subrotina, ela recebe alguns argumentos de entrada e retorna outros

argumentos de sada. A forma geral de declarar uma subrotina


subroutine nome (lista_de_argumentos)
declaracoes_no_executaveis

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

50

Fortran 90/95
declaracoes_executaveis
return
end subroutine nome

No bloco de cdigo acima a primeira linha marca o incio da subrotina e a ltima linha
marca o final da subrotina. A declarao return retorna o controle da execuo ao programa
principal, da mesma forma que um programa pode ter vrios STOPs, uma subrotina pode ter
vrios RETURNs. O nome da subrotina pode ter at 31 caracters porm o primeiro deve ser
alfabtico. Na lista _de_ argumentos tm-se as variveis e arrays que sero passadas, por
referncia, pelo programa principal quando invocar a subrotina.
Como uma subrotina (ou funo) um programa independente pode-se utilizar
variveis com os mesmos nomes de variveis usadas no programa principal e outras
subrotinas sem a possibilidade de conflito.
Uma subrotina no pode chamar a si mesma, a no que tenha sido declarada recursiva
(recursive).
A forma de invocar uma subrotina como segue
call nome (lista_de_argumentos)

onde os argumentos na lista_de_argumentos deve ter uma relao biunvoca com os listados na
declarao de argumentos da subrotinas, quanto quantidade, ao tipo e ao uso que se destina.
Abaixo apresenta-se um programa que tem uma subrotina
program soma_dois_reais
!O objetivo deste programa eh mostrar o uso de uma subrotina
!
!Programmer: joao batista aparecido
ilha solteira, 11 dezembro 1999
!
implicit none
real :: x = 1.5, y = 2.5, z
!invocando a subrotina
call soma(x, y, z)
stop
end program soma_dois_reais
subroutine soma(a, b, c)
implicit none
real :: a, b, c
!soma dois reais
c=a+b
return
end subroutine soma

Neste programa, quando de sua execuo a passagem de dados feita de uma forma
apropriada e o resultado produzido o correto, z = 4.0.
Quando um programa passa um argumento para uma subrotina, em realidade ele est
passando um ponteiro que aponta para a posio de memria onde aquela varivel est, com
isto a subrotina pode fazer uso do seu valor. Fica claro que a subrotina pode modificar o valor
que est naquele endereo mediante uma simples operao de atribuio. Em realidade isto
que ocorre com os chamados argumentos de retorno, a subrotina escreve algo naquela posio
de memria que foi indicada pelo programa principal, a questo se de entrada ou de sada
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

51

Fortran 90/95
(at este ponto) est mais na cabea do programador. Percebe-se ento que possvel haver a
corrupo dos dados do programa principal atravs de uma alterao indevida ocorrida em
uma subrotina.
A seguir apresenta-se um programa onde pode haver algum tipo de corrupo de dados
program corrupcao_de_dados
!O objetivo deste programa eh mostrar a corrupcao de
!dados quando se utiliza subrotinas
!
!Programmer: joao batista aparecido
ilha solteira, 11 dezembro 1999
!
implicit none
real :: x = 1.5, y = 2.5, z
!invocando a subrotina
call soma(x, y, z)
stop
end program corrupcao_de_dados
subroutine soma(a, b, c)
implicit none
real :: a, b, c
!corrompendo o dado b. Isto pode ocorrer por digitacao distraida em um cdigo !grande, por
fragmentos de codigo no deletado e assim por diante.
b=b*2
!soma dois reais
c=a+b
return
end subroutine soma

Neste caso o resultado deveria ser z = 4.0 no entanto o resultado ser z = 6.5, isto
ocorreu porque uma operao dentro da subrotina que alterou o valor que estava armazenado
no endereo da varivel y, neste ficam os valores e y e z corrompidos. Dependendo da
estrutura do programa a informao corrompida poder se propagar contaminado os
resultados intermedirios e o resultado final.
Agora apresenta-se outro caso de corrupo de dados, via definio incorreta dos tipos
das variveis na subrotina

program corrupcao_de_dados_2
!O objetivo deste programa mostrar a corrupo de dados
!quando se utiliza subrotinas
!
!Programmer: joao batista aparecido
ilha solteira, 11 dezembro 1999
!
implicit none
real :: x = 1.5, y = 2.5, z

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

52

Fortran 90/95
!invocando a subrotina
call soma(x, y, z)
stop
end program corrupcao_de_dados_2
subroutine soma(a, b, c)
implicit none
!introduzindo a corrupo nos dados. Via uma declarao
!incorreta de tipo na subrotina
integer :: a, b, c
!soma dois reais
c=a+b
return
end subroutine soma
A execuo deste programa no ir corromper o valor da varivel y mas ir produzir um
resultado totalmente errado para a varivel z.
Apresenta-se a seguir a soluo para os problemas de corrupo de dados mostrados no
primeiro exemplo, posteriormente retornaremos aos apresentados no segundo exemplo.
6.1.1 O atributo INTENT
Percebe-se da anlise dos dois exemplos apresentados acima que duas formas de
corrupo de dados so: via a modificao acidental do valor das variveis de entrada ou
sada; ou a definio conflitante dos tipos das variveis no programa principal e na subrotina,
neste caso haver a corrupo dos resultados gerados, ou seja os argumentos de sada.
A declarao INTENT especifica em uma subrotina quais argumentos so de entrada,
quais so de sada e quais so de entrada e sada. Com isto o programa quando estiver
executando no permitir que um subrotina faa alteraes no valor de uma varivel de
entrada. Este mecanismo refora o encapsulamento de dados que ocorre na execuo de uma
subrotina. A declarao INTENT um atributo da varivel e deve ser declarado no local de
declarao de variveis, ou seja no incio da subrotina. Este atributo pode tomar as seguintes
trs formas

intent(in)
Usado apenas para passar dados de entrada para a subrotina
intent(out)
Usado apenas para passar dados de sada para o programa principal
intent(inout) Usado nos dois casos, para receber e passar dados.

O objetivo do atributo INTENT informar ao compilador como o programador quer usar


cada um dos argumentos listados. Isto ajudar a detectar erros ainda durante a fase de
compilao.
Apresenta-se abaixo o primeiro programa exemplo sob corrupo de dados, apresentado
na seo anterior, agora escrito utilizando o atributo INTENT.
program eliminando_corrupcao_de_dados

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

53

Fortran 90/95
!O objetivo deste programa mostrar que o bom uso do atributo INTENT, ajuda
!a combater a corrupo de dados dentro de uma subrotina (ou function).
!
!Programmer: joao batista aparecido
ilha solteira, 11 dezembro 1999
!
implicit none
real :: x = 1.5, y = 2.5, z
!invocando a subrotina
call soma(x, y, z)
stop
end program eliminando_corrupcao_de_dados
subroutine soma(a, b, c)
implicit none
real, intent(in) :: a, b
real, intent(out) :: c
!corrompendo o dado b. Isto pode ocorrer por digitao distrada
!em um cdigo grande,
!por fragmentos de cdigo no deletado e assim por diante.
b = b*2
!soma dois reais
c=a+b
return
end subroutine soma

Quando da compilao, o compilador acusar de imediato o erro, e mostrar claramente


qual o erro e onde encontra-se. Basta compilar para ver!
Portanto, sempre declare o atributo INTENT para todos os argumentos de uma subrotina.
6.1.2 Passando arrays para subrotinas
Como estabelecido anteriormente, um escalar passando do programa principal para
um subrotina simplesmente passando um ponteiro que aponta para a varivel. Se o argumento
um array o programa principal passa um ponteiro que aponta para o primeiro elemento do
array. A pergunta que surge : Como a subrotina fica sabendo do da forma e das extenses do
array? O rank do array ser definido no atributo dimension colocado na subrotina, mas ainda
fica faltando a informao sobre a extenso do array em cada direo. Existem trs formas de
informar subrotina quais as extenses do array em cada direo.
A primeira forma de se fazer isto passar as extenses do array via argumentos da
prpria subrotina e ento utilizar esta informao em uma declarao de atributo dimension e
definir por completo a forma do array. Os arrays passados desta forma so denominados de
arrays com forma explicita, uma vez que sua forma passada explicitamente.
A seguir apresenta-se um programa que utiliza este tipo de passagem de argumentos do
tipo array
program passando_array_1
!Objetivo: Mostrar a passagem de um array do program principal
!para um subrotina de forma explicita
!
!programmer: joao batista aparecido
ilha solteira, 11 dezembro 1999
!

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

54

Fortran 90/95
implicit none
integer, parameter :: i_max = 100, j_max = 120
real, dimension(i_max,j_max) :: array1, array2
!atribuio de valores aos arrays
array1 = 5.0
!invocando a subrotina passa_array
call passa_array(i_max, j_max, array1, array2)
stop
end
subroutine passa_array(i, j, x, y)
implicit none
integer, intent(in) :: i, j
real, intent(in), dimension(i,j) :: x
real, intent(out), dimension(i,j) :: y
y = sqrt(x)
return
end subroutine passa_array

Note que este tipo de passagem de array suporta operaes sobre arrays completos.
Uma segunda maneira de se passar as informaes de um array para o compilador
declarar na subrotina cada extenso do array com um asterisco. Neste caso o compilador no
sabe nada sobre as dimenses do array, e as operaes de verificao de limites do array e
operaes sobre arrays inteiros no so permitidas. Os arrays passados desta forma so
chamados de arrays de tamanho presumido.
O programa mostrado acima adaptado para fazer passagem de array neste novo
formato, a seguir o cdigo
program passando_array_2
!Objetivo: Mostrar a passagem de um array do program principal
!para um subrotina de forma implicita
!
!programmer: joao batista aparecido
ilha solteira, 11 dezembro 1999
!
implicit none
integer, parameter :: i_max = 100, j_max = 120
real, dimension(i_max,j_max) :: array1, array2
!atribuio de valores aos arrays
array1 = 5.0
!invocando a subrotina passa_array
call passa_array(i_max, j_max, array1, array2)
stop
end
subroutine passa_array(i, j, x, y)
implicit none
integer, intent(in) :: i, j
integer :: m

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

55

Fortran 90/95
!note a seguir os asteriscos nos atributos dimension
real, intent(in), dimension(*) :: x
real, intent(out), dimension(*) :: y
do m = 1,i*j
y(m) = sqrt(x(m))
end do
return
end subroutine passa_array

Note que neste caso o programa no suporta a operao sobre array completo
y = sqrt(x), e intuitivo que no lugar desta expresso devssemos colocar dois laos de DO
uma vez que no programa principal estes arrays so rank 2. No entanto isto no funcionou,
porque como o compilador no sabe nada sobre o rank nem as extenses do array em cada
direo, ele interpreta que trata-se um um array rank 1, no formato em que os dados so
armazenados na memria. Ento ao invs de colocar dois DOs, para cobrir as duas extenses
dos arrays rank 2, tive que colocar apenas um DO com lao igual ao tamanho (quantidade de
elementos) do array. A ento funciona.
Evite, fortemente, a passagem de arrays para subrotinas pelo mtodo do tamanho
presumido.
Uma terceira forma de fazer a passagem de array utilizando arrays de forma
presumida juntamente com uma interface explicita para a subrotina. Veremos mais adiante
neste captulo como fazer isto.
Procure sempre fazer a passagem de arrays pelo mtodo da forma explicita ou da forma
presumida com interface explicita.
6.1.3 Passando variveis caracter para subrotinas
Quando uma varivel caracter passada para um subrotina no necessrio passar o
tamanho da varivel, bastando colocar um asterisco no local onde apareceria o seu tamanho,
no cdigo da subrotina. Se for necessrio saber o tamanho da varivel caracter pode-se usar a
funo intrnseca LEN(varivel_caracter). Ver exemplo abaixo
program passando_caracter
implicit none
character(len = 5) :: word = 'manga'
call caracter(word)
stop
end program passando_caracter
subroutine caracter(x)
implicit none
character(len = *)x
write(*,*)'O tamanho da varivel caracter ',x,' = ',len(x)
return
end subroutine caracter

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

56

Fortran 90/95
6.2 A declarao e o atributo SAVE
Os valores de todas as variveis locais de uma subrotina tornam-se indefinidos toda vez
que a subrotina termina de executar. Surge ento a seguinte pergunta: Quando a subrotina for
acessada por um segunda vez qual ser o valor inicial assumido por uma determinada varivel
local da subrotina? Pela afirmao na primeira linha deste pargrafo pode-se dizer que o valor
ser indeterminado, uma vez que o programa (ou sistema operacional) poder ter destinando
um novo endereo na memria para aquela varivel local. Pode acontecer tambm que a
posio de memria ocupada pela varivel local pela primeira vez tenha sido usada
posteriormente para outra finalidade e o seu valor tenha mudado. De qualquer forma evite
fiar-se em valores volteis armazenados na memria entre um chamada e outra da subrotina,
embora algumas vezes estes valores parecem permanentes.
O Fortran prov um mecanismos para tornar perene o valor de uma varivel local de
uma subrotina, normalmente voltil entre duas chamadas. o atributo SAVE que tornar
permanente o valor da varivel local entre chamadas consecutivas de uma subrotina. Sua
declarao como segue
real, save :: lista_de variveis
integer, save, dimension (5, 6) :: x, y

6.3 Arrays automticos


Aprendeu-se no captulo anterior a alocar arrays alocveis em programas principais bem
como a desaloc-los. Pode-se fazer o mesmo em subrotinas, no entanto existe uma forma mais
fcil e prtica de conseguir o mesmo efeito. Considerando que toda varivel local de subrotina
voltil, ou seja ela torna-se indefinida depois que a execuo da subrotina termina, pode-se
criar arrays locais, passando apenas as extenses do array via argumentos da subrotina. Veja
a seguinte uma subrotina criando um array rank 2 local chamado array1 com extenses p e q
subroutine array_automatico(p,q)
implicit none
real, dimension array1(p,q,)
outras_declaracoes_executaveis
return
end subroutine array_automatico

Assim, use arrays automticos para criar locais temporrios de trabalho em subrotinas.
Use arrays alocveis para criar locais de trabalho temporrios de trabalho no programa
principal ou que vai ser criado em uma subrotina e destrudo em outra. Em Fortran 95 os
arrays alocveis criados dentro de subrotinas so automaticamente destrudos assim que a
execuo da rotina termina, exceto aqueles que receberam o atributo SAVE.
6.4 Compartilhando dados usando mdulos (modules)
Pelo visto at o momento o programa principal e as subrotinas so programas distintos
que trocam informaes entre si, via uma lista de argumentos.
O Fortran 90/95 possui uma nova forma de passar dados (e outras informaes tambm,
como veremos mais adiante) que mais flexvel e segura. Assim programas Fortran,
subrotinas e funes podem compartilhar informaes usando mdulos (modules). Mdulo
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

57

Fortran 90/95
uma unidade de programa compilada separadamente que contm as definies e valores
iniciais dos dados que deseja-se compartilhar entre o programa e os sub-programas. Para uma
unidade de programa acessar os dados no mdulo, basta mencionar o nome do mdulo logo
aps a declarao USE. Esta declarao deve ir logo aps a declarao do nome do programa
ou sub-programa. Para que os dados contidos no mdulo no fiquem volteis necessrio
utilizar a declarao SAVE na seo de declarao de variveis.
A forma geral de definir um mdulo
module nome_do_modulo
declaraes
end module nome_do_modulo

A forma geral de invocar um mdulo usar a seguinte declarao


use nome_do_modulo

na primeira linha aps o cabealho do programa ou sub-programa.


A seguir temos um exemplo de um mdulo para compartilhar constantes.
module constantes
implicit none
save
!definindo as constantes
real :: pi = 3.14159, e = 2.718281828
end module constantes
program modulo
!Objetivo: Mostrar o uso de modulos para compartilhar dados entre programas.
!
!programmer: joao batista aparecido
ilha solteira, 11 de dezembro 1999
!
use constantes
implicit none
integer, parameter :: i_max = 10
real, dimension(i_max) :: x, y, z
integer :: i
do i = 1, i_max
x(i) = sqrt(real(i)/i_max)
y(i) = cos(real(i)*pi*x(i))
end do
call sub_seno(i_max, x, z)
stop
end program modulo
subroutine sub_seno(m, t, s)
use constantes
implicit none
integer :: i, m
real, dimension(m) :: t, s
do i = 1, m

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

58

Fortran 90/95
s(i) = sin(real(i)*pi*t(i))
end do
end subroutine sub_seno

6.5 Sub-programas mdulo


Alm de dados os mdulos podem conter subrotinas e funes, que so chamadas ento
subprogramas-mdulo. Estes subprogramas-mdulo so compilados como componentes do
mdulo e so disponibilizados para as unidades de programa atravs do uso da declarao
USE. Os subprogramas inclusos em um mdulo devem vir depois da declarao de dados
compartilhados e devem ser precedidos pela declarao CONTAINS. Esta declarao diz ao
compilador que o restante de cdigo so subprogramas inclusos.
Assim um mdulo pode conter uma coleo de subrotinas, como segue
module banco
implicit none
save
real :: pi = 3.14159, e = 2.718281828
contains
subroutine sub1(x, y)
implicit none
real, intent(in) :: x
real, intent(out) :: y
y=sin(pi*x)
return
end subroutine sub1
subroutine sub2(m, x, y)
implicit none
real, intent(in) :: x
real, intent(out) :: y
integer, intent(in) :: m
y = exp(real(m)*x)/e
return
end subroutine sub2
end module banco
program banco_de_rotinas
use banco
implicit none
real :: a = 2.0, b, c
integer :: j = 5
call sub1(a, b)
call sub2(j, a, c)

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

59

Fortran 90/95
stop
end program banco_de_rotinas

6.5.1 Usando mdulos para criar interfaces explicitas


Sabe-se que possvel criar e compilar subrotinas separadamente e depois coloc-las
juntas usando o linker. Ento porque ter o trabalho extra de colocar estas subrotinas em um
mdulo, compilar e depois lincar de novo? A razo que o mdulo prov uma maneira
superior de compartilhamento de dados, de tal forma que mais informaes sobre as
subrotinas estaro disponveis ao compilador, que poder ento fazer um melhor controle do
programa. Quando o programa (usando mdulo) compilado, o compilador verifica o nmero
de argumentos, os tipos dos argumentos, se o argumento um array ou no, os atributos
INTENT de cada argumento, e assim por diante.
Um sub-programa compilado dentro de um mdulo e acessado atravs de uma
declarao USE tm uma interface explicita. Ento o compilador do Fortran automaticamente
sabe explicitamente todos os detalhes sobre cada argumento no subprograma sempre que este
usado e verifica a interface para confirmar que est sendo usada adequadamente.
Quando os subprogramas no esto dentro de um mdulo o compilador tm pouca
informao sobre os subprogramas. Estes subprogramas tm um interface implcita. Um
exemplo disto o programa mostrado acima chamado corrupcao_de_dados_2 onde os
argumentos da subrotina esto declarados de forma errada. Enquanto deveriam ser reais, esto
declarados como inteiros. Mais adiante mostraremos a soluo para evitar este tipo de
corrupo de dados utilizando o conceito de mdulo. Quando compilando um programa deste
tipo, o compilador apenas assume que tudo vai transcorrer bem, ou seja que a quantidade e os
tipos dos argumentos esto corretos, que esto na ordem correta, e que o tamanho dos arrays
esto corretos. Se algo estiver errado o programa falhar totalmente.
Mostra-se abaixo o programa corrupcao_de_dados_3 que o corrupcao_de_dados_2 com
a subrotina escrita dentro de um mdulo.
module auxiliar
contains
subroutine soma(a, b, c)
implicit none
!introduzindo a corrupo nos dados. Via uma declarao
!incorreta de tipo na subrotina
integer :: a,b,c
!soma dois reais
c=a+b
return
end subroutine soma
end module auxiliar
program corrupcao_de_dados_3
!O objetivo deste programa eh mostrar a corrupo de dados quando
!se utiliza subrotinas
!
!Programmer: joao batista aparecido
ilha solteira, 11 dezembro 1999
!
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

60

Fortran 90/95
use auxiliar
implicit none
real :: x = 1.5, y = 2.5, z
!invocando a subrotina
call soma(x, y, z)
stop
end program corrupcao_de_dados_3

Aps a compilao deste programa (usando o Compildor da Microsoft V4.0) percebe-se


que o resultado no to bom quanto esperado. O compilador, dependendo das diretivas
internas (trs: no warning, normal warning, and warning treated as error) pode acontecer trs
coisas: 1) na opo no warning, no emite nada, ignorando o erro; 2) na opo normal
warning, identifica claramente o erro mas emite mensagem apenas de warning; e 3) na opo
warning treated as error o compilador emitiu os mesmos warnings do item 2, mas identificou
que tinha um erro.
digno de nota que o resultado (da compilao, com os warnings tratados com erros)
apresentado quando compilando os programas corrupcao_de_dados_3 e corrupcao_de_dados_2
foram praticamente idnticos, ou seja este compilador est implicitamente instrudo a fazer a
verificao dos argumentos de um subrotina mesmo quando no possui uma interface
explicita. A literatura mostra que nem todos compiladores fazem isto.
Quando ainda estiver na fase de desenvolvimento de um programa, sempre use as
opes de emisso de warnings da forma mais restritiva possvel, para evitar deixar escapar
erros importantes disfarados de simples warnings.
6.5.2 Passando arrays para subrotinas usando mdulos e arrays de forma assumida.
Como dito anteriormente, quando uma subrotina tem uma interface explicita, toda a
informao necessria sobre os argumentos estaro disponveis para o compilador. Assim
podemos ento desenvolver a terceira forma de passar arrays para uma subrotina, mencionada
anteriormente neste captulo. Vimos anteriormente duas formas de passagem: A explicita
onde as informaes sobre os arrays so passadas via argumento da subrotina e ento usados
por ela. Outra forma era a do tamanho assumido do array, onde a subrotina apenas assume
que o array rank 1 e que tem um determinado tamanho.
Veremos agora a terceira forma onde as informaes sobre o rank e as extenses do
array so passadas via uma interface explicita usando mdulo. Abaixo apresenta-se uma nova
verso do program passando_array_1, a passando_array_3,
module passando_array
contains
subroutine passa_array(x,y)
implicit none
real, intent(in), dimension(:,:) :: x
real, intent(out), dimension(:,:) :: y
integer :: i1, i2, j1, j2, m1, m2, n1, n2
!Se necessario as dimensoes dos arrays podem ser recuperadas
!diretamente, como abaixo
i1 = lbound(x,1)
i2 = ubound(x,1)
j1 = lbound(x,2)

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

61

Fortran 90/95
j2 = ubound(x,2)
m1 = lbound(y,1)
m2 = ubound(y,1)
n1 = lbound(y,2)
n2 = ubound(y,2)
y = sqrt(x)
return
end subroutine passa_array
end module passando_array
program passando_array_3
!Objetivo: Mostrar a passagem de um array do program principal
!para um subrotina usando array de forma assumida e mdulo
!
!programmer: joao batista aparecido
ilha solteira, 12 dezembro 1999
!
use passando_array
implicit none
integer, parameter :: i_max = 10, j_max = 12
real, dimension(i_max,j_max) :: array1, array2
!atribuio de valores aos arrays
array1 = 5.0
!invocando a subrotina passa_array
call passa_array(array1, array2)
stop
end program passando_array_3

interessante notar que neste mtodo de passagem de arrays no necessrio passar


explicitamente a extenso do array em cada direo, estes valores podem ser obtidos na
prpria subrotina usando as declaraes LBOUND e UBOUND. Os arrays passados assim
suportam operaes sobre array completo.
6.6 Funes Fortran 90/95
Uma funo um subprograma Fortran que produz apenas um resultado de sada,
embora podendo ser um array. O nome da funo pode ser usado no lado direito de uma
funo aritmtica como uma varivel qualquer. O Fortran tm suas prprias funes
intrnsecas (j falado anteriormente) e suporta tambm funes definidas pelo programador. O
uso das funes definidas pelo usurio similar aquele das funes intrnsecas. A forma geral
de uma funo
function nome_da_funo (lista_de_argumentos)
declaraces_no_executveis
declaraes_executveis
nome_da_funo = expreso
return
end function nome_da_funo

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

62

Fortran 90/95
A funo deve comear com a declarao FUNCTION e terminar com a declarao END
FUNCTION. O nome da funo pode conter at 31 caracteres sendo que o primeiro deve ser
alfabtico.
Uma funo invocada quando seu nome mencionado em uma expresso aritmtica.
Quando isto ocorre o programa para a execuo e passa o controle da execuo para a
primeira linha da funo que efetua sua execuo, quando esta termina, o controle retornado
ao programa que invocou a funo. Quando a funo retorna, o seu valor usado para
continuar o processamento onde ocorria seu nome na expresso aritmtica. Uma funo pode
ser vazia de argumentos, neste caso deve-se colocar os dois parnteses sem nada entre. Como
o nome da funo retorna um valor, ento este nome deve ser declarado na seo de
declarao de variveis, tanto no programa que invoca quanto na prpria funo.
A passagem de argumentos nas funes ocorre da mesma forma que nas subrotinas.
program funcao
!Objetivo: Mostrar a tcnica de uso de uma function, calculando
!o valor assumido por uma parabola, sendo conhecido os coeficientes
!a, b, c e a coordenada x.
!
!programmer: joao batista aparecido ilha solteira, 12 de dezembro 1999
!
implicit none
real :: a = 2.0, b = 3.5 , c = -5.0 , x = 1.0 , y, parabola
y = parabola(a, b, c, x)
stop
end program funcao
function parabola(r, s, t, w)
implicit none
real :: r, s, t, w, parabola
parabola = (r*w+s)*w+t
return
end function parabola

6.7 Funes puras (pure functions) e funes elementares (elemental functions)


Duas novas classes de funes disponveis em Fortran 90/95, destinadas principalmente
(porm no somente) ao processamento paralelo do tipo SIMD (single instruction multiple
data) so as funes puras (pure functions) e as funes elementares (elemental function).
6.7.1 Funes puras (pure functions)
Funes puras so aquelas que no tm efeitos colaterais, isto os seus argumentos
no podem ser modificados, nem outros dados podem ser modificados tais como aqueles
contidos em mdulos. Adicionalmente, variveis locais no podem ter o atributo SAVE, e
tambm no podem ser inicializadas em declaraes de tipo (uma vez que isto implicitamente
implicaria em SAVE). Qualquer funo invocada por uma funo pura tambm dever ser
pura. Todos os argumentos de uma funo pura devem ter a declarao de atributo
INTENT(IN), alm do mais no devem fazer nenhuma operao de entrada e sada de dados.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

63

Fortran 90/95
Uma vez que funes puras no tem efeitos colaterais, elas so ideais para se utilizar
junto com a declarao FORALL, onde podem ser executadas em (paralelo) qualquer ordem.
Funes puras propriamente ditas s so definidas no Fortran 95, embora seja possvel
criar algo parecido em Fortran 90 declarando todos os argumentos da funo com o atributo
INTENT(IN).
Para declarar um funo pura basta acrescentar o prefixo PURE antes da palavra
FUNCTION como segue
pure function nome_da_funcao (lista_de_argumentos)

6.7.2 Funes elementares (elemental functions)


Funes elementares so aquelas que operando com escalares como argumento
tambm operam com arrays ou sees de arrays como argumento. O resultado que sai de
uma funo elementar tem a mesma forma do argumento de entrada. Isto , se o argumento
um escalar o resultado ser um escalar, se o argumento um array o resultado ser um array
com a mesma forma do array de entrada.
Funes intrnsecas elementares so disponveis em Fortran 90 e Fortran 95, mas
funes elementares definidas pelo programador so suportadas apenas no Fortran 95.
Funes elementares definidas pelo programador devem ser tambm funes puras e
atender tambm as seguintes restries:
1) Todos os argumentos devem ser escalares e no devem ter o atributo POINTER
(voltaremos ao pointer em outro captulo);
2) A funo deve ser escalar e no deve ter o atributo POINTER;
3) Argumentos da funo no podem ser usados em declaraes de tipo. Isto probe o uso de
arrays automticos.
Funes elementares so especificadas para escalares mas que podem tambm ser usadas
com argumentos do tipo array.
Para declarar um funo elementar basta acrescentar o prefixo ELEMENTAL antes da
palavra FUNCTION como segue
elemental function nome_da_funcao (lista_de_argumentos)

6.8 Passando subprogramas como argumentos para outros subprogramas


Quando um subprograma invocado, a lista de argumentos passada como um
conjunto de ponteiros que apontam para as posies de memria ocupadas por aqueles
argumentos. Como cada posio de memria interpretada pelo subprograma depende do tipo
e tamanho declarado no subprograma. Esta passagem por referncia pode ser estendida para
permitir passar tambm ponteiros que apontem para outros subprogramas. Em Fortran
funes e subrotinas podem ser passadas como argumento para outras funes ou subrotinas.
6.8.1 Passando funes como argumento
Se o nome de uma funo mencionado na lista de argumentos de um subprograma,
ento um ponteiro passado para o subprograma. Se o argumento correspondente funo for
mencionado internamente no subprograma, quando o subprograma executado, ento a
funo receber o comando da execuo.
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

64

Fortran 90/95
Todo funo usada como argumento dever ter o atributo EXTERNAL.
Abaixo apresenta-se um exemplo de uma subrotina que extrai valores de uma funo
em certas posies definidas pela subrotina.
program funcao_como_argumento
!Objectivo: Mostrar o uso de uma funo Fortran como argumento de
!um outro subprograma: funo ou subrotina.
!
!programmer: joao batista aparecido ilha solteira, 12 dezembro 1999
!
!Declarando as variveis do programa principal.
!Note que a funo f aparece aqui com os atributos real e external
implicit none
integer :: i
integer, parameter :: i_max = 100
real, external :: f
real, dimension(i_max) :: x, y
!Lao de atribuio de valores a x
do i = 1, i_max
x(i) = real(i)/10.0
end do
!Rotina para extrair os valores de uma funo f, definida pelo usurio
call extrai_valor(f, i_max, x, y)
!terminao do programa
stop
end program funcao_como_argumento
subroutine extrai_valor(g, m, t, s)
!Subrotina que extrai os valores da funo nas posies definidas
!no programa principal
!declarao de variveis. Note que aqui chamei localmente a funcao de g
implicit none
real :: g
integer :: m, j
real, dimension(m) :: t, s
!Lao onde a funcao invocada para os vrios valores do argumento.
do j = 1, m
s(j) = g(t(j)) ! Aqui a funcao sendo invocada
end do
!Finalizando a execuo da subrotina
return
end subroutine extrai_valor
function f(x)
!Funo que recebe um escalar e retorno o valor da funo para aquele argumento
!Declaracao de variveis
implicit none
real :: x, f
f = sin(x)+x ! A funcao sendo avaliada para o argumento x.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

65

Fortran 90/95
!Completando a execuo da funo.
return
end function f

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

66

Fortran 90/95

CAPTULO 7
OUTROS TIPOS DE DADOS
Neste captulo vamos apresentar nmeros reais e inteiros com comprimentos (kind)
diferentes daqueles apresentados at o momento. Apresenta-se tambm o tipo de dados
COMPLEX, e o tipo de dados definido pelo usurio (UDT User Data Type). Este conceito,
UDT, tambm conhecido por ADT (Abstract Data Type). A primeira terminologia enfatiza
que este tipo de dado definido pelo usurio, contrariamente aos tipos bsicos de dados,
previamente definidos no compilador. A segunda terminologia enfatiza que este tipo de dados
parte de algo bsico, ou no abstrato, para construir algo que transcende, ou abstrai, os tipos
bsicos de dados.
7.1 Outros tamanhos de dados para variveis do tipo real
Como j visto anteriormente o tipo real de dados usado para representar nmeros com
ponto flutuante. Na maioria dos computadores hoje operando o tamanho default da varivel
real, tambm chamado de preciso simples (single precision) usualmente 4 bytes, ou seja 32
bits. Conforme explicado em captulo anterior estes 32 bits so divididos em dois grupos, um
para representar a mantissa e o outro para representar o expoente.
A implementao padro de tipos de dados reais com preciso simples em geral ter
uma preciso de, aproximadamente, 7 casas decimais e os nmeros estaro em uma faixa de
10-38 a 10+38. Caso seja necessrio ou desejvel representar nmeros reais com mais de 7 casas
decimais e com uma faixa maior que de 10-38 a 10+38, ento ser necessrio utilizar variveis
reais com tamanhos maiores que 32 bits. O Fortran possui um tipo de dados com tamanho
maior para representao de dados com maior preciso e maior faixa. O tipo de dados reais
com maior tamanho so denominados de dupla preciso (double precision). Uma varivel real
com dupla preciso tem usualmente 8 bytes ou 64 bits, nestes casos a implementao mais
comum usar 53 bits para a mantissa e 11 bits para o expoente. Os 53 bits da mantissa so
suficientes para representar, aproximadamente, 16 casas decimais, e os 11 bits do expoente
so suficientes para representar nmeros em uma faixa de 10-308 a 10+308.
7.1.1 Tamanhos de dados para variveis e constantes do tipo real
Como o Fortran prov para tipos de dados reais mais de um tamanho (kind) necessria
a existncia de uma maneira de declar-los. Para tal existe o parmetro de tamanho (kind type
parameter) para declarar os diferentes tamanhos. A seguir tem-se algumas exemplos de como
efetuar esta declarao de tamanho de variveis ou constantes reais
real(kind = 4) :: r,s ou real(4) :: r,s
real(kind = 8) :: w ou real(8)

Cada fabricante de compilador livre para definir o tamanho da palavra para cada
representao de dados reais. Assim kind = 4 pode na maioria dos computadores significar
uma palavra com 32 bits, mas em outros pode significar uma palavra com 64 bits. Assim o
fragmento de cdigo escrito acima torna-se dependente de cada processador. Na Tabela 7.1
apresenta-se os tamanhos e os tipos de nmeros reais de alguns compiladores Fortran 90. Uma
maneira mais elegante, mas ainda dependente do processador, de escrever o trecho de cdigo
acima
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

67

Fortran 90/95
integer, parameter :: single = 4, double = 8
real(kind = single) :: r,s ou real(single) :: r,s
real(kind = double) :: w ou real(double)

Tabela 7.1-Parmetros de tamanho (kind) e tamanho em bits de variveis reais em


compiladores Fortran 90
Computador/Compilador
real de 32 bits real de 64 bits real de 128 bits
Cray T90 Supercomputer/CF90
NH
4,8*
16
DEC/DEC Fortran 90
4*
8
NA
PC/Lahey Fortran 90
4*
8
NA
PC/Microsoft Powerstation 4
4*
8
NA
PC/NAGWare FTN90
1*
2
NA
* Parmetro default
possvel declarar o tamanho de um dado real colocando um apndice na atribuio do
dado, como segue
x = 37.5
y = 37.5_4
z = 37.5E0
w = 37.5D0
t = 37.5_double

Na maioria dos compiladores para microcomputadores, nas atribuies acima, a


primeira atribuio interpreta 37.5 como sendo um dado do tipo preciso simples (32 bits); na
segunda 37.5 representado por um tamanho que corresponde ao parmetro de tamanho igual
a 4, nestes casos em geral mas nem sempre (ver tabela acima) corresponde tambm a 32 bits;
a terceira corresponde exatamente primeira; na quarta 37.5 representado em preciso dupla
que em geral corresponde a 64 bits; a quinta corresponde exatamente quarta.
Um erro muito sutil que pode ocorrer e muito difcil de detectar o seguinte: suponha
que algum desejando uma representao em preciso dupla escrevesse o seguinte
integer(4), parameter :: double = 8
real(double) :: x = 0.33333333333333333

neste caso o valor armazenado em x ser 0.3333333, ou algo muito prximo. O que teria
ocorrido para o valor original 0.33333333333333333 fosse corrompido e se tornasse
0.3333333? A explicao est na maneira em que o compilador interpreta o cdigo fonte. O
que ocorreu foi o seguinte: o compilador ao interpretar o cdigo encontra o nmero
0.33333333333333333, como no encontra nenhum indicador extra, ento assume que o
tamanho daquela varivel de 4 bytes e portanto o que realmente armazenado, ainda no
procedimento intermedirio, do nmero 0.3333333. No passo seguinte o compilador executa
a atribuio na qual um nmero em preciso simples atribudo a uma varivel real, x, de
dupla preciso, que por fim assumir o valor x = 0.3333333, o restante dos bits no utilizados,
de maneira til, assumiro valores nulos. De qualquer forma o erro j foi cometido, e a
varivel x, definida de preciso dupla, em realidade estar operando com preciso simples. A
maneira correta de evitar este erro
integer(4), parameter :: double = 8
real(double) :: x = 0.33333333333333333_double

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

68

Fortran 90/95
7.1.2 Determinando o tamanho (kind) de uma varivel
O Fortran 90/95 prov uma funo intrnseca KIND para determinar o parmetro de
tamanho de um varivel. O programa abaixo mostra como usar a funo KIND
program usando_kind
implicit none
integer, parameter :: double = 8
write(*,*)kind(37.5), kind(37.5_4), kind(37.5e0), kind(37.5d0), &
kind(37.5_double)
stop
end program usando_kind

7.1.2 Definindo a preciso de uma varivel, independentemente do processador


As expresses preciso simples e preciso dupla no possuem unicidade em Fortran,
uma vez que em um processador a preciso simples pode estar usando 64 bits e a preciso
dupla 128 bits. No entanto outros computadores utilizam 64 bits para dupla preciso e 32 bits
para preciso simples. Desta forma dependendo do processador que se usa a interpretao do
que simples e dupla preciso poder variar, implicando muitas vezes em resultados
totalmente inesperados.
interessante utilizarmos alguma maneira de definir a preciso de um varivel de uma
forma o mais independente possvel do processador. O Fortran 90/95 apresenta uma funo
intrnseca que auxilia nesta tarefa. A funo chamada SELECTED_REAL_KIND, quando
executada retorna o parmetro de tamanho necessrio a uma varivel real, que corresponde a
uma preciso e faixa especificadas, para aquele processador especfico. A forma geral desta
funo
parametro_de_tamanho = selected_real_kind(p,f)

onde p a preciso em casas decimais desejada e f a faixa do expoente requerido em


potncia de dez. A funo retorna o menor parmetro de tamanho que satisfaz as condies
especificadas. Se esta funo retornar (1) significa que nenhum parmetro de tamanho
satisfaz a preciso especificada; se retornar (2) significa que nenhum parmetro de tamanho
satisfaz a faixa especificada; e se retorna 3 porque nenhum parmetro de tamanho satisfaz
a preciso e a faixa especificadas. A seguir tem-se alguns exemplos de uso desta funo
intrnseca
program usando_selected_kind
implicit none
integer :: valor_kind
valor_kind = selected_real_kind(p = 2,r = 10)
valor_kind = selected_real_kind(p = 5,r = 35)
valor_kind = selected_real_kind(p = 7)
valor_kind = selected_real_kind(r = 30)
valor_kind = selected_real_kind(p = 20,r = 350)
stop
end program usando_selected_kind

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

69

Fortran 90/95
No programa acima o primeiro valor_kind ser 4, porque em um PC (onde estou testando
os programas) os dados reais em preciso simples usa 4 bytes ou 32 bits e portanto atende ao
requisitado; o segundo valor de valor_kind ser tambm 4; o terceiro ser 8 porque uma
varivel de 4 bytes prov uma preciso de apenas 6.8 casas decimais, ou seja abaixo de 7; no
quarto caso ser 4 porque a faixa de uma varivel com 4 bytes ser de at 38; e por fim o
ltimo valor ser 3 indicando que nenhum parmetro de tamanho atende aquela
especificao.
Existem ainda outras funes intrnsecas relacionadas ao parmetro de tamanho (kind),
mostradas na Tabela 7.2
Tabela 7.2-Funes intrnsecas comuns relacionadas ao parmetro de tamanho (kind)
Funo intrnseca
Descrio
selected_real_kind(p,r) Retorna o menor valor do parmetro de tamanho com um
mnimo de p casas decimais e uma faixa 10r
selected_int_kind(r)
Retorna o menor valor do parmetro de tamanho com um
range 10r
kind(x)
Retorna o parmetro de tamanho da varivel x, onde x
uma constante ou varivel de qualquer tipo.
precision(x)
Retorna a preciso decimal de x, onde x real ou complexo.
range(x)
Retorna o expoente decimal de x, onde inteiro, real ou
complexo
7.1.3. Preciso dupla em funes intrnsecas
Todas as funes genricas do Fortran 90/95 que operam com preciso simples,
suportam tambm valores reais com preciso dupla. Se o argumento for preciso simples o
retorno ser preciso simples, se o argumento for preciso dupla a resposta ser tambm
preciso dupla.
7.2 Outros tamanhos (kinds) de dados para variveis inteiras
No caso de dados do tipo inteiro a idia geral totalmente semelhante quela dos dados
do tipo real. No caso dos inteiros mais simples, pois necessita-se especificar apenas a faixa
que o nmero deve satisfazer. Na Tabela 7.3 tm-se os parmetros de tamanho para dados do
tipo inteiro para alguns processadores.
Tabela 7.3-Parmetros de tamanho (kind) e tamanho de variveis inteiras em
compiladores Fortran 90
Computador/Compilador
inteiro
inteiro
inteiro
inteiro
inteiro
8 bits
16 bit
32 bits
48 bits
64 bits
Cray T90 Supercomputer/CF90
NA
NA
1,2,4
6*
8
DEC/DEC Fortran90
1
2
4*
NA
8
PC/Lahey Fortran 90
1
2
4*
NA
NA
PC/Microsoft Powerstation 4.0
1
2
4*
NA
NA
PC/NAGWare FTN90
1
2
4*
NA
NA
*Valores default
7.3 O tipo de dados COMPLEX

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

70

Fortran 90/95
O tipo COMPLEX uma das formas bsicas de representao de dados em compiladores
Fortran 90. Praticamente tudo que se disse at o momento sobre tipos reais aplica-se tambm
aos dados do tipo complexo. Um nmero complexo em realidade uma dupla de dados reais
que satisfazem um lgebra especial. Assim tem-se algumas funes implcitas que aplicam-se
para complexos. Para declarar variveis e constantes do tipo complexo procede-se da seguinte
maneira
complex, parameter :: x = (1.0, 2.0) ! Declarando e inicializando uma constante complexa
complex, dimension(55) :: y
! Declarando um array com 55 elementos complexos
complex :: z = (-1.5, 5.5)
! Declarando e inicializando uma varivel complexa

onde na dupla (a,b) o real da esquerda a componente real do dado do tipo complexo e b a
parte imaginria.
7.3.1 Aritmtica mista entre dados complexos e no complexos
Quando um complexo vai sofrer uma operao com um nmero no complexo o
programa converte o valor do dado no complexo para complexo e executa a operao.
7.3.2 Utilizando operadores relacionais com complexos
possvel comparar dois dados complexos usando o operador relacional == e pode-se
tambm verificar se so diferentes usando o operador /=. Os outros operadores relacionais >,
<, >= e <= no podem ser usados com complexos.
7.4 Tipos de dados derivados
Os tipos de dados bsicos do Fortran so: inteiros, reais, caracteres, lgicos e
complexos.
O Fortran permite ao usurio definir os seus prprios tipos de dados (UDT ou ADT),
so os chamados tipos derivados de dados. Eles so derivados porque devem ser construdos
utilizando aqueles tipos bsicos mencionados acima e eventualmente outros tipos de dados
derivados j definidos. Uma das vantagens dos dados derivados o encapsulamento, isto os
componentes internos dos dados derivados devem ser acessado explicitamente.
Um dado do tipo derivado uma maneira conveniente de agrupar um conjunto de
informaes, de uma maneira semelhante definio de um array como um conjunto de
elementos. Porm a sintaxe diferente, e cada elemento referenciado por um nome ao invs
de por um nmero.
Um dado derivado definido como uma seqncia de declaraes precedidas da
declarao TYPE e completado com a declarao END TYPE. A forma geral de declarao de
um UDT
type :: nome_do_tipo
componentes_da_declarao
end type nome_do_tipo

Abaixo apresenta-se um caso concreto de um dado derivado destinado a descrever


quantidade de frutos
type :: frutos_no_cesto
integer :: numero_bananas
integer :: numero_laranjas

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

71

Fortran 90/95
integer :: numero_cajus
integer :: numero_mangas
integer :: numero_goiabas
end type frutos_no_cesto

Outro exemplo simples aqueles destinado a descrever as dimenses de um caixa


Cartesiana, que possui altura, comprimento e largura. Assim, um UDT para descrever caixas
deste tipo seria
type :: caixa
real :: largura
real :: profundidade
real :: comprimento
end type caixa

Uma vez que uma determinado UDT esteja definido possvel utiliz-lo e produzir as
seguintes declaraes
type (frutos_no_cesto) :: cesto1, cesto2, cesto_na_prateleira
type (frutos_no_cesto), dimension(20) :: cesto_grande, cesto_pequeno

Um dado derivado tambm chamado de estrutura. Uma estrutura pode ser inicializada
utilizando um construtor de estruturas, de um forma semelhante ao construtor de arrays, como
segue
cesto1 = frutos_no_sexto(12, 9, 0, 2, 5)
cesto2 = frutos_no_sexto (0, 24, 3, 0, 6)

Na primeira linha de cdigo, logo acima, o construtor da estrutura cesto1 ir atribuir 12


ao numero_bananas, 9 ao numero_laranjas, 0 ao numero_cajus, 2 ao numero_mangas, e 5 ao
numero_goiabas.
Uma estrutura pode ser usada como elemento em outra estrutura.
7.4.1 Acessando elementos de uma estrutura
Os componentes numricos bsicos de uma estrutura podem ser usados de acordo com
as operaes que cada tipo suporta. O mesmo vale para os componentes do tipo caracter.
Como estes elementos esto encapsulados dentro da estrutura, para acess-los ser necessrio
usar o seletor de componentes (component selector)
No exemplo dos cestos de frutos mostrados acima pode-se atribuir valor a um
componente da estrutura da seguinte maneira
cesto1%numero_bananas = 13

ou
cesto1.numero_bananas = 13

estas duas formas acima, usando % ou usando . so equivalentes. O mais comum em todas
linguagens usar o ponto.
Para somar o nmero de goiabas no cesto1 e no cesto2, faz-se
quantidade_goiabas = cesto1.numero_goiabas + cesto2.numero_goiabas

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

72

Fortran 90/95
Os tipos de dados derivados podem ser definidos dentro de mdulos, evitando ter que
defini-los em todas as unidades de programa.
Abaixo apresenta-se o uso do UDT caixa, definido anteriormente
program UDT_caixa
implicit none
type :: caixa
real :: largura
real :: profundidade
real :: comprimento
end type caixa
type (caixa) :: caixa1, caixa2
real :: volume1, volume2
caixa1.largura = 1.5
caixa1.profundidade = 2.0
caixa1.comprimento = 5.7
caixa2 = caixa(3.5, 8.0, 2.)
volume1 = caixa1.largura*caixa1.profundidade*caixa1.comprimento
volume2 = caixa2.largura*caixa2.profundidade*caixa2.comprimento
stop
end program UDT_caixa

7.5 Imprimindo UDTs


Na impresso de uma UDT os membros sero impressos na seqncia em que foram
declarados. A formatao de cada componente segue as mesmas regras de formatao das
variveis bsicas. Tambm possvel imprimir cada componente, separadamente, utilizando o
seletor de componentes.
7.6 Armazenamento de UDT na memria e a declarao SEQUENCE
Devido sua caracterstica de realizar processamento paralelo SIMD o compilador
Fortran90 no armazena, necessariamente, os membros de uma UDT em posies contguas
de memria. Entretanto, sob certas circunstncias pode ser necessrio garantir que os
membros da UDT estejam em seqncia na memria, assim utiliza-se a declarao
SEQUENCE que informa ao compilador para proceder em conformidade. Segue abaixo um
exemplo de UDT utilizando a declarao SEQUENCE
type :: pessoa
sequence
caracter(64) :: nome
integer(1) :: idade
real(4) :: altura
real(4) :: peso
caracter(11) :: cpf
caracter(11) :: rg
end type pessoa

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

73

Fortran 90/95

CAPTULO 8
ASPECTOS AVANADOS DE FUNES, SUBROTINAS E MDULOS
Neste captulo apresenta-se alguns aspectos mais avanados de funes, subrotinas e
mdulos, visando ter um controle mais seguro da transferncia de dados entre estas unidades
de programa. Estas caractersticas permitem definir subrotinas e funes com argumentos
opcionais, com argumentos que variam de tipo. Adicionalmente apresenta-se maneiras de
definir operaes sobre tipos derivados de dados (UDTs).
8.1 Subprogramas internos
At o momento todos os subprogramas que definimos, funes, subrotinas e mdulos,
eram do tipo externo. Vamos ver agora como construir os chamados subprogramas internos.
O Fortran 90/95 suporta os subprogramas internos, que so funes e subrotinas que ficam
dentro do programa principal, ou de algum outro subprograma. Os subprogramas internos so
compilados juntamente com a compilao do programa hospedeiro, e podem ser invocadas
apenas por ele. O local no programa em que fica um subprograma interno logo aps a ltima
declarao executvel do programa, e antes das declaraes STOP e END PROGRAM.
Separando os subprogramas internos do restante do cdigo deve-se usar apenas a palavra
CONTAINS. De outra forma, todos os subprogramas internos devero estar entre a declarao
CONTAINS e a finalizao do programa. O nome de um subprograma interno no pode ser
passado como argumento de linha de comando a outro subprograma. Um subprograma interno
recebe todas as variveis e constantes definidas no seu hospedeiro, em outras palavras todas
as variveis e constantes do programa hospedeiro so globais para os seus subprogramas
internos. Quando define-se uma varivel no subprograma interno, que tenha o mesmo nome
de uma varivel do programa hospedeiro, ento esta varivel passa a ter um carter local, e
por conseguinte no consegue acessar o valor contido na varivel do mesmo nome no
programa hospedeiro.
8.2 Escopo de variveis e constantes
Os escopos possveis de todos os tipos de objetos (inteiro, real, lgico, complexo,
caracter e UDT) so: global, local e declarao.
Objetos globais so aqueles cuja definio atinge todas as instncias do programa
(programa principal e subprogramas), consequentemente os nomes destes objetos devem ser
nicos em todas as unidades do programa. Os nicos objetos que gozam desta propriedade so
o nome do programa principal, os nomes das funes, os das subrotinas, e os dos mdulos.
Utilizando-se mdulos tambm pode-se produzir variveis que tenham um escopo global,
quando todas as unidades de programa referenciarem um determinado mdulo de
compartilhamento de dados.
Objetos locais so definidos apenas dentro de algumas unidades do programa,
tambm chamadas de unidades de escopo. Alguns exemplos so: programas, funes,
subrotinas, e mdulos. O nome de um objeto de ser nico dentro de sua unidade de escopo,
porm o mesmo nome pode ser usado para outra varivel em outra unidade de escopo.
Um objeto tambm pode ter como escopo declarao do tipo DO implcito em
construtores de arrays, abaixo tem-se um exemplo de onde pode ocorrer este tipo de escopo
de variveis

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

74

Fortran 90/95
array1 = (/i**2, i = 1,100/)

Abaixo mostra-se um programa exemplo que apresenta todos os tipos de escopo: global,
local e de declarao.
module global
implicit none
save
integer, parameter :: j = 5
end module global
program escopo
!Objetivo: Demonstrar os tipos de escopo: global, local e declarao
!
!programmer: joao batista aparecido ilha solteira, 14 dezembro 1999
!programmer: joao batista aparecido ilha solteira, 02 agosto 2001
!
!Declarando variveis
use global
implicit none
integer, parameter :: k = 6
integer :: i
real, dimension(k) :: a
do i = 1, k
! Note que existem dois is um no DO e outro no construtor de array
a = (/(i*j, i = 1, k)/)
end do
call sub(k,a)
stop
end program escopo
subroutine sub(k,a)
use global
implicit none
integer :: k, i
real, dimension(k) :: a
do i = 1, j
a(i) = sin(a(i))
end do
return
end subroutine sub

No programa acima alm do nome do programa, da subrotina e do mdulo, tambm o


inteiro j definido no mdulo tm escopo global.
No programa principal tem-se um lao de DO em que o ndice (i) vai de 1 a k (= 6), este
lao inicializa o vetor a seis vezes, e dentro daquele lao tem o lao de DO implcito, cuja
varivel de controle tambm (i) que vai atribuir valores a cada posio do array, note que
no ocorre erro de compilao, nem erro de link, nem erro de execuo, isto porque a varivel
(i) do lao interno tem escopo apenas dentro do lao implcito, deixando de existir assim que
o lao completa-se, este o escopo de declarao. Para evitar problemas de interpretao ao
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

75

Fortran 90/95
se ler o cdigo procure escrever o nome das variveis de controle dos DOs implcitos
diferentes das dos DOs explcitos que envolvem em seu lao DOs implcitos.
Quando o lao de DO, do programa termina o valor da varivel i ser i = 7, ento a
subrotina sub invocada, e l dentro dela existe outro lao de DO no qual a varivel de
controle tambm (i). O valor de i dentro da subrotina vai variar de 1 a 5 e quando a
subrotina completar o valor de i ser i = 6, ento a subrotina passa o controle da execuo ao
programa principal e o valor armazenado na varivel i ainda i = 7. Isto ocorre porque a
varivel i da subrotina tem escopo apenas local, no podendo alterar o valor da varivel i que
encontra-se tambm no programa principal.
8.3 Subprogramas recursivos
As funes e subrotinas comuns do Fortran 90/95 no podem invocar a si mesmas, quer
seja diretamente ou indiretamente. Significa dizer que os subprogramas comuns do Fortran
no so recursivos. Alguns tipos de problemas podem ser resolvidos mais facilmente se
determinada funo ou subrotina recursiva. O Fortran 90/95 suporta funes e subrotinas
recursivas desde que tenham o atributo RECURSIVE, colocado antes da palavra FUNCTION ou
SUBROUTINE. Um exemplo clssico de uso de subrotina recursiva para calcular o fatorial de
um inteiro n. Abaixo apresenta-se um programa que faz o cmputo do fatorial de um inteiro n,
utilizando-se de uma subrotina recursiva.
program recursivo
implicit none
integer :: n = 5, valor
call fatorial(n, valor)
stop
end program recursivo
recursive subroutine fatorial(i, x)
implicit none
integer :: i, x, aux
if (i >= 1) then
call fatorial(i-1, aux)
x = i*aux
else
x=1
end if
return
end subroutine fatorial

Outro exemplo de uso de subrotina recursiva para efetuar a exponenciao inteira (n)
de um valor real (x). A seguir apresenta-se um programa para tal, utilizando-se de uma
subrotina recursiva.
program recursivo2
implicit none
integer :: n = 2
real :: x = 2, exp

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

76

Fortran 90/95
if(n >= 0) then
call exponenciacao(n, x, exp)
else
write(*,*)' Valor negativo de n, programa abortado!'
stop
end if
stop
end program recursivo2
recursive subroutine exponenciacao(i, x, y)
implicit none
integer :: i
real :: x, y
if (i > 0) then
call exponenciacao(i - 1, x, y)
y = x*y
else
y = 1.0
end if
return
end subroutine exponenciacao

No caso de definio de funes recursivas existe um complicao extra. Como j


vimos anteriormente para invocar uma funo necessrio que ela esteja em uma expresso
aritmtica, isto do lado direito da declarao de atribuio (=). Por outro lado para receber o
valor que retorna o nome da funo teria que estar do lado esquerdo do (=). Este problema foi
resolvido da seguinte forma: colocando-se uma especificao RESULT (varivel_de_retorno)
aps a lista de variveis da funo, de tal forma que o resultado retorne na
varivel_de_retorno, ao invs de retornar no nome da funo, podendo ser utilizado de um
forma semelhante das subrotinas. Abaixo apresenta-se uma declarao de um funo
recursiva func que usa o argumento arg para retornar o valor
recursive function func(lista_de_variaveis) result(arg)

Abaixo tem-se uma nova verso do programa para calcular o fatorial de n, agora
utilizando uma funo recursiva
program recursivo3
implicit none
integer :: n = 5, valor, fatorial
valor = fatorial(n)
stop
end program recursivo3
recursive function fatorial(i) result(retorno)
implicit none
integer :: i, retorno
if (i >= 1) then

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

77

Fortran 90/95
retorno = i*fatorial(i-1)
else
retorno = 1
end if
return
end function fatorial

8.4 Argumentos com palavras-chave e argumentos opcionais.


J foi dito vrias vezes que a quantidade, o tipo e o tamanho dos argumentos de uma
funo ou subrotina devem coincidir onde ela invocada e com sua definio. Caso contrrio
haver algum tipo de erro, de compilao, de lincagem ou de execuo. Existem situaes nas
quais possvel modificar a ordem em que os argumentos aparecem na chamada e no
subprograma, e mesmo assim o programa operar corretamente. Esta tcnica a ser descrita s
funcionar se o subprograma tiver uma interface explicita. Como j foi dito anteriormente
uma das maneiras de prover uma interface explicita colocar o subprograma dentro de um
mdulo. A outra forma, que veremos mais adiantes, consiste em prover explicitamente blocos
de interface. Se o subprograma possuir uma interface explicita ento possvel usar
argumentos nomeados, no programa que est invocando o subprograma, de tal forma que
seja possvel ao programa saber onde est cada argumento da lista de argumentos e fazer a
associao correta, mesmo com o argumentos embaralhados na lista. Um argumento nomeado
um argumento com a seguinte forma
palavra_chave = argumento_verdadeiro

onde palavra_chave o nome do argumento que est sendo associado com o argumento
verdadeiro. Se a invocao de um subprograma usa palavras-chave, ento os argumentos na
chamada podem ser arranjados em qualquer ordem porque as palavras-chave auxiliam o
compilador a saber qual argumento corresponde a qual.
Vamos ilustrar estas idias construindo um programa que chama uma subrotina duas
vezes. Na primeira chamada os argumentos esto colocados na lista de argumentos sem usar
palavras-chave, e na segunda vez est com os argumentos embaralhados porm usando
palavras-chave. O resultando em os ambos os casos ser o mesmo.
module sub
contains
subroutine sub1(r, s, t, u)
implicit none
real :: r, s, t, u
u=r+s+t
return
end subroutine sub1
end module sub
program argumento_embaralhado
use sub
implicit none
real :: a = 1.0, b = 2.0, c = 3.0, d

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

78

Fortran 90/95
call sub1(a, b, c, d)
write(*,*) d
call sub1(u = d, s = b, r = a, t = c)
write(*,*) d
stop
end program argumento_embaralhado

Esta prtica um pouco mais segura porm necessrio um gasto maior de tempo
escrevendo os argumentos da chamada do subprograma em uma forma mais complexa.
A principal conseqncia desta tcnica no entanto outra. Com este tipo de declarao
ser possvel ter argumentos opcionais. Argumentos opcionais so aqueles que podem ou no
aparecer na lista de argumentos e o subprograma no acusar erro de compilao e a execuo
continuar, alm do mais o compilador ter condies de saber qual o argumento que no
est presente. Obviamente argumentos opcionais s sero possveis em subprogramas com
interface explicita. Estes argumentos opcionais devero ser declarados com o atributo
OPTIONAL. Uma rotina que tem argumentos do tipo OPTIONAL pode usar a funo intrnseca
PRESENT para verificar se um dado argumento est presente. Se o argumento estiver presente,
PRESENT retornar TRUE, se estiver ausente PRESENT retornar FALSE. Abaixo apresenta-se
o programa anterior modificado para suportar a falta de alguns argumentos de entrada.
module sub
contains
subroutine sub1(r, s, t, u)
implicit none
real, optional, intent(in) :: r, s, t
real, intent(out) :: u
logical :: i_r, i_s, i_t
i_r = present(r)
i_s = present(s)
i_t = present(t)
if(i_r.and.i_s.and.i_t) u = r + s + t
if(i_r.and.i_s.and.(.not.i_t)) u = r + s
if(i_r.and.(.not.i_s).and.i_t) u = r + t
if((.not.i_r).and.i_s.and.i_t) u = s + t
if((.not.i_r).and.(.not.i_s).and.i_t) u = t
if((.not.i_r).and.i_s.and.(.not.i_t)) u = s
if(i_r.and.(.not.i_s).and.(.not.i_t)) u = r
if((.not.i_r).and.(.not.i_s).and.(.not.i_t)) u = 0.d0
return
end subroutine sub1
end module sub
program argumento_opcional
use sub
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

79

Fortran 90/95
implicit none
real :: a = 1.0, b = 2.0, c = 3.0, d
call sub1(a, b, c, d)
call sub1(u = d, r = a, t = c)
call sub1(u = d, s = b, t = c)
call sub1(u = d, s = b)
call sub1(u = d)
call sub1(u = d, r = a, t = c, s = b)
stop
end program argumento_opcional

O programa acima capaz de suportar e identificar os argumentos fora de ordem. Se


existe algum argumento ausente, e se existe algum, o compilador consegue identificar qual .
Evidentemente, se existe algum argumento faltando necessrio executar procedimentos
compatveis. Assim implementou-se algumas somas que levaram em considerao apenas os
argumentos presentes.
8.5 Interfaces para subprogramas e blocos de interfaces
Conforme j foi dito anteriormente desejvel que o programador coloque as subrotinas
e funes dentro de um mdulo, de tal forma que tenham automaticamente uma interface
explicita. No entanto nem sempre possvel colocar-se estas informaes dentro de um
mdulo. So vrias as situaes: imagine um conjunto de rotinas que no se tm o cdigo
fonte para fazer as modificaes; ou uma biblioteca antiga e muito grande que ficaria muito
caro re-escreve-la novamente; ou ainda uma biblioteca escrita em outra linguagem. Desta
forma til alguma ferramenta que permita a construo de interfaces explicitas sem
necessariamente ter que alterar o cdigo original. A maneira de se fazer isto utilizando
blocos de interface.
8.5.1. Criando blocos de interface
Os blocos de interface so criados no programa que invoca os subprogramas, colocados
na seo de declarao de variveis. Uma interface criada duplicando as informaes das
declaraes de atributo de todas as variveis da lista de argumentos, e colocadas entre as
declaraes INTERFACE e END INTERFACE. A forma geral para criar um bloco de interface
interface
subroutine nome_da_subrotina (lista_argumentos)
declaracoes_de_atributos_dos_argumentos
end subroutine nome_da_subroutine
function nome_da_function (lista_argumentos)
declaracoes_de_atributos_dos_argumentos
end function nome_da_function
end interface

A forma acima apresenta apenas um funo e uma subrotina, mas podem ser empilhadas
tantas quantas forem necessrias. Estas informaes contidas na interface so suficientes para
que o compilador reconhea a quantidade, tipo e tamanho dos argumentos. Segue, abaixo, um
programa exemplo
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

80

Fortran 90/95
program interface_explicita
implicit none
!Definindo o bloco de interface
interface
subroutine sub1(r, s, t, u)
implicit none
real, optional, intent(in) :: r, s, t
real, intent(out) :: u
end subroutine sub1
end interface
real :: a = 1.0, b = 2.0, c = 3.0, d
call sub1(a, b, c, d)
call sub1(u = d, r = a, t = c)
call sub1(u = d, s = b, t = c)
call sub1(u = d, s = b)
call sub1(u = d)
call sub1(u = d, r = a, t = c, s = b)
stop
end program interface_explicita
subroutine sub1(r, s, t, u)
implicit none
real, optional, intent(in) :: r, s, t
real, intent(out) :: u
logical :: i_r, i_s, i_t
i_r = present(r)
i_s = present(s)
i_t = present(t)
if(i_r.and.i_s.and.i_t) u = r + s + t
if(i_r.and.i_s.and.(.not.i_t)) u = r + s
if(i_r.and.(.not.i_s).and.i_t) u = r + t
if((.not.i_r).and.i_s.and.i_t) u = s + t
if((.not.i_r).and.(.not.i_s).and.i_t) u = t
if((.not.i_r).and.i_s.and.(.not.i_t)) u = s
if(i_r.and.(.not.i_s).and.(.not.i_t)) u = r
if((.not.i_r).and.(.not.i_s).and.(.not.i_t)) u = 0.d0
return
end subroutine sub1

Este programa usando uma interface explicita, produzida via um bloco de interface,
produz exatamente o mesmo resultado que outro mostrado mais acima que tinha uma
interface explicita produzida pelo fato da subrotina estar imersa em um mdulo. Os
parmetros listados em um bloco de interface deve coincidir em quantidade, tipo, ordem e
tamanho com aqueles do subprograma que se est interfaceando, mas no necessrio que o
nome seja o mesmo.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

81

Fortran 90/95
Sempre que possvel coloque as subrotinas e funes dentro de um mdulo de tal forma
que tenham um interface explicita, sem utilizar blocos de interface. Se for necessrio criar
vrios blocos de interface, ento coloque os dentro de um mdulo e as acesse via uma
declarao USE.
8.6 Subprogramas genricos
O Fortran 90/95 inclui entre suas funes intrnsecas, funes de uso genrico e funes
de uso especfico. As genricas operam sobre dados de diferentes naturezas, por exemplo:
inteiros, reais e arrays de inteiros e reais. As especficas operam apenas sobre um
determinado tipo de dado.
8.6.1 Subprogramas genricos definidas pelo programador
Viemos at o momento tratando com subprogramas (definidos pelo programador)
apenas do tipo especfico onde fixa-se o tipo de varivel, e o subprograma s funciona para
aquele tipo. O Fortran 90/95 suporta funes genricas definidas pelo programador. Suponha
a existncia de vrias rotinas capazes de somar dois dados de diferentes tipos e tamanhos, e
que queiramos produzir apenas um rotina que seja capaz de operar sobre todos os tipos de
dados e retornar um resultado compatvel. Se definirmos um nome genrico para a interface,
diferente do nome dos subprogramas dentro da interface, ento o compilador Fortran 90/95
ser capaz de entender que todos os subprogramas contidos dentro daquela interface so
verses especiais do subprograma genrico que se quer construir. A seguir apresenta-se um
programa que adiciona dois nmeros reais ou inteiros e de comprimentos diferentes.
module tipo_dado
!Mdulo para compartilhar os parmetros de tamanhos das variveis
save
integer, parameter :: curto = 2, longo = 4, simples = 4, duplo = 8
end module tipo_dado
program soma_generica
!Objetivo: Mostrar como se define uma funo genrica
!
!programador: joao batista aparecido, ilha solteira, 15 de dezembro 1999
!
use tipo_dado
implicit none
!Definio da interface genrica (soma)
interface soma
subroutine soma1(a, b, c) !Interface da subrotina que soma inteiros curtos
use tipo_dado
implicit none
integer(curto), intent(in) :: a, b
integer(curto), intent(out) :: c
end subroutine soma1
subroutine soma2(a, b, c)
use tipo_dado
implicit none

!Interface da subrotina que soma inteiros longos

integer(longo), intent(in) :: a, b
integer(longo), intent(out) :: c

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

82

Fortran 90/95
end subroutine soma2
subroutine soma3(a, b, c)
use tipo_dado
implicit none

!Interface da subrotina que soma reais simples

real(simples), intent(in) :: a, b
real(simples), intent(out) :: c
end subroutine soma3
subroutine soma4(a, b, c)
use tipo_dado
implicit none

!Interface da subrotina que soma reais duplos

real(duplo), intent(in) :: a, b
real(duplo), intent(out) :: c
end subroutine soma4
end interface
integer(curto) :: i = 1,j = 5, k
integer(longo) :: m = 2, n = 9, o
real(simples) :: x = 1.e0, y = -1.e0/3.e0, z
real(duplo) :: r = 1.d0, s = -1.d0/3.d0, t
call soma(i, j, k)
call soma(m, n, o)
call soma(x, y, z)
call soma(r, s, t)
stop
end program soma_generica
subroutine soma1(a, b, c) !Subrotina que soma dois inteiros curtos
use tipo_dado
implicit none
integer(curto), intent(in) :: a, b
integer(curto), intent(out) :: c
c = a+ b
return
end subroutine soma1
subroutine soma2(a, b, c) !Subrotina que soma dois inteiros longos
use tipo_dado
implicit none
integer(longo), intent(in) :: a, b
integer(longo), intent(out) :: c
c = a+ b
return
end subroutine soma2
subroutine soma3(a, b, c) !Subrotina que soma dois reais simples
use tipo_dado
implicit none

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

83

Fortran 90/95
real(simples), intent(in) :: a, b
real(simples), intent(out) :: c
c = a+ b
return
end subroutine soma3
subroutine soma4(a, b, c) !Subrotina que soma dois reais duplos
use tipo_dado
implicit none
real(duplo), intent(in) :: a, b
real(duplo), intent(out) :: c
c = a+ b
return
end subroutine soma4

Use blocos de interface genricos para definir subprogramas que podem operar com
tipos de dados variveis. Subprogramas genricos facilitam operaes com diferentes tipos de
dados.
8.6.2 Interfaces genricas para subprogramas em mdulos
No item anterior mostrou-se como criar um subprograma genrico usando interfaces
explicitas via bloco de interface. Agora mostra-se como fazer a mesma coisa porm usando
mdulo. A dificuldade em se fazer isto em um mdulo que se os subprogramas j est no
mdulo, eles automaticamente j tem cada um uma interface, ento como definir um interface
mais genrica se o conceito de mdulo probe a definio de uma interface explicitamente
dentro dele uma vez que ela j gerada automaticamente. O Fortran apresenta uma declarao
especial para efetuar esta tarefa a declarao MODULE PROCEDURE, que pode ser usada em
bloco de interface genrica. A forma desta declarao
module procedure lista_nome_procedure

onde procedure lista_nome_procedure a lista de subprogramas que compem a funo


genrica.
Para o caso mostrado no programa acima, a interface genrica para a subrotina soma
deve ser da seguinte forma
interface soma
module procedure soma1
module procedure soma2
module procedure soma3
module procedure soma4
end interface

O bloco de interface deve ser colocado no mesmo mdulo onde esto os subprogramas
componentes do subprograma genrico.
8.7 Estendendo o Fortran com declaraes e operadores definidos pelo programador

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

84

Fortran 90/95
Quando definimos no captulo anterior os tipos de dados derivados conseguimos apenas
atribuir valores s componentes dos dados derivados. Porm no foi possvel fazer operaes
sobre as variveis como um todo. As operaes bsicas dos operadores aritmticos binrios e
unrios no funcionam para dados derivados. Isto porque o programador deve fornecer
informaes suficientes, ao compilador, para se construir uma lgebra prpria de cada tipo
especfico de dado derivado. O Fortran 90/95 uma linguagem extensvel de tal forma que o
programador pode ir adicionando novos aspectos para acomodar tipos especiais de dados. J
vimos como definir tipos novos de dados, vamos ver agora como definir novos operadores.
Ou de outra forma como definir operadores para estes novos tipos de dados. Assim, com a
devida imaginao possvel dar novos sentidos para adio, subtrao, multiplicao,
diviso e comparaes de dados derivados.
Como isto pode ser feito? O primeiro passo construir um subprograma que execute o
desejado e coloc-lo em um mdulo. O segundo passo associar este subprograma com um
operador (smbolo) usando um bloco de interface de operador. A forma desta interface
interface operator (simbolo_do_operador)
module procedure nome_da_function
end interface

onde simbolo_do_operador qualquer um dos operadores intrnsecos (+,-,*,/,>,< etc.) ou


qualquer smbolo definido pelo programador. Um operador definido pelo programador pode
ter at 31 caracteres cercado por um ponto antes e um ponto depois, tal como .DIVIDIR. Mais
de um tipo de subprograma pode estar associado a um dado operador, mas ser necessrio que
estes subprogramas possam ser distinguidos uns dos outros atravs da anlise dos tipos e
tamanhos de seus argumentos. Quando o compilador encontra um operador, ento procura
pelo correspondente subprograma. Se o operador tem dois argumentos ento um operador
binrio, se tem apenas um unrio. Uma vez definido, o operador ser tratado como uma
referncia para a funo.
Se o operador sendo definido pela interface utiliza os smbolos dos operadores
intrnsecos (+,-,*,/, etc.) ento tem-se alguns restries adicionais:
1) No se pode mudar o sentido dos operadores intrnsecos quando estes operam sobre os
tipos bsicos de dados (inteiro, real, lgico, complexo e caracter). No entanto estes
operadores podem ser estendidos em outros sentidos para quando estiverem operando com
dados derivados;
2) O nmero de argumentos em uma funo deve ser consistente com suas natureza, ou seja
em uma adio s se pode somar dois nmeros de cada vez. Qualquer extenso do sentido
da soma deve atender a este requisito.
Pode-se estender tambm o sentido da declarao de atribuio (=) de uma maneira
similar. Para se fazer isto utiliza-se o bloco interface de atribuio, que tem a seguinte forma
interface assignment (=)
module procedure nome_subroutine
end interface

Para o operador de atribuio a interface deve ter uma subrotina ao invs de uma
function. A subrotina dever ter dois argumentos O primeiro o argumento de sada e deve
ter o atributo intent(out). O segundo o argumento de entrada e deve ter o atributo intent(in). O
argumento da esquerda corresponde ao lado esquerdo da atribuio e o direito ao da direita.
Abaixo apresenta-se uma aplicao para executar operaes sobre um tipo de dado
derivado que um vetor com trs componentes.
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

85

Fortran 90/95
MODULE vectors
!Purpose:
!To define a derived data type called vector and the
!operations that can be performed on it. The module
!defines eight operations that can be performed on vectors:
!
! 1.Creation from a real array
=
! 2.Conversion to a real array
=
! 3.Vector addition
+
! 4.Vector subtraction
! 5.Vector-scalar multiplication (4 cases)
*
! 6.Vector-scalar division (2 cases)
/
! 7.Dot product
.dot.
! 8.Cross product
*
!
!It contains a total of 12 procedures to implement those
!operations: array_to_vector, vector_to_array, vector_add,
!vector_subtract, vector_times_real, real_times_vector,
!vector_times_int, int_times_vector, vector_div_real,
!vector_div_int, dot _product, and cross _product.
!
implicit none
! declare vector data types:
type :: vector
real :: x
real :: y
real :: z
end type
! declare interface operators:
interface assignment (=)
module procedure array_to_vector
module procedure vector_to_array
end interface
interface operator (+)
module procedure vector_add
end interface
interface operator (-)
module procedure vector_subtract
end interface
interface operator (*)
module procedure vector_times_real
module procedure real_times_vector
module procedure vector_times_int
module procedure int_times_vector
module procedure cross_product
end interface
interface operator (/)
module procedure vector_div_real
module procedure vector_div_int
end interface
interface operator (.dot.)

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

86

Fortran 90/95
module procedure dot_product
end interface
! now define the implementing functions.
contains
subroutine array_to_vector(vec_result, array)
type (vector), intent(out) :: vec_result
real, dimension(3), intent(in) :: array
vec_result.x = array(1)
vec_result.y = array(2)
vec_result.z = array(3)
end subroutine array_to_vector
subroutine vector_to_array(array_result, vec_1)
real, dimension(3), intent(out) :: array_result
type (vector), intent(in) :: vec_1
array_result(1) = vec_1.x
array_result(2) = vec_1.y
array_result(3) = vec_1.z
end subroutine vector_to_array
function vector_add(vec_1, vec_2)
type (vector) :: vector_add
type (vector), intent(in) :: vec_1, vec_2
vector_add.x = vec_1.x + vec_2.x
vector_add.y = vec_1.y + vec_2.y
vector_add.z = vec_1.z + vec_2.z
end function vector_add
function vector_subtract(vec_1, vec_2)
type (vector) :: vector_subtract
type (vector), intent(in) :: vec_1, vec_2
vector_subtract.x = vec_1.x - vec_2.x
vector_subtract.y = vec_1.y - vec_2.y
vector_subtract.z = vec_1.z - vec_2.z
end function vector_subtract
function vector_times_real(vec_1, real_2)
type (vector) :: vector_times_real
type (vector), intent(in) :: vec_1
real, intent(in) :: real_2
vector_times_real.x = vec_1.x * real_2
vector_times_real.y = vec_1.y * real_2
vector_times_real.z = vec_1.z * real_2
end function vector_times_real
function real_times_vector(real_1, vec_2)
type (vector) :: real_times_vector
real, intent(in) :: real_1
type (vector), intent(in) :: vec_2
real_times_vector.x = real_1 * vec_2.x
real_times_vector.y = real_1 * vec_2.y
real_times_vector.z = real_1 * vec_2.z
end function real_times_vector
function vector_times_int(vec_1, int_2)
type (vector) :: vector_times_int
type (vector), intent(in) :: vec_1
integer, intent(in) :: int_2

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

87

Fortran 90/95
vector_times_int.x = vec_1.x * real(int_2)
vector_times_int.y = vec_1.y * real(int_2)
vector_times_int.z = vec_1.z * real(int_2)
end function vector_times_int
function int_times_vector(int_1, vec_2)
type (vector) :: int_times_vector
integer, intent(in) :: int_1
type (vector), intent(in) :: vec_2
int_times_vector.x = real(int_1) * vec_2.x
int_times_vector.y = real(int_1) * vec_2.y
int_times_vector.z = real(int_1) * vec_2.z
end function int_times_vector
function vector_div_real(vec_1, real_2)
type (vector) :: vector_div_real
type (vector), intent(in) :: vec_1
real, intent(in) :: real_2
vector_div_real.x = vec_1.x / real_2
vector_div_real.y = vec_1.y / real_2
vector_div_real.z = vec_1.z / real_2
end function vector_div_real
function vector_div_int (vec_1, int_2)
type (vector) :: vector_div_int
type (vector), intent(in) :: vec_1
integer, intent(in) :: int_2
vector_div_int.x = vec_1.x / real(int_2)
vector_div_int.y = vec_1.y / real(int_2)
vector_div_int.z = vec_1.z / real(int_2)
end function vector_div_int
function dot_product (vec_1, vec_2)
real :: dot_product
type (vector), intent(in) :: vec_1, vec_2
dot_product = vec_1.x*vec_2.x + vec_1.y*vec_2.y &
+ vec_1.z*vec_2.z
end function dot_product
function cross_product (vec_1, vec_2)
type (vector) :: cross_product
type (vector), intent(in) :: vec_1, vec_2
cross_product.x = vec_1.y*vec_2.z - vec_1.z*vec_2.y
cross_product.y = vec_1.z*vec_2.x - vec_1.x*vec_2.z
cross_product.z = vec_1.x*vec_2.y - vec_1.y*vec_2.x
end function cross_product
end module vectors

program test_vectors
!purpose:
!to test the definitions, operations, and assignments
!associated with the vector data type.
!
use vectors
implicit none
! list of variables:

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

88

Fortran 90/95
real, dimension(3) :: array_out
type (vector) :: vec_1, vec_2
! output array
! test vectors
! test assignments by assigning an array to vec_1 and
! assigning vec_1 to array_out.
vec_1 = (/ 1., 2., 3. /)
array_out = vec_1
write (*,*) vec_1, array_out
! test addition and subtraction.
vec_1 = (/10., 20., 30. /)
vec_2 = (/1., 2., 3. /)
write (*,*) vec_1, vec_2, vec_1 + vec_2, vec_1-vec_2
! test multiplication by a scalar.
vec_1 = (/1., 2., 3. /)
write (*,*) vec_1, 2.*vec_1, vec_1*2., 2*vec_1, vec_1*2
! test division by a scalar.
vec_1 = (/10., 20., 30. /)
write (*,*) vec_1, vec_1/5., vec_1/5
! test dot product.
vec_1 = (/ 1., 2., 3. /)
vec_2 = (/1., 2., 3. /)
write (*,*) vec_1, vec_2, vec_1 .dot. vec_2
! test cross product.
vec_1 = (/ 1., -1., 1. /)
vec_2 = (/ -1., 1., 1. /)
write (*,*) vec_1, vec_2, vec_1*vec_2
end program test_vectors

8.8 Restringindo acesso ao contedo de um mdulo


At o momento todos os dados que foram colocados nos mdulos estavam totalmente
disponveis e acessveis. No entanto as vezes no h interesse que determinados dados do
interior de um mdulo esteja disponvel fora do mdulo. Ento a questo : Como esconder
alguns dados do interior de um mdulo? O Fortran apresenta dois atributos para tratar esta
questo, o PUBLIC e o PRIVATE. Se declararmos uma varivel interna de um mdulo de
PRIVATE, ela ficar totalmente indisponvel fora do ambiente do mdulo. Por outro lado ela
continuar totalmente disponvel no interior do mdulo. O atributo PUBLIC o default e torna
uma varivel totalmente disponvel, quer seja internamente ao mdulo quer seja
externamente.
Abaixo tem-se alguns exemplos de como efetuar esta declarao
integer, private :: conta
real, public :: tension
type (caixa), private :: caixa_sapato

aconselhvel esconder qualquer dado ou subprograma de um mdulo que no


precisem ser acessados de fora. A melhor maneira para ser fazer isto incluir o atribute
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

89

Fortran 90/95
em cada mdulo, e listar os itens especficos que se quer deixar visveis em uma
declarao especfica com o atributo PUBLIC.
PRIVATE

8.9 Opes avanadas da declarao USE


Quando um programa acessa um mdulo atravs de uma declarao USE todas as
informaes ali contidas ficam disponveis para o programa que o est acessando, exceto
aquelas protegidas com o atributo PRIVATE. No entanto nem todas as informaes disponveis
sero usadas, assim interessante que se acesse apenas as que forem necessrias. Para
restringir este acesso pode-se adicionar a especificao ONLY declarao USE. A forma de
se fazer
use nome_do_modulo, only : lista_only

onde nome_do_modulo o nome do mdulo e lista_only a lista dos itens do mdulo a serem
usadas. Nesta lista os itens so separados por vrgula.
Tambm possvel renomear dados ou subprogramas de um mdulo quando usando a
declarao USE. Uma das razes para renomear um item a existncia em algum local do
programa de uma outra varivel com o mesmo nome. Fazendo esta renomeao no vai haver
conflito de nomes. Outra razo surge quando um dado que usado com muita freqncia e
tem um nome muito grande, pode-se ento renome-lo com um nome pequeno e economizar
em tempo de digitao.
As formas de usar a declarao USE para permitir ao programador renomear algum
dado ou subprograma so
use nome_do_modulo, lista_para_renomear
use nome_do_modulo, only: lista_para_renomear

onde lista_para_renomear toma a forma


nome_no_modulo => nome_local

Na declarao abaixo
use data_fit, only : sp_real_least_square_fit => lsqfit

utiliza-se um mdulo chamado data_fit. De todos os dados e subprogramas que este mdulo
tem, utiliza-se apenas o chamado sp_real_least_square_fit que est sendo renomeado,
localmente, para lsqfit.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

90

Fortran 90/95

CAPTULO 9
PONTEIROS E ESTRUTURAS DINMICAS DE DADOS
Ponteiros so variveis que no armazenam seu valor prprio, mas armazenam o
endereo de uma outra varivel. Por isto o nome, ponteiro, aquele que aponta para uma outra
varivel. O conceito de ponteiro introduz muita flexibilidade na construo de muitos
algoritmos, mas tambm muita responsabilidade para o programador, uma vez que o mau uso
de ponteiros pode levar a resultados catastrficos.
Um exemplo simblico do poder dos ponteiros : Se voc diz que Jos da Silva mora na
cidade de So Paulo, tm um significado; mas se voc diz Jos da Silva mora em So Paulo,
na Rua Fantasia, 40, Apartamento 105, o significado ser muito mais claro, e a localizao de
Jos da Silva ser muito mais rpida.
Quase todas as variveis dos tipos bsicos do Fortran so estticas. Isto , so criadas
no incio da execuo do programa e permanecem da mesma forma e na mesma posio de
memria at o final da execuo. Isto tambm ocorre com variveis do tipo derivado. As
excees a esta realidade so os arrays alocveis e os arrays automticos (em subprogramas).
Neste captulo apresenta-se uma outra maneira de definir estruturas de dados que podem ser
dinamicamente criadas e podem ter o tamanho varivel ao longo da execuo. Os ponteiros
so fundamentais para viabilizar a existncia de tais estruturas.
Imagine um programa que manipule a base de dados dos CPFs dos brasileiros, alm das
atribuies de verificao de dados, certamente existir a necessidade de introduzir ou retirar
nmeros da base de dados. Considere que vamos aumentar um nmero de CPF na lista, o
array que guarda estas informaes enquanto na memria principal precisar ser
incrementado de uma unidade com o programa j executando e com os dados j existentes j
alocados na memria. Como fazer isto? Veremos neste captulo.
9.1 Ponteiros e alvos
Uma varivel ponteiro (pointer) quando possui o atributo POINTER na sua declarao
de varivel, ou atravs de um declarao POINTER. Adiante apresenta-se alguns exemplos da
sintaxe para definir ponteiros
real, pointer :: p_x

ou
real :: p_x
pointer :: p_x

Como foi dito anteriormente um ponteiro no tm valor prprio mas guarda o endereo
de memria de uma outra varivel. Uma varivel ponteiro dever ter o mesmo tipo declarado
da varivel para qual aponta. De outra forma, um ponteiro s poder apontar para uma
varivel que seja do seu mesmo tipo. Podem existir ponteiros apontando para variveis do tipo
derivado. Ponteiros tambm podem apontar para arrays, neste caso na declarao do ponteiro
estar explicito o rank do array mas no a sua extenso, de qualquer forma o ponteiro aponta
para o primeiro elemento do array. Algumas maneiras de definir ponteiros para arrays so
integer, dimension(:), pointer :: p_y
real, pointer, dimension(:,:) :: p_w
pointer, real, dimension(:,:,:) :: p_z

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

91

Fortran 90/95
Os ponteiros acima apontam para arrays rank 1, rank 2 e rank 3, respectivamente.
Para que seja possvel que um ponteiro aponte para uma varivel necessrio que a
mesma seja um alvo. Em outras palavras, um alvo uma varivel que foi disponibilizada para
o uso com ponteiros. Para uma varivel tornar-se um alvo necessrio que a mesma tenha o
atributo TARGET ou atravs de uma declarao TARGET. A seguir alguns exemplos de
declarao de variveis como alvo
real, target :: x
integer, dimension(5), target :: y
real, target, dimension(5,10) :: w

9.1.1 Declarao de atribuio de ponteiro


Um ponteiro pode ser associado a uma varivel alvo atravs de uma declarao de
atribuio de ponteiro. Esta declarao tem o seguinte formato
ponteiro => alvo

onde ponteiro o nome da varivel ponteiro que ir conter o endereo do alvo, e alvo a
varivel apontada pelo ponteiro.
Depois que um ponteiro foi associado a uma varivel alvo, qualquer referncia ao
ponteiro em realidade uma referncia varivel alvo. Se um ponteiro est associado a uma
varivel alvo e ento novamente associado a uma segunda varivel alvo, a primeira
associao ser desfeita. Em outras palavras um ponteiro no pode apontar para dois alvos
simultaneamente, no entanto um alvo pode ser apontado por um, dois ou mais ponteiros.
Quando um alvo est sendo apontado por dois ponteiros e um dos ponteiros movido, o outro
ponteiro no ser modificado. Um valor que est armazenado em uma varivel alvo pode ser
obtido referenciado a varivel alvo ou ento referenciado o ponteiro que est apontado para
ela. Um ponteiro pode apontar para outro ponteiro, neste caso em realidade os dois ponteiros
estaro apontando para o mesmo alvo.
Uma boa conduta na definio de variveis do tipo ponteiro colocar um p no incio do
nome da varivel para se ter uma distino clara quando se l um programa de quais variveis
so ponteiros e quais no so.
9.1.1 Situao de um associao ponteiro-alvo
A situao da associao de um ponteiro e de um alvo indica se um dado ponteiro est
associado a um dado alvo. possvel trs situaes: associado (associated), indefinido
(undefined) e desassociado (disassociated). Quando um ponteiro criado em uma declarao
de tipo sua situao indefinido, quando associado a um alvo a situao ento associado, e
quando desassociado do alvo sua situao torna-se desassociado. J vimos como declarar um
ponteiro e como associar um ponteiro a um alvo, resta vermos como desassociar um ponteiro
de seu alvo. Para tal necessrio apenas executar uma declarao NULLIFY com o seguinte
formato
nullify(lista_de_ponteiros)

onde nullify ir desassociar todos os ponteiros lista na lista_de_ponteiros de todos os seus


respectivos alvos. A situao de todos os ponteiros da lista passar ento para desassociados.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

92

Fortran 90/95
Um ponteiro ter sua situao indefinida desde quando definido at o ponto que sofre
uma atribuio. Como a situao indefinida ambgua importante que todos os ponteiros
sejam nulificados usando nullify logo aps sua definio. A partir de ento a situao daquele
ponteiro ser associado ou desassociado.
Um ponteiro s pode referenciar uma varivel se estiver a ela associado. Para descobrir
se um dado ponteiro est associado, ou desassociado de um dado alvo basta usar a funo
lgica ASSOCIATED, a qual retornar um valor TRUE se estiver associado e um valor FALSE
se no estiver associado. Esta funo apresenta a caracterstica de suportar quantidade
varivel de argumentos, podendo ter um ou dois argumentos. No caso de possuir apenas um
argumento, sua forma geral de uso
variavel_logica = associated(ponteiro)

que responder se ponteiro j est associado ou no. A segunda forma de uso desta funo
com dois argumentos
variavel_logica = associated(ponteiro, alvo)

a qual retornar a situao da associao de ponteiro e alvo.


9.2 Usando ponteiros em declaraes de atribuio
Quando um ponteiro aparece em uma expresso aritmtica, no lugar de um valor
numrico ento o valor da varivel para a qual ele est apontando usado.
Quando se escreve
p_x = p_y

o valor que est na varivel alvo apontada por p_y atribuda posio de memria da
varivel alvo apontada por p_x. Adicionalmente, se escrevemos
p_x => p_y

significa que estamos apontando o ponteiro p_x para o ponteiro p_y, assim p_x ficar
apontando para a mesma posio de memria que p_y, ou seja a varivel alvo de p_y.
Abaixo apresenta-se um programa que utiliza ponteiros para trocar a posio de duas
matrizes
program usando_pointer
!Objetivo: Mostrar o uso de ponteiros
!
!programador: joo batista aparecido ilha solteira, 16 de dezembro, 1999
!programador: joo batista aparecido ilha solteira, 02 de agosto, 2001
!
implicit none
integer, parameter :: i_max = 100, j_max = 100
integer :: i, j
real :: aux
real, target, dimension(i_max, i_max) :: x, y
!Definindo os alvos
real, pointer, dimension(:,:) :: p_x, p_y, p_aux !Definindo os ponteiros
nullify(p_x, p_y, p_aux) !Nulificando os ponteiros
p_x => x
!Atribuindo o ponteiro p_x

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

93

Fortran 90/95
p_y => y
x = 1.0
y = 5.0

!Atribuindo o ponteiro p_y


!Inicializando a matriz, x
!Inicializando a matriz, y

!Fazendo o swap das matrizes da forma clssica


do i = 1, i_max
do j = 1, j_max
aux = x(i, j)
x(i,j) = y(i, j)
y(i,j) = aux
end do
end do
x = 2.0
y = 6.0

!Redefinindo a matriz, x
!Redefinindo a matriz, y

write(*,*) p_x(i_max/2, j_max/2)


!Fazendo o swap das matrizes usando ponteiros
p_aux => p_x
p_x => p_y
p_y => p_aux
write(*,*) p_x(i_max/2, j_max/2)
stop
end program usando_pointer

9.3 Alocao dinmica de memria usando ponteiros


Um dos aspectos mais poderosos do uso de ponteiros em alocao dinmica que ele
permite no s a criao de espaos na memria como tambm depois de criados aumentar ou
diminuir estes espaos sem destruir os dados j armazenados.
A maneira de se fazer isto parecida com aquela j vista usando arrays alocveis.
Espaos em memria so alocados usando a declarao ALLOCATE, e desalocados usando
DEALLOCATE. Neste caso a declarao ALLOCATE fica da seguinte forma
allocate(ponteiro_1(forma_do_ponteiro_1),,stat = status)

onde ponteiro_1 o nome do primeiro ponteiro a ser alocado, e assim por diante,
forma_do_ponteiro_1 a respectiva forma de ponteiro_1, ou seja o rank e a extenso em cada
direo que possui a estrutura para a qual o ponteiro vai apontar, e status o resultado para
operao. Se a alocao for bem sucedida seu valor zero, caso contrrio seu valor ser
dependente da implementao de cada compilador, sendo necessrio consultar o manual do
fabricante.
A operao descrita acima criar um ponteiro que apontar para um conjunto de dados
sem nome. Devido ao fato deste objeto no ter nome ele poder ser acessado apenas via
ponteiro. Depois que a rotina acima executada com sucesso a situao do ponteiro ser
associado. Se o ponteiro (ou ponteiros), que est associado a este objeto sem nome, for
nulificado ou redirecionado para outro objeto, aquele objeto estar perdido para sempre.
Porm ainda ocupando as posies de memria, criando o chamado vazamento de memria.
Por isto importante que a memria que foi alocada usando ALLOCATE seja desalocada
usando DEALLOCATE, da seguinte maneira

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

94

Fortran 90/95
deallocate(ponteiro, stat = status)

Quando um espao de memria desalocado usando DEALLOCATE, automaticamente o


ponteiro que apontava para aquele objeto nulificado.
Logo abaixo apresenta-se a verso semelhante ao programa anterior, agora usando
alocao dinmica de memria
program usando_pointer
!Objetivo: Mostrar alocao dinmica usando ponteiros
!
!programador: joo batista aparecido ilha solteira, 16 de dezembro, 1999
!
implicit none
integer, parameter :: i_max = 100, j_max =100
integer :: status
real, pointer, dimension(:,:) :: p_x, p_y, p_aux !Definindo os ponteiros
nullify(p_x,p_y,p_aux) !Nulificando os ponteiros
allocate(p_x(i_max,j_max), p_y(i_max,j_max), stat = status) !Alocando memria
p_x = 1.0
p_y = 5.0

!Inicializando o array para onde aponta p_x


!Inicializando o array para onde aponta p_y

!Fazendo o swap das matrizes usando ponteiros


p_aux => p_x
p_x => p_y
p_y => p_aux
write(*,*) p_x(i_max/2, j_max/2)
deallocate(p_x, stat=status) !Desalocando memria
deallocate(p_y, stat=status) !Desalocando memria
deallocate(p_aux, stat=status) !Desalocando memria
stop
end program usando_pointer

9.4 Usando ponteiros com estruturas derivadas de dados


Pode-se colocar ponteiros dentro de estruturas derivadas de dados, e que apontem para
outras estruturas do mesmo tipo. Assim seja a seguinte estrutura derivada de dados
type :: real_value
real :: value
type(real_value), pointer :: p
end type

Esta estrutura de dados acima toda vez que definida (instanciada) armazena um valor
real, e um ponteiro que aponta para outra estrutura do mesmo tipo, e assim por diante. Estes
elementos podem ser alocados dinamicamente e esta pilha pode ir crescendo o quanto se
desejar. Para parar o processo basta nulificar a ponta do ultimo ponteiro, e para regredir o
processo basta ir nulificando os ponteiros que foram abertos, dos ltimos para os primeiros,
at o primeiro. Desta forma cria-se uma estrutura capaz de armazenar reais seqencialmente,
como se fosse um array, mas cujo tamanho pode crescer ou decrescer continuamente em
tempo de execuo. Pode-se inclusive inserir estruturas no meio da seqncia sem a
Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

95

Fortran 90/95
necessidade de mover dados de suas posies de memria, basta apontar o ponteiro da
estrutura anterior para a nova estrutura e o ponteiro da nova estrutura para a estrutura
subsequente. Esta estrutura clssica em computao e conhecida como lista lincada.
Existem outras, igualmente conhecidas, tal como rvore binria.
Abaixo apresenta-se um exemplo de utilizao deste tipo de dado onde um arquivo com
nmeros reais, de tamanho desconhecido, lido, seqencialmente, at o final. O programa
capaz de dinamicamente ir aumentando o tamanho da estrutura geral de dados para abrigar
novas informaes.
program linked_list
!
!
!
!
!
!
!
!
!

purpose:
to read in a series of real values from an input data file
and store them in a linked list. after the list is read in,
it will be written back to the standard output device.
record of revisions:
date programmer
==== ==========
01/28/95 s. j. chapman

! description of change
! =====================
! original code
implicit none
! derived data type to store real values in
type :: real_value
real :: value
type (real_value), pointer :: p
end type
! list of variables:
type (real_value), pointer :: head
character(len = 20) :: filename
integer :: nvals = 0
type (real_value), pointer :: ptr
type (real_value), pointer :: tail
integer :: istat
real :: temp, aux

!
!
!
!
!
!
!

pointer to head of list


input data file name
number of data read
temporary pointer
pointer to tail of list
status: 0 for success
temporary variable

! get the name of the file containing the input data.


write (*,*) 'enter the file name with the data to be read: '
read (*,'(a20)') filename
! open input data file.
open ( unit = 9, file = filename, status = 'old', action = 'read', iostat = istat )
! was the open successful?
fileopen: if ( istat == 0 ) then
! open successful
! the file was opened successfully, so read the data from
! it, and store it in the linked list.
input: do

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

96

Fortran 90/95
read (9, *, iostat = istat) temp ! get value
if ( istat /= 0 ) exit
! exit on end of data
nvals = nvals + 1
! bump count
if (.not. associated(head)) then
allocate (head, stat = istat)
tail => head
nullify (tail.p)
tail.value = temp
else
allocate (tail.p, stat = istat)
tail => tail.p
nullify (tail.p)
tail.value = temp
end if
end do input
! now, write out the data.
ptr => head
output: do
if (.not.associated(ptr)) exit
write (*,*) ptr.value
ptr => ptr.p
end do output

! no values in list
! allocate new value
! tail pts to new value
! nullify p in new value
! store number
! values already in list
! allocate new value
! tail pts to new value
! nullify p in new value
! store number

! pointer valid?
! yes: write value
! get next pointer

else fileopen
! else file open failed. tell user.
write (*,*) 'file open failed--status = ', istat
end if fileopen
end program

A seguir um exemplo de arquivo de dados para se testar o programa acima


1.0
-2.0
3.0
-4.0
5.0
-6.0
7.0
-8.0
9.0
-10.000

A estrutura derivada de dados utilizada acima pode ser estendida para conter no seu
interior vrios valores reais, inteiros, lgicos, caracteres, complexos, assim uma extenso
nesta direo seria, por exemplo, o que segue
type :: various_values
complex :: c1
integer :: int1, int2
real :: value1, value2, value3
character(20) :: nome1, nome2
logical :: logic1, logic2, logic3
type(various_values), pointer :: p
end type

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

97

Fortran 90/95
Um outro tipo de extenso, na estrutura de dados acima, incorporar mais de um
ponteiro. Um exemplo bem conhecido na literatura a arvore binria que acrescenta mais um
ponteiro ao tipo derivado de dados. Assim cada elemento na estrutura global estar apontando
para nenhum, um ou dois outros elementos, formando assim uma arvore binria. Uma
estrutura razoavelmente genrica de uma rvore binria seria
type :: various_values_and_two_pointers
complex :: c1
integer :: int1, int2
real :: value1, value2, value3
character(20) :: nome1, nome2
logical :: logic1, logic2, logic3
type(various_values_and_two_pointers), pointer :: p1, p2
end type

Imagine-se uma arvore binria para armazenar e disponibilizar os primeiro, segundo e


terceiro nomes de uma pessoa bem como o seu respectivo telefone. A seguir o programa que
usa esta estrutura de dados
module btree
!
! purpose:
! to define the derived data type used as a node in the
! binary tree, and to define the operations >, <. and ==
! for this data type. this module also contains the
! subroutines to add a node to the tree, write out the
! values in the tree, and find a value in the tree.
!
! record of revisions:
!
date
programmer
description of change
!
====
==========
=====================
! 02/04/96 s. j. chapman
original code
!
implicit none
! restrict access to module contents.
private
public :: node, operator(>), operator(<), operator(==)
public :: add_node, write_node, find_node
! declare type for a node of the binary tree.
type :: node
character(len = 10) :: last
character(len = 10) :: first
character :: mi
character(len = 16) :: phone
type (node), pointer :: before
type (node), pointer :: after
end type
interface operator (>)
module procedure greater_than
end interface
interface operator (<)
module procedure less_than
end interface

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

98

Fortran 90/95
interface operator (==)
module procedure equal_to
end interface
contains
recursive subroutine add_node (ptr, new_node)
!
! purpose:
! to add a new node to the binary tree structure.
!
type (node), pointer :: ptr ! pointer to current pos. in tree
type (node), pointer :: new_node ! pointer to new node
if ( .not. associated(ptr) ) then
! there is no tree yet. add the node right here.
ptr => new_node
else if ( new_node < ptr ) then
if ( associated(ptr.before) ) then
call add_node ( ptr.before, new_node )
else
ptr.before => new_node
end if
else
if ( associated(ptr.after) ) then
call add_node ( ptr.after, new_node )
else
ptr.after => new_node
end if
end if
end subroutine add_node
recursive subroutine write_node (ptr)
!
! purpose:
! to write out the contents of the binary tree
! structure in order.
!
type (node), pointer :: ptr ! pointer to current pos. in tree
! write contents of previous node.
if ( associated(ptr.before) ) then
call write_node ( ptr.before )
end if
! write contents of current node.
write (*,"(1x,a,', ',a,1x,a)") ptr.last, ptr.first, ptr.mi
! write contents of next node.
if ( associated(ptr.after) ) then
call write_node ( ptr.after )
end if
end subroutine write_node
recursive subroutine find_node (ptr, search, error)
!
! purpose:
! to find a particular node in the binary tree structure.
! "search" is a pointer to the name to find, and will
! also contain the results when the subroutine finishes

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

99

Fortran 90/95
! if the node is found.
!
type (node), pointer :: ptr ! pointer to curr pos. in tree
type (node), pointer :: search ! pointer to value to find.
integer :: error
! error: 0 = ok, 1 = not found
if ( search < ptr ) then
if ( associated(ptr.before) ) then
call find_node (ptr.before, search, error)
else
error = 1
end if
else if ( search == ptr ) then
search = ptr
error = 0
else
if ( associated(ptr.after) ) then
call find_node (ptr.after, search, error)
else
error = 1
end if
end if
end subroutine find_node
logical function greater_than (op1, op2)
!
! purpose:
! to test to see if operand 1 is > operand 2
! in alphabetical order.
!
type (node), intent(in) :: op1, op2
character(len=10) :: last1, last2, first1, first2
character :: mi1, mi2
call ushift (op1, last1, first1, mi1 )
call ushift (op2, last2, first2, mi2 )
if (last1 > last2) then
greater_than = .true.
else if (last1 < last2) then
greater_than = .false.
else ! last names match
if (first1 > first2) then
greater_than = .true.
else if (first1 < first2) then
greater_than = .false.
else ! first names match
if (mi1 > mi2) then
greater_than = .true.
else
greater_than = .false.
end if
end if
end if
end function greater_than
logical function less_than (op1, op2)
!
! purpose:
! to test to see if operand 1 is < operand 2

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

100

Fortran 90/95
! in alphabetical order.
!
type (node), intent(in) :: op1, op2
character(len=10) :: last1, last2, first1, first2
character :: mi1, mi2
call ushift (op1, last1, first1, mi1 )
call ushift (op2, last2, first2, mi2 )
if (last1 < last2) then
less_than = .true.
else if (last1 > last2) then
less_than = .false.
else ! last names match
if (first1 < first2) then
less_than = .true.
else if (first1 > first2) then
less_than = .false.
else ! first names match
if (mi1 < mi2) then
less_than = .true.
else
less_than = .false.
end if
end if
end if
end function less_than
logical function equal_to (op1, op2)
!
! purpose:
! to test to see if operand 1 is equal to operand 2
! alphabetically.
!
type (node), intent(in) :: op1, op2
character(len=10) :: last1, last2, first1, first2
character :: mi1, mi2
call ushift (op1, last1, first1, mi1 )
call ushift (op2, last2, first2, mi2 )
if ( (last1 == last2) .and. (first1 == first2) .and. &
(mi1 == mi2 ) ) then
equal_to = .true.
else
equal_to = .false.
end if
end function equal_to
subroutine ushift( op, last, first, mi )
!
! purpose:
! to create upshifted versions of all strings for
! comparison.
!
type (node), intent(in) :: op
character(len=10), intent(inout) :: last, first
character, intent(inout) :: mi

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

101

Fortran 90/95
last = op.last
first = op.first
mi = op.mi
call ucase (last)
call ucase (first)
call ucase (mi)
end subroutine ushift
subroutine ucase ( string )
!
! purpose:
! to shift a character string to upper case.
!
! record of revisions:
!
date
programmer
description of change
!
====
==========
=====================
! 11/25/95 s. j. chapman
original code
! 1. 11/25/95 s. j. chapman
modified for any collating seq
!
implicit none
! declare calling parameters:
character(len=*), intent(inout) :: string
! declare local variables:
integer :: i
! loop index
integer :: length
! length of input string
! get length of string
length = len ( string )
! now shift lower case letters to upper case.
do i = 1, length
if ( ( string(i:i) >= 'a' ) .and. &
( string(i:i) <= 'z' ) ) then
string(i:i) = achar ( iachar ( string(i:i) ) - 32 )
end if
end do
end subroutine ucase
end module btree
program binary_tree
!
! purpose:
! to read in a series of random names and phone numbers
! and store them in a binary tree. after the values are
! stored, they are written out in sorted order. then the
! user is prompted for a name to retrieve, and the program
! recovers the data associated with that name.
!
! record of revisions:
!
date
programmer
description of change
!
====
==========
=====================
! 02/06/95 s. j. chapman
original code
!
use btree
implicit none

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

102

Fortran 90/95
! list of variables:
integer :: error
! error flag: 0=success
character(len=20) :: filename
! input data file name
integer :: istat
! status: 0 for success
type (node), pointer :: root
! pointer to root node
type (node), pointer :: temp
! temp pointer to node
! nullify new pointers
nullify ( root, temp )
! get the name of the file containing the input data.
write (*,*) 'enter the file name with the input data: '
read (*,'(a20)') filename
! open input data file. status is old because the input data must
! already exist.
open ( unit=9, file=filename, status='old', action='read', &
iostat=istat )
! was the open successful?
fileopen: if ( istat == 0 ) then

! open successful

! the file was opened successfully, allocate space for each


! node, read the data into that node, and insert it into the
! binary tree.
input: do
allocate (temp,stat=istat)
! allocate node
nullify ( temp.before, temp.after) ! nullify pointers
read (9, 100, iostat=istat) temp.last, temp.first, &
temp.mi, temp.phone
! read data
100 format (a10,1x,a10,1x,a1,1x,a16)
if ( istat /= 0 ) exit input
! exit on end of data
call add_node(root, temp)
! add to binary tree
end do input
! now, write out the sorted data.
write (*,'(/,1x,a)') 'the sorted data list is: '
call write_node(root)
! prompt for a name to search for in the tree.
write (*,'(/,1x,a)') 'enter name to recover from tree:'
write (*,'(1x,a)',advance='no') 'last name:
'
read (*,'(a)') temp.last
write (*,'(1x,a)',advance='no') 'first name: '
read (*,'(a)') temp.first
write (*,'(1x,a)',advance='no') 'middle initial: '
read (*,'(a)') temp.mi
! locate record
call find_node ( root, temp, error )
check: if ( error == 0 ) then
write (*,'(/,1x,a)') 'the record is:'
write (*,'(1x,7a)') temp.last, ', ', temp.first, ' ', &
temp.mi, ' ', temp.phone
else
write (*,'(/,1x,a)') 'specified node not found!'
end if check
else fileopen

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

103

Fortran 90/95
! else file open failed. tell user.
write (*,'(1x,a,i6)') 'file open failed--status = ', istat
end if fileopen
end program

A seguir um arquivo de dados para se testar este programa


Carneiro
Silva
Forte
Ricieri
Alves
Honda
Park
Smith
Chung
Ling

Paulo
Joo
Ronaldo
Maria
Paula
Eiko
Sum
John
Chang
Ding

S
M
P
R
B
H
L
W
S
P

(602)
(309)
(987)
(276)
(145)
(849)
(743)
(478)
(586)
(667)

534-2398
234-8534
854-4590
794-8520
639-7856
466-8866
136-3484
375-3678
975-8766
889-6544

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

104

Fortran 90/95

CAPTULO 10
BIBLIOTECAS DE SUBROTINAS E FUNES
Desde a mais remota antigidade o ser humano tem tentado formas de perenizar a
informao. As civilizaes que no conseguiram perenizar a informao e j desapareceram,
hoje so totalmente desconhecidas porque no deixaram qualquer registro. Uma das formas
mais antigas de preservar a informao foi atravs das colees de livros, as bibliotecas. Com
o passar do tempo, surgiram vrios tipos de colees que receberam nomes especficos,
conforme os casos. Naturalmente, isto tambm ocorrem com programas computacionais. Com
o desenvolvimento de algoritmos eficientes e robustos para o mais variados tipos de tarefas,
tornou-se possvel colecionar conjuntos de subprogramas, subrotinas ou funes, as
bibliotecas computacionais. O termo parecer um tanto inapropriado, uma vez que os objetos
da coleo no so livros nem so objetos reais. De qualquer forma trata-se de objetos virtuais
que fazer uso de uma linguagem escrita, e portanto tem uma certa semelhana com livros. De
qualquer forma so conhecidas como bibliotecas. Existem as mais variadas, para as mais
diferentes tarefas: bibliotecas de clculo diferencial e integral, bibliotecas estatsticas,
bibliotecas grficas, e assim por diante.
O Fortran90/95, prov meios para se criar e/ou utilizar bibliotecas computacionais.
Neste captulo, apresenta-se algumas maneiras de explorar o conceito de bibliotecas ou
colees de programas, previamente estabelecidos.
Vamos imaginar uma biblioteca de programas para realizar as operaes bsicas (+,,*,/) da aritmtica sobre os tipos de dados bsicos. Obviamente, este problema trivial mas
servir perfeitamente da demonstrar os conceitos envolvidos.
10.1 Bibliotecas de programas fonte
Pode-se desenvolver uma coleo de cdigo-fonte, que seja confivel, precisa e
eficiente, e que possa ser usada repetidas vezes, sem a necessidade de se reprogramar os
mesmos algoritmos repetidas vezes.
Seja abaixo uma coleo de rotinas para cumprir o objetivo enunciado acima.
Rotinas para efetuar soma
! Function que soma inteiros de 1 byte
function soma_int1(a, b)
implicit none
integer(1), intent(in) :: a, b
integer(1)
:: soma_int1
soma_int1 = a + b
end function soma_int1
! Function que soma inteiros de 2 bytes
function soma_int2(a, b)
implicit none
integer(2), intent(in) :: a, b
integer(2)
:: soma_int2

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

105

Fortran 90/95
soma_int2 = a + b
end function soma_int2
! Function que soma inteiros de 4 bytes
function soma_int4(a, b)
implicit none
integer(4), intent(in) :: a, b
integer(4)
:: soma_int4
soma_int4 = a + b
end function soma_int4
! Function que soma reais de 4 bytes
function soma_real4(a, b)
implicit none
real(4), intent(in) :: a, b
real(4)
:: soma_real4
soma_real4 = a + b
end function soma_real4
! Function que soma reais de 8 bytes
function soma_real8(a, b)
implicit none
real(8), intent(in) :: a, b
real(8)
:: soma_real8
soma_real8 = a + b
end function soma_real8
! Function que soma complexos de 4 bytes
function soma_complex4(a, b)
implicit none
complex(4), intent(in) :: a, b
complex(4)
:: soma_complex4
soma_complex4 = a + b
end function soma_complex4
! Function que soma complexos de 8 bytes
function soma_complex8(a, b)
implicit none
complex(8), intent(in) :: a, b
complex(8)
:: soma_complex8
soma_complex8 = a + b
end function soma_complex8
! Function que soma lgicos

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

106

Fortran 90/95
function soma_logical(a, b)
implicit none
logical, intent(in) :: a, b
logical
:: soma_logical
soma_logical = a + b
end function soma_logical

Rotinas para efetuar subtrao


! Function que subtrai inteiros de 1 byte
function subtrai_int1(a, b)
implicit none
integer(1), intent(in) :: a, b
integer(1)
:: subtrai_int1
subtrai_int1 = a - b
end function subtrai_int1
! Function que subtrai inteiros de 2 bytes
function subtrai_int2(a, b)
implicit none
integer(2), intent(in) :: a, b
integer(2)
:: subtrai_int2
subtrai_int2 = a - b
end function subtrai_int2
! Function que subtrai inteiros de 4 bytes
function subtrai_int4(a, b)
implicit none
integer(4), intent(in) :: a, b
integer(4)
:: subtrai_int4
subtrai_int4 = a - b
end function subtrai_int4
! Function que subtrai reais de 4 bytes
function subtrai_real4(a, b)
implicit none
real(4), intent(in) :: a, b
real(4)
:: subtrai_real4
subtrai_real4 = a - b
end function subtrai_real4
! Function que subtrai reais de 8 bytes
function subtrai_real8(a, b)
implicit none

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

107

Fortran 90/95
real(8), intent(in) :: a, b
real(8)
:: subtrai_real8
subtrai_real8 = a - b
end function subtrai_real8
! Function que subtrai complexos de 4 bytes
function subtrai_complex4(a, b)
implicit none
complex(4), intent(in) :: a, b
complex(4)
:: subtrai_complex4
subtrai_complex4 = a - b
end function subtrai_complex4
! Function que subtrai complexos de 8 bytes
function subtrai_complex8(a, b)
implicit none
complex(8), intent(in) :: a, b
complex(8)
:: subtrai_complex8
subtrai_complex8 = a - b
end function subtrai_complex8
! Function que subtrai lgicos
function subtrai_logical(a, b)
implicit none
logical, intent(in) :: a, b
logical
:: subtrai_logical
subtrai_logical = a - b
end function subtrai_logical

Rotinas para efetuar multiplicao


! Function que multiplica inteiros de 1 byte
function multiplica_int1(a, b)
implicit none
integer(1), intent(in) :: a, b
integer(1)
:: multiplica_int1
multiplica_int1 = a * b
end function multiplica_int1
! Function que multiplica inteiros de 2 bytes
function multiplica_int2(a, b)
implicit none
integer(2), intent(in) :: a, b
integer(2)
:: multiplica_int2

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

108

Fortran 90/95
multiplica_int2 = a * b
end function multiplica_int2
! Function que multiplica inteiros de 4 bytes
function multiplica_int4(a, b)
implicit none
integer(4), intent(in) :: a, b
integer(4)
:: multiplica_int4
multiplica_int4 = a * b
end function multiplica_int4
! Function que multiplica reais de 4 bytes
function multiplica_real4(a, b)
implicit none
real(4), intent(in) :: a, b
real(4)
:: multiplica_real4
multiplica_real4 = a * b
end function multiplica_real4
! Function que multiplica reais de 8 bytes
function multiplica_real8(a, b)
implicit none
real(8), intent(in) :: a, b
real(8)
:: multiplica_real8
multiplica_real8 = a * b
end function multiplica_real8
! Function que multiplica complexos de 4 bytes
function multiplica_complex4(a, b)
implicit none
complex(4), intent(in) :: a, b
complex(4)
:: multiplica_complex4
multiplica_complex4 = a * b
end function multiplica_complex4
! Function que multiplica complexos de 8 bytes
function multiplica_complex8(a, b)
implicit none
complex(8), intent(in) :: a, b
complex(8)
:: multiplica_complex8
multiplica_complex8 = a * b
end function multiplica_complex8
! Function que multiplica lgicos

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

109

Fortran 90/95
function multiplica_logical(a, b)
implicit none
logical, intent(in) :: a, b
logical
:: multiplica_logical
multiplica_logical = a * b
end function multiplica_logical

Rotinas para efetuar diviso


! Function que divide inteiros de 1 byte
function divide_int1(a, b)
implicit none
integer(1), intent(in) :: a, b
integer(1)
:: divide_int1
if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_int1 = a / b
end function divide_int1
! Function que divide inteiros de 2 bytes
function divide_int2(a, b)
implicit none
integer(2), intent(in) :: a, b
integer(2)
:: divide_int2
if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_int2 = a / b
end function divide_int2
! Function que divide inteiros de 4 bytes
function divide_int4(a, b)
implicit none
integer(4), intent(in) :: a, b
integer(4)
:: divide_int4

if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_int4 = a / b
end function divide_int4

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

110

Fortran 90/95
! Function que divide reais de 4 bytes
function divide_real4(a, b)
implicit none
real(4), intent(in) :: a, b
real(4)
:: divide_real4

if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_real4 = a / b
end function divide_real4
! Function que divide reais de 8 bytes
function divide_real8(a, b)
implicit none
real(8), intent(in) :: a, b
real(8)
:: divide_real8

if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_real8 = a / b
end function divide_real8
! Function que divide complexos de 4 bytes
function divide_complex4(a, b)
implicit none
complex(4), intent(in) :: a, b
complex(4)
:: divide_complex4

if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_complex4 = a / b
end function divide_complex4
! Function que divide complexos de 8 bytes
function divide_complex8(a, b)
implicit none
complex(8), intent(in) :: a, b
complex(8)
:: divide_complex8

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

111

Fortran 90/95
if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_complex8 = a / b
end function divide_complex8
! Function que divide lgicos
function divide_logical(a, b)
implicit none
logical, intent(in) :: a, b
logical
:: divide_logical
divide_logical = a / b
end function divide_logical

Este um conjunto de functions para realizar operaes aritmticas bsicas sobre tipos
bsicos de dados. Para UDTs procede-se da mesma maneira. Evidentemente, o conceito de
operaes para uma UDT abstrata ser tambm abstrato.
De posse de uma biblioteca de cdigos fonte, basta construir um programa que possa
us-las adequadamente. Estas rotinas podem ser usadas diretamente, sendo invocadas por seus
nomes ou pode-se criar uma interface explicita para melhor informar ao compilador sobre a
biblioteca. Tambm pode-se construir uma interface genrica que tenha funcionalidade
genrica, conforme explicado em captulos anteriores.
Para utilizar a biblioteca de fontes de uma maneira segura vou prover no programa
principal uma interface explicita. Tambm vou dotar esta interface de funcionalidade
genrica, de tal forma a esconder do usurio alguns detalhes internos.
Segue abaixo um programa teste para fazer da biblioteca.
program lib_demo_sources
implicit none
!***** Interface genrica para soma *****
interface soma
! Function que soma inteiros de 1 byte
function soma_int1(a, b)
implicit none
integer(1), intent(in) :: a, b
integer(1)
:: soma_int1
end function soma_int1
! Function que soma inteiros de 2 bytes
function soma_int2(a, b)
implicit none
integer(2), intent(in) :: a, b
integer(2)
:: soma_int2
end function soma_int2
! Function que soma inteiros de 4 bytes
function soma_int4(a, b)
implicit none

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

112

Fortran 90/95
integer(4), intent(in) :: a, b
integer(4)
:: soma_int4
end function soma_int4
! Function que soma reais de 4 bytes
function soma_real4(a, b)
implicit none
real(4), intent(in) :: a, b
real(4)
:: soma_real4
end function soma_real4
! Function que soma reais de 8 bytes
function soma_real8(a, b)
implicit none
real(8), intent(in) :: a, b
real(8)
:: soma_real8
end function soma_real8
! Function que soma complexos de 4 bytes
function soma_complex4(a, b)
implicit none
complex(4), intent(in) :: a, b
complex(4)
:: soma_complex4
end function soma_complex4
! Function que soma complexos de 8 bytes
function soma_complex8(a, b)
implicit none
complex(8), intent(in) :: a, b
complex(8)
:: soma_complex8
end function soma_complex8
! Function que soma lgicos
function soma_logical(a, b)
implicit none
logical, intent(in) :: a, b
logical
:: soma_logical
end function soma_logical
end interface

!soma

!***** Interface genrica para subtrao *****


interface subtrai
! Function que subtrai inteiros de 1 byte
function subtrai_int1(a, b)
implicit none
integer(1), intent(in) :: a, b
integer(1)
:: subtrai_int1
end function subtrai_int1
! Function que subtrai inteiros de 2 bytes
function subtrai_int2(a, b)
implicit none
integer(2), intent(in) :: a, b
integer(2)
:: subtrai_int2
end function subtrai_int2
! Function que subtrai inteiros de 4 bytes
function subtrai_int4(a, b)

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

113

Fortran 90/95
implicit none
integer(4), intent(in) :: a, b
integer(4)
:: subtrai_int4
end function subtrai_int4
! Function que subtrai reais de 4 bytes
function subtrai_real4(a, b)
implicit none
real(4), intent(in) :: a, b
real(4)
:: subtrai_real4
end function subtrai_real4
! Function que subtrai reais de 8 bytes
function subtrai_real8(a, b)
implicit none
real(8), intent(in) :: a, b
real(8)
:: subtrai_real8
end function subtrai_real8
! Function que subtrai complexos de 4 bytes
function subtrai_complex4(a, b)
implicit none
complex(4), intent(in) :: a, b
complex(4)
:: subtrai_complex4
end function subtrai_complex4
! Function que subtrai complexos de 8 bytes
function subtrai_complex8(a, b)
implicit none
complex(8), intent(in) :: a, b
complex(8)
:: subtrai_complex8
end function subtrai_complex8
! Function que subtrai lgicos
function subtrai_logical(a, b)
implicit none
logical, intent(in) :: a, b
logical
:: subtrai_logical
end function subtrai_logical
end interface
!***** Interface genrica para multiplicao *****
interface multiplica
! Function que multiplica inteiros de 1 byte
function multiplica_int1(a, b)
implicit none
integer(1), intent(in) :: a, b
integer(1)
:: multiplica_int1
end function multiplica_int1
! Function que multiplica inteiros de 2 bytes
function multiplica_int2(a, b)
implicit none
integer(2), intent(in) :: a, b
integer(2)
:: multiplica_int2
end function multiplica_int2
! Function que multiplica inteiros de 4 bytes

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

114

Fortran 90/95
function multiplica_int4(a, b)
implicit none
integer(4), intent(in) :: a, b
integer(4)
:: multiplica_int4
end function multiplica_int4
! Function que multiplica reais de 4 bytes
function multiplica_real4(a, b)
implicit none
real(4), intent(in) :: a, b
real(4)
:: multiplica_real4
end function multiplica_real4
! Function que multiplica reais de 8 bytes
function multiplica_real8(a, b)
implicit none
real(8), intent(in) :: a, b
real(8)
:: multiplica_real8
end function multiplica_real8
! Function que multiplica complexos de 4 bytes
function multiplica_complex4(a, b)
implicit none
complex(4), intent(in) :: a, b
complex(4)
:: multiplica_complex4
end function multiplica_complex4
! Function que multiplica complexos de 8 bytes
function multiplica_complex8(a, b)
implicit none
complex(8), intent(in) :: a, b
complex(8)
:: multiplica_complex8
end function multiplica_complex8
! Function que multiplica lgicos
function multiplica_logical(a, b)
implicit none
logical, intent(in) :: a, b
logical
:: multiplica_logical
end function multiplica_logical
end interface
!***** Interface genrica para diviso *****
interface divide
! Function que divide inteiros de 1 byte
function divide_int1(a, b)
implicit none
integer(1), intent(in) :: a, b
integer(1)
:: divide_int1
end function divide_int1
! Function que divide inteiros de 2 bytes
function divide_int2(a, b)
implicit none
integer(2), intent(in) :: a, b
integer(2)
:: divide_int2
end function divide_int2

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

115

Fortran 90/95
! Function que divide inteiros de 4 bytes
function divide_int4(a, b)
implicit none
integer(4), intent(in) :: a, b
integer(4)
:: divide_int4
end function divide_int4
! Function que divide reais de 4 bytes
function divide_real4(a, b)
implicit none
real(4), intent(in) :: a, b
real(4)
:: divide_real4
end function divide_real4
! Function que divide reais de 8 bytes
function divide_real8(a, b)
implicit none
real(8), intent(in) :: a, b
real(8)
:: divide_real8
end function divide_real8
! Function que divide complexos de 4 bytes
function divide_complex4(a, b)
implicit none
complex(4), intent(in) :: a, b
complex(4)
:: divide_complex4
end function divide_complex4
! Function que divide complexos de 8 bytes
function divide_complex8(a, b)
implicit none
complex(8), intent(in) :: a, b
complex(8)
:: divide_complex8
end function divide_complex8
! Function que divide lgicos
function divide_logical(a, b)
implicit none
logical, intent(in) :: a, b
logical
:: divide_logical
end function divide_logical
end interface
!Declarao de variveis para teste
integer(1) :: int_a1 = 1_1, int_b1 = 3_1, int_c1
integer(2) :: int_a2 = 1_2, int_b2 = 3_2, int_c2
integer(4) :: int_a4 = 1_4, int_b4 = 3_4, int_c4
real(4) :: real_a4 = 1._4, real_b4 = 3._4, real_c4
real(8) :: real_a8 = 1._8, real_b8 = 3._8, real_c8
complex(4) :: cplx_a4 =(1._4,1._4), cplx_b4 =(3._4,3._4), cplx_c4
complex(8) :: cplx_a8 =(1._8,1._8), cplx_b8 =(3._8,3._8), cplx_c8
logical :: logical_a = .true., logical_b = .true., logical_c
! Teste da operaes bsicas sobre inteiros de 1 byte
int_c1 = soma(int_a1, int_b1)
int_c1 = subtrai(int_a1, int_b1)

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

116

Fortran 90/95
int_c1 = multiplica(int_a1, int_b1)
int_c1 = divide(int_a1, int_b1)
! Teste da operaes bsicas sobre inteiros de 2 bytes
int_c2 = soma(int_a2, int_b2)
int_c2 = subtrai(int_a2, int_b2)
int_c2 = multiplica(int_a2, int_b2)
int_c2 = divide(int_a2, int_b2)
! Teste da operaes bsicas sobre inteiros de 4 bytes
int_c4 = soma(int_a4, int_b4)
int_c4 = subtrai(int_a4, int_b4)
int_c4 = multiplica(int_a4, int_b4)
int_c4 = divide(int_a4, int_b4)
! Teste da operaes bsicas sobre reais de 4 bytes
real_c4 = soma(real_a4, real_b4)
real_c4 = subtrai(real_a4, real_b4)
real_c4 = multiplica(real_a4, real_b4)
real_c4 = divide(real_a4, real_b4)
! Teste da operaes bsicas sobre reais de 8 bytes
real_c8 = soma(real_a8, real_b8)
real_c8 = subtrai(real_a8, real_b8)
real_c8 = multiplica(real_a8, real_b8)
real_c8 = divide(real_a8, real_b8)
! Teste da operaes bsicas sobre complexos de 4 bytes
cplx_c4 = soma(cplx_a4, cplx_b4)
cplx_c4 = subtrai(cplx_a4, cplx_b4)
cplx_c4 = multiplica(cplx_a4, cplx_b4)
cplx_c4 = divide(cplx_a4, cplx_b4)
! Teste da operaes bsicas sobre complexos de 8 bytes
cplx_c8 = soma(cplx_a8, cplx_b8)
cplx_c8 = subtrai(cplx_a8, cplx_b8)
cplx_c8 = multiplica(cplx_a8, cplx_b8)
cplx_c8 = divide(cplx_a8, cplx_b8)
! Teste da operaes bsicas sobre lgicos
logical_c = soma(logical_a, logical_b)
logical_c = subtrai(logical_a, logical_b)
logical_c = multiplica(logical_a, logical_b)
logical_c = divide(logical_a, logical_b)
end program lib_demo_sources

De posse de todos os cdigos fonte, da biblioteca e do programa aplicativo, compila-se


e linca-se, produzindo o arquivo executvel.
10.2 Bibliotecas de arquivos objeto
Uma outra possibilidade para produzir e usar bibliotecas gerar, a partir dos cdigos
fonte, os respectivos arquivos objeto (*.obj) da biblioteca. Outra possibilidade utilizar
arquivos objeto produzidos por outros programadores. Uma vantagem dos arquivos objeto
que eles escondem a implementao dos algoritmos, protegendo os cdigos fonte e
possibilitando o comrcio das bibliotecas.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

117

Fortran 90/95
De qualquer maneira, com arquivos objeto prprios ou de outra procedncia, basta
colocar este arquivos em diretrio apropriado, que depende de cada compilador, ento
compila-se o programa que est sendo desenvolvido e por fim linca-se todos os arquivos
objeto, da biblioteca e do aplicativo, para produzir o arquivo executvel.
10.3 Bibliotecas estticas
O Fortran da suporte ao conceito de bibliotecas estticas (static library). Esta
denominao deve-se ao fato de que este tipo de biblioteca tem que ser lincada antes do incio
da execuo. Para produzir uma biblioteca esttica basta usar as diretivas corretas do
compilador, que depende de cada fabricante, e compilar e lincar os cdigos fonte da
biblioteca. O resultado final ser uma biblioteca esttica, em realidade um arquivo do tipo
(*.lib). De posse de um arquivo do tipo (*.lib), independente de quem o produziu, pode-se
desenvolver um aplicativo para utilizar aquela biblioteca, ao final basta lincar o arquivo
objeto (*.obj) do aplicativo com o arquivo da biblioteca (*.lib).
10.4 Bibliotecas utilizando Mdulos
Uma forma bastante prtica de se produzir uma biblioteca utilizando mdulos.
Basicamente, coloca-se os cdigos fonte em um mdulo, como mostrado abaixo
module arithmetic
!Biblioteca criado utilizando o conceito de mdulo.
implicit none
! Interfaces
interface soma
module procedure soma_int1
module procedure soma_int2
module procedure soma_int4
module procedure soma_real4
module procedure soma_real8
module procedure soma_complex4
module procedure soma_complex8
module procedure soma_logical
end interface
interface subtrai
module procedure subtrai_int1
module procedure subtrai_int2
module procedure subtrai_int4
module procedure subtrai_real4
module procedure subtrai_real8
module procedure subtrai_complex4
module procedure subtrai_complex8
module procedure subtrai_logical
end interface
interface multiplica
module procedure multiplica_int1
module procedure multiplica_int2
module procedure multiplica_int4
module procedure multiplica_real4
module procedure multiplica_real8
module procedure multiplica_complex4

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

118

Fortran 90/95
module procedure multiplica_complex8
module procedure multiplica_logical
end interface
interface divide
module procedure divide_int1
module procedure divide_int2
module procedure divide_int4
module procedure divide_real4
module procedure divide_real8
module procedure divide_complex4
module procedure divide_complex8
module procedure divide_logical
end interface
contains
! Function que soma inteiros de 1 byte
function soma_int1(a, b)
implicit none
integer(1), intent(in) :: a, b
integer(1)
:: soma_int1
soma_int1 = a + b
end function soma_int1
! Function que soma inteiros de 2 bytes
function soma_int2(a, b)
implicit none
integer(2), intent(in) :: a, b
integer(2)
:: soma_int2
soma_int2 = a + b
end function soma_int2
! Function que soma inteiros de 4 bytes
function soma_int4(a, b)
implicit none
integer(4), intent(in) :: a, b
integer(4)
:: soma_int4
soma_int4 = a + b
end function soma_int4
! Function que soma reais de 4 bytes
function soma_real4(a, b)
implicit none
real(4), intent(in) :: a, b
real(4)
:: soma_real4
soma_real4 = a + b
end function soma_real4

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

119

Fortran 90/95
! Function que soma reais de 8 bytes
function soma_real8(a, b)
implicit none
real(8), intent(in) :: a, b
real(8)
:: soma_real8
soma_real8 = a + b
end function soma_real8
! Function que soma complexos de 4 bytes
function soma_complex4(a, b)
implicit none
complex(4), intent(in) :: a, b
complex(4)
:: soma_complex4
soma_complex4 = a + b
end function soma_complex4
! Function que soma complexos de 8 bytes
function soma_complex8(a, b)
implicit none
complex(8), intent(in) :: a, b
complex(8)
:: soma_complex8
soma_complex8 = a + b
end function soma_complex8
! Function que soma lgicos
function soma_logical(a, b)
implicit none
logical, intent(in) :: a, b
logical
:: soma_logical
soma_logical = a + b
end function soma_logical
! Function que subtrai inteiros de 1 byte
function subtrai_int1(a, b)
implicit none
integer(1), intent(in) :: a, b
integer(1)
:: subtrai_int1
subtrai_int1 = a - b
end function subtrai_int1
! Function que subtrai inteiros de 2 bytes
function subtrai_int2(a, b)
implicit none

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

120

Fortran 90/95
integer(2), intent(in) :: a, b
integer(2)
:: subtrai_int2
subtrai_int2 = a - b
end function subtrai_int2
! Function que subtrai inteiros de 4 bytes
function subtrai_int4(a, b)
implicit none
integer(4), intent(in) :: a, b
integer(4)
:: subtrai_int4
subtrai_int4 = a - b
end function subtrai_int4
! Function que subtrai reais de 4 bytes
function subtrai_real4(a, b)
implicit none
real(4), intent(in) :: a, b
real(4)
:: subtrai_real4
subtrai_real4 = a - b
end function subtrai_real4
! Function que subtrai reais de 8 bytes
function subtrai_real8(a, b)
implicit none
real(8), intent(in) :: a, b
real(8)
:: subtrai_real8
subtrai_real8 = a - b
end function subtrai_real8
! Function que subtrai complexos de 4 bytes
function subtrai_complex4(a, b)
implicit none
complex(4), intent(in) :: a, b
complex(4)
:: subtrai_complex4
subtrai_complex4 = a - b
end function subtrai_complex4
! Function que subtrai complexos de 8 bytes
function subtrai_complex8(a, b)
implicit none
complex(8), intent(in) :: a, b
complex(8)
:: subtrai_complex8
subtrai_complex8 = a - b

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

121

Fortran 90/95
end function subtrai_complex8
! Function que subtrai lgicos
function subtrai_logical(a, b)
implicit none
logical, intent(in) :: a, b
logical
:: subtrai_logical
subtrai_logical = a - b
end function subtrai_logical
! Function que multiplica inteiros de 1 byte
function multiplica_int1(a, b)
implicit none
integer(1), intent(in) :: a, b
integer(1)
:: multiplica_int1
multiplica_int1 = a * b
end function multiplica_int1
! Function que multiplica inteiros de 2 bytes
function multiplica_int2(a, b)
implicit none
integer(2), intent(in) :: a, b
integer(2)
:: multiplica_int2
multiplica_int2 = a * b
end function multiplica_int2
! Function que multiplica inteiros de 4 bytes
function multiplica_int4(a, b)
implicit none
integer(4), intent(in) :: a, b
integer(4)
:: multiplica_int4
multiplica_int4 = a * b
end function multiplica_int4
! Function que multiplica reais de 4 bytes
function multiplica_real4(a, b)
implicit none
real(4), intent(in) :: a, b
real(4)
:: multiplica_real4
multiplica_real4 = a * b
end function multiplica_real4
! Function que multiplica reais de 8 bytes
function multiplica_real8(a, b)
implicit none

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

122

Fortran 90/95
real(8), intent(in) :: a, b
real(8)
:: multiplica_real8
multiplica_real8 = a * b
end function multiplica_real8
! Function que multiplica complexos de 4 bytes
function multiplica_complex4(a, b)
implicit none
complex(4), intent(in) :: a, b
complex(4)
:: multiplica_complex4
multiplica_complex4 = a * b
end function multiplica_complex4
! Function que multiplica complexos de 8 bytes
function multiplica_complex8(a, b)
implicit none
complex(8), intent(in) :: a, b
complex(8)
:: multiplica_complex8
multiplica_complex8 = a * b
end function multiplica_complex8
! Function que multiplica lgicos
function multiplica_logical(a, b)
implicit none
logical, intent(in) :: a, b
logical
:: multiplica_logical
multiplica_logical = a * b
end function multiplica_logical
! Function que divide inteiros de 1 byte
function divide_int1(a, b)
implicit none
integer(1), intent(in) :: a, b
integer(1)
:: divide_int1
if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_int1 = a / b
end function divide_int1
! Function que divide inteiros de 2 bytes
function divide_int2(a, b)
implicit none

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

123

Fortran 90/95
integer(2), intent(in) :: a, b
integer(2)
:: divide_int2
if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_int2 = a / b
end function divide_int2
! Function que divide inteiros de 4 bytes
function divide_int4(a, b)
implicit none
integer(4), intent(in) :: a, b
integer(4)
:: divide_int4
if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_int4 = a / b
end function divide_int4
! Function que divide reais de 4 bytes
function divide_real4(a, b)
implicit none
real(4), intent(in) :: a, b
real(4)
:: divide_real4
if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_real4 = a / b
end function divide_real4
! Function que divide reais de 8 bytes
function divide_real8(a, b)
implicit none
real(8), intent(in) :: a, b
real(8)
:: divide_real8
if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_real8 = a / b
end function divide_real8

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

124

Fortran 90/95
! Function que divide complexos de 4 bytes
function divide_complex4(a, b)
implicit none
complex(4), intent(in) :: a, b
complex(4)
:: divide_complex4
if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_complex4 = a / b
end function divide_complex4
! Function que divide complexos de 8 bytes
function divide_complex8(a, b)
implicit none
complex(8), intent(in) :: a, b
complex(8)
:: divide_complex8
if(0 == b) then
write(*,*)'Erro fatal, diviso por zero!'
stop
end if
divide_complex8 = a / b
end function divide_complex8
! Function que divide lgicos
function divide_logical(a, b)
implicit none
logical, intent(in) :: a, b
logical
:: divide_logical
if(.not.b) then
write(*,*) 'Erro fatal em divide_logical, diviso por zero!'
stop
end if
divide_logical = a / b
end function divide_logical
end module arithmetic

Este programa fonte acima quando compilado ir produzir um arquivo objeto (*.obj) e
um arquivo modulo (*.mod). Estes arquivos constituem a biblioteca contida dentro de um
mdulo. Neste caso no foi necessrio prover uma interface explicita para as rotinas, uma vez
que o mdulo, por si s capaz de extrair automaticamente uma interface explicita.
A seguir apresenta-se o aplicativo modificado, que vai utilizar a biblioteca.
program module_lib_demo_sources
use arithmetic

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

125

Fortran 90/95
implicit none
!Declarao de variveis para teste
integer(1) :: int_a1 = 1_1, int_b1 = 3_1, int_c1
integer(2) :: int_a2 = 1_2, int_b2 = 3_2, int_c2
integer(4) :: int_a4 = 1_4, int_b4 = 3_4, int_c4
real(4) :: real_a4 = 1._4, real_b4 = 3._4, real_c4
real(8) :: real_a8 = 1._8, real_b8 = 3._8, real_c8
complex(4) :: cplx_a4 =(1._4,1._4), cplx_b4 =(3._4,3._4), cplx_c4
complex(8) :: cplx_a8 =(1._8,1._8), cplx_b8 =(3._8,3._8), cplx_c8
logical :: logical_a = .true., logical_b = .true., logical_c
! Teste da operaes bsicas sobre inteiros de 1 byte
int_c1 = soma(int_a1, int_b1)
int_c1 = subtrai(int_a1, int_b1)
int_c1 = multiplica(int_a1, int_b1)
int_c1 = divide(int_a1, int_b1)
! Teste da operaes bsicas sobre inteiros de 2 bytes
int_c2 = soma(int_a2, int_b2)
int_c2 = subtrai(int_a2, int_b2)
int_c2 = multiplica(int_a2, int_b2)
int_c2 = divide(int_a2, int_b2)
! Teste da operaes bsicas sobre inteiros de 4 bytes
int_c4 = soma(int_a4, int_b4)
int_c4 = subtrai(int_a4, int_b4)
int_c4 = multiplica(int_a4, int_b4)
int_c4 = divide(int_a4, int_b4)
! Teste da operaes bsicas sobre reais de 4 bytes
real_c4 = soma(real_a4, real_b4)
real_c4 = subtrai(real_a4, real_b4)
real_c4 = multiplica(real_a4, real_b4)
real_c4 = divide(real_a4, real_b4)
! Teste da operaes bsicas sobre reais de 8 bytes
real_c8 = soma(real_a8, real_b8)
real_c8 = subtrai(real_a8, real_b8)
real_c8 = multiplica(real_a8, real_b8)
real_c8 = divide(real_a8, real_b8)
! Teste da operaes bsicas sobre complexos de 4 bytes
cplx_c4 = soma(cplx_a4, cplx_b4)
cplx_c4 = subtrai(cplx_a4, cplx_b4)
cplx_c4 = multiplica(cplx_a4, cplx_b4)
cplx_c4 = divide(cplx_a4, cplx_b4)
! Teste da operaes bsicas sobre complexos de 8 bytes
cplx_c8 = soma(cplx_a8, cplx_b8)
cplx_c8 = subtrai(cplx_a8, cplx_b8)
cplx_c8 = multiplica(cplx_a8, cplx_b8)
cplx_c8 = divide(cplx_a8, cplx_b8)
! Teste da operaes bsicas sobre lgicos
logical_c = soma(logical_a, logical_b)
logical_c = subtrai(logical_a, logical_b)

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

126

Fortran 90/95
logical_c = multiplica(logical_a, logical_b)
logical_c = divide(logical_a, logical_b)
end program module_lib_demo_sources

Note-se que neste caso no foi necessrio construir no corpo do aplicativo a interface
explicita, neste caso j construda automaticamente, pelo fato da biblioteca estar inserida
dentro de um mdulo. Para acessar as informaes na biblioteca foi necessrio usar a
declarao use arithmetic.
10.4 O uso de bibliotecas comerciais
A linguagem Fortran por ser uma das mais antigas em operao contnua e tambm por
ser uma linguagem eminentemente cientfica, possui grandes bibliotecas de rotinas,
desenvolvidas ao longo de dcadas de pesquisas. Estas bibliotecas so comercializadas pelo
fabricantes. As duas principais bibliotecas cientficas, provavelmente, so IMSL
(International Mathematical and Statistical Library) e NAG (Numerical Algorithm Group). A
que conheo bem e tenho usado desde 1986 a IMSL. Esta biblioteca possui mais de mil
rotinas cientficas nos mais variados ramos da matemtica e da estatstica. A biblioteca NAG
tambm muito usada. Os seus manuais esto impressos em cinco volumes com alguns
milhares de pginas.
Para utilizar-se destas rotinas, precisa-se estudar os respectivos manuais e as diretivas
do compilador para inclu-las. No caso do compilador Microsoft basta colocar a seguinte
declarao use msimslmd, na linha logo aps as palavras: program, subroutine e function.
Abaixo apresenta-se um pequeno exemplo de como efetuar a integrao de uma funo
dada
! Este programa demonstra como utilizar uma dada rotina
! da biblioteca IMSL
!
! O exemplo escolhido a integrao de uma funo de uma varivel
!
! Programador: joo batista aparecido, 03/08/2001
!
program exemplo_imsl
!Declarao para acessar a biblioteca
use msimslmd, only: integral => dqdag
implicit none
external f
integer :: rule
real(8) :: f, a, b, err_abs, err_rel, res, err_est
!Para a maioria das funes use rule igual a 2,
!para funes com picos acentuados use rule igual a 1,
!e para funes oscilatrias use rule = 6.
rule = 2
!Extremo esquerdo do intervalo de integrao
a = 0._8
!Extremo direito do intervalo de integrao
b = 1._8

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

127

Fortran 90/95
!Erros: absoluto, relativo
err_abs = 1.d-10
err_rel = 1.d-10

call integral(f, a, b, err_abs, err_rel, rule, res, err_est)


! Impresso da integral e de seu erro estimado
write(*,*)'Resultado da integral = ', res
write(*,*)'Erro estimado da integral = ', err_est
end program exemplo_imsl
! Funo a ser integrada
function f(x)
implicit none
real(8) :: x, f
f = 3.d0*dsqrt(1.d0-x)/2.d0
return
end function f

importante que o usurio leia atentamente os manuais das rotinas, pois muitas delas
so de natureza complexa, e no ser difcil cometer erros de julgamento e usar rotinas
pensando que se est fazendo uma coisa e em realidade est-se fazendo totalmente outra.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

128

Fortran 90/95

CAPTULO 11
PROGRAMA EXEMPLO
Neste captulo apresenta-se um programa exemplo. O contexto matemtico do problema
em questo no importante. O importante so a estrutura do programa e as solues
encontradas. Fez-se um uso extensivo de mdulos. Procurou-se criar mdulos de dados e
mdulos de rotinas. Desta forma o encapsulamento dos dados bastante bom. O acesso das
rotinas aos dados fez-se atravs do uso controlado e racional da declarao USE. Evitou-se
totalmente o uso da declarao COMMON, uma vez que o uso de mdulos a substituem com
grande vantagem.
Um pouco de cdigo sempre bom para inspirao.
Este curso basicamente de linguagem, mas como as linguagens computacionais so
usadas para programao computacional inevitvel praticar-se a programao. Alis este o
objetivo quando se aprende uma linguagem. Porm, um curso apenas de programao seria
bastante distinto.
Uma idia final que gostaria de mencionar
Antes de comear a programar, pense profundamente nos dados envolvidos no algoritmo
que se quer implementar. Muitos tendem a pensar apenas nos mtodos esquecendo-se dos
dados. preciso antes de tudo ter-se uma idia muito clara das estruturas de dados que
sero utilizadas. Isto no tudo, nem muito, mas uma regra heurstica que pode lhe
economizar muitas horas de retrabalho para acertar um cdigo no qual as estruturas de
dados mudaram no meio do desenvolvimento do projeto.

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

129

Fortran 90/95
program rectangular_contraction
! este programa destina-se a resolver a equao de laplace sobre um domnio
! irregular formado por uma contrao.
! o fluido modelado como um fluido perfeito devido ao alto nmero de reynolds
! e tambm porque tem-se mais interesse sobre o escoamento fora da camada limite.
!
! programador: joo batista aparecido, ilha solteira, 11 de maro de 2000.
!
! o polinomio que define a parede eh do terceiro grau.
! a condio de contorno na sada da contrao do tipo derivada nula.
!
! programador: joo batista aparecido, ilha solteira, 16 de maio de 2000.
use data_type
use global_data
use eigenproblem
use aiibijcij
use msimslmd
use grid
use velocity_field_data, only : xpos
use sist_lin_data
use bcdijmn
use matrixlib
use outputwriting
implicit none
real(double) :: void
void = computeeigenvalues_y()
void = computeeigenconstants_y()
void = computeeigenvaluessquared_y()
void = computeeigenvalues_x()
void = computeeigenconstants_x()
void = computeeigenvaluessquared_x()
void = computeaii()
void = computebij()
void = computecij()
void = computegi()
void = basicgrid()
void = modifiedgrid()
eijmn = 0.d0
gim = 0.d0
void = computebijmn()
void = computecijmn()
void = computedijmn()
void = computegim()
call dlinrg(m0*m0,eijmn,m0*m0,eijmn,m0*m0)
call prod_matrix_vector(m0*m0,eijmn,gim,yq)
void = assignyim()
void = fieldsstreamfunctionvelsuv()
void = axialquantities()

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

130

Fortran 90/95
void = averagevelocityu()
void = averagevelocityv()
void = printing()
end program rectangular_contraction

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

131

Fortran 90/95
!====
module data_type
!
! this module defines four integers parameters for using in the definition of
! kinds of integers: short and long; and two kinds of reals: single and double.
!
! programmer: joo batista aparecido
! place : ilha solteira
! date
: january 1, 2000
!
implicit none
save
integer(2), parameter, public :: short = 2, long = 4, single = 4, double = 8
end module data_type
!====
module constants
use data_type
!
! this module defines common constants that are frequently used.
!
! programmer: joo batista aparecido
! place : ilha solteira
! date
: january 19, 2000
!
implicit none
save
integer(long), parameter :: zero_int = 0_4
real(double), parameter :: pi = 3.141592653589793d0
real(double), parameter :: zero_real = 0.0d0
real(double), parameter :: root_of_two = 1.414213562373d0
real(double), parameter :: unity = 1.d0
end module constants
!====

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

132

Fortran 90/95
module global_data
use data_type
!
! this module define the main global variables.
!
! programmer: joo batista aparecido
! place : ilha solteira
! date
: march 11, 2000
!
implicit none
save
! number of terms in the series
integer(long), parameter :: m0 = 10

! number of terms in the series

! characteristic lengths
real(double), parameter :: l1 = 1.d0
real(double), parameter :: l2 = 3.0d0
real(double), parameter :: l3 = 0.25d0
real(double), dimension(m0) :: eigenvalues_y, eigenconstants_y
real(double), dimension(m0) :: eigenvaluessquared_y, eigenfunctions_y
real(double), dimension(m0) :: eigenfunctions_ydrv_y, eigenfunctions_ydrv_x
real(double), dimension(m0) :: aii, gi
real(double), dimension(m0) :: eigenvalues_x, eigenconstants_x
real(double), dimension(m0) :: eigenvaluessquared_x, eigenfunctions_x
real(double), dimension(m0) :: eigenfunctions_xdrv_x
real(double), dimension(m0,m0) :: bij, cij
end module global_data

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

133

Fortran 90/95
module sist_lin_data
use data_type
use constants
use global_data, only : m0
implicit none
save
real(double), dimension(m0*m0, m0*m0) :: eijmn
real(double), dimension(m0*m0) :: gim
real(double), dimension(m0*m0) :: yq
real(double), dimension(m0,m0) :: yim
end module sist_lin_data

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

134

Fortran 90/95
module velocity_field_data
use data_type
implicit none
save
! number of nodes in each direction
integer(long), parameter :: mx = 101, my = 101
real(double), dimension(mx) :: x_axis, uw, vw, pw, u0, v0, p0, uav, vav
real(double), dimension(my,mx) :: u, v, p, psi, xpos, ypos
end module velocity_field_data

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

135

Fortran 90/95
module matrixlib
use data_type
use constants
implicit none
contains
!ccccccccccccccccccccccccc
!c this routine setts a vector to zero
!c==========================
subroutine zero_vector(n_vec, a_vector)
implicit none
integer(long) :: i, n_vec
real(double), dimension(n_vec) :: a_vector
do i=1,n_vec
a_vector(i) = zero_real
end do
return
end subroutine zero_vector
!ccccccccccccccccccccccccc
!c this routine adds two vector a_vector, b_vector and return in c_vector
!c==========================
subroutine add_vector(n_vec,a_vector,b_vector,c_vector)
implicit none
integer(long) :: i, n_vec
real(double), dimension(n_vec) :: a_vector, b_vector, c_vector
do i=1,n_vec
c_vector(i)=a_vector(i)+b_vector(i)
end do
return
end subroutine add_vector
!ccccccccccccccccccccccccc
!c this routine equal vector a_vector toa vector b_vector
!c==========================
subroutine equal_vector(n_vec,a_vector,b_vector)
implicit none
integer(long) :: i, n_vec
real(double), dimension(n_vec) :: a_vector,b_vector
do i=1,n_vec
b_vector(i)=a_vector(i)
end do
return
end subroutine equal_vector
!ccccccccccccccccccccccccc
!c this routine does the product of a square matrix a_matrix by a
!c vector b_vector and return in a c_vector
!c==========================
subroutine prod_matrix_vector(n_vec,a_matrix,b_vector,c_vector)

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

136

Fortran 90/95
implicit none
integer(long) :: i, j, n_vec
real(double), dimension(n_vec) :: b_vector, c_vector
real(double), dimension(n_vec,n_vec) :: a_matrix
do i=1,n_vec
c_vector(i) = zero_real
do j=1,n_vec
c_vector(i)=c_vector(i)+a_matrix(i,j)*b_vector(j)
end do
end do
return
end subroutine prod_matrix_vector
!ccccccccccccccccccccccccc
!c this routine does the iner product of a vector a_vector by a
!c vector b_vector and return prod
!c==========================
subroutine prod_int_vector(n_vec,a_vector,b_vector,prod)
implicit none
integer(long) :: i, n_vec
real(double) :: prod
real(double), dimension(n_vec) :: a_vector, b_vector
prod = zero_real
do i = 1,n_vec
prod = prod+a_vector(i)*b_vector(i)
end do
return
end subroutine prod_int_vector
!ccccccccccccccccccccccccc
!c this routine does the product of a transpose square matrix a_matrix
!c by a vector b_vector and return in a c_vector
!c==========================
subroutine prod_trans_matrix_vector(n_vec,a_matrix,b_vector,c_vector)
implicit none
integer(long) :: i, j, n_vec
real(double), dimension(n_vec) :: b_vector, c_vector
real(double), dimension(n_vec,n_vec) :: a_matrix
do i=1,n_vec
c_vector(i)=0.d0
do j=1,n_vec
c_vector(i)=c_vector(i)+a_matrix(j,i)*b_vector(j)
end do
end do
return
end subroutine prod_trans_matrix_vector
!ccccccccccccccccccccccccc
!c this routine does the product of a diagonal square matrix a_matrix

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

137

Fortran 90/95
!c (stored in vector form) by a vector b_vector and return in a c_vector
!c==========================
subroutine prod_diag_matrix_vector(n_vec,a_matrix,b_vector,c_vector)
implicit none
integer(long) :: i, n_vec
real(double), dimension(n_vec) :: a_matrix, b_vector, c_vector
do i=1,n_vec
c_vector(i)=a_matrix(i)*b_vector(i)
end do
return
end subroutine prod_diag_matrix_vector
!ccccccccccccccccccccccccc
!c this routine multiply a vector a_vector by -1.
!c==========================
subroutine oposite_vector(n_vec,a_vector)
implicit none
integer(long) :: i, n_vec
real(double), dimension(n_vec) :: a_vector
do i=1,n_vec
a_vector(i) = -a_vector(i)
end do
return
end subroutine oposite_vector
!ccccccccccccccccccccccccc
!c this routine invert the order of elements in a vector
!c==========================
subroutine reverse_vector(n_vec,a_vector)
implicit none
integer(long) :: i, n, n_vec
complex(double) :: aux
complex(double), dimension(n_vec) :: a_vector
n=n_vec/2
do i=1,n
aux=a_vector(i)
a_vector(i)=a_vector(n_vec-i+1)
a_vector(n_vec-i+1)=aux
end do
return
end subroutine reverse_vector
!ccccccccccccccccccccccccc
!c this routine shifts the elements of vector by a constant
!c==========================
subroutine shift_vector(n_vec,const,a_vector)
implicit none
integer(long) :: i, n_vec

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

138

Fortran 90/95
real(double) :: const
real(double), dimension(n_vec) :: a_vector
do i=1,n_vec
a_vector(i)=a_vector(i)+const
end do
return
end subroutine shift_vector
!ccccccccccccccccccccccccc
!c this routine invert the order of columns in a matrix
!c==========================
subroutine reverse_matrix(n_vec,a_matrix)
implicit none
integer(long) :: i, j, n, n_vec
complex(double) aux
complex(double),dimension(n_vec,n_vec) :: a_matrix
n = n_vec/2
do j = 1,n
do i = 1,n_vec
aux = a_matrix(i,j)
a_matrix(i,j) = a_matrix(i,n_vec-j+1)
a_matrix(i,n_vec-j+1) = aux
end do
end do
return
end subroutine reverse_matrix
!ccccccccccccccccccccccccc
!c this routine prints a given matrix by columns
!c==========================
subroutine print_matrix(n_vec,a_matrix)
implicit none
integer(long) :: i, j, n_vec
real(double), dimension(n_vec,n_vec) :: a_matrix
do j=1,n_vec
write(*,*)
do i=1,n_vec
write(*,*)i,j,a_matrix(i,j)
end do
end do
return
end subroutine print_matrix
!ccccccccccccccccccccccccc
!c this routine prints a given matrix in a full form
!c==========================
subroutine print_matrix2(n_vec,a_matrix)
implicit none
integer(long) :: i, j, n_vec

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

139

Fortran 90/95
real(double), dimension(n_vec,n_vec) :: a_matrix
do i=1,n_vec
write(*,100)i,(a_matrix(i,j),j=1,n_vec)
end do
100 format(1x,i2,2x,4(f11.5,2x))
return
end subroutine print_matrix2
!ccccccccccccccccccccccccc
!c this routine prints a given vector
!c==========================
subroutine print_vector(n_vec,a_vector)
implicit none
integer(long) :: j, n_vec
real(double), dimension(n_vec) :: a_vector
write(*,*)(a_vector(j),j=1,n_vec)
return
end subroutine print_vector
end module matrixlib

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

140

Fortran 90/95
module aiibijcij
use data_type
use constants
! this module is designed to compute the matrix aij, bij and cij. since aij is
! a diagonal matrix it is stored as a vector.
implicit none
contains
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computeaii()
use global_data, only : m0, aii
integer(long) :: i
real(double) :: computeaii
do i = 1, m0
aii(i) = unity
end do

! diagonal elements equal to unity

computeaii = unity
end function computeaii
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computebij()
use global_data, only : m0, bij, eigenvalues_y, eigenvaluessquared_y
integer(long) :: i, j
real(double) :: computebij
do i = 1, m0
do j = 1, m0
if(i == j) then
bij(i,j) = zero_real
else
bij(i,j) = 4.d0*eigenvalues_y(i)*eigenvalues_y(j)/
&
(eigenvaluessquared_y(i)-eigenvaluessquared_y(j))
if((i+j)/2*2 /= (i+j)) bij(i,j) = - bij(i,j)
end if
end do
end do
computebij = unity
end function computebij
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computecij()
use global_data, only : m0, cij, eigenvalues_y, eigenvaluessquared_y
integer(long) :: i, j
real(double) :: computecij
do i = 1, m0
do j = 1, m0
if(i == j) then
cij(i,j) = -(3.d0 + 4.d0*eigenvaluessquared_y(i))/12.d0

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

141

Fortran 90/95
else
cij(i,j) = -2.d0*eigenvalues_y(i)*eigenvalues_y(j)/
&
(eigenvaluessquared_y(i)-eigenvaluessquared_y(j))**2
if((i+j)/2*2 /= (i+j)) cij(i,j) = - cij(i,j)
end if
end do
end do
computecij = unity
end function computecij
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computegi()
use global_data, only : m0, gi, eigenvalues_y
integer(long) :: i
real(double) :: computegi
do i = 1, m0
gi(i) = -root_of_two/eigenvalues_y(i)
!gi(i) = root_of_two/eigenvalues_y(i)
if(i/2*2 /= i ) gi(i) = -gi(i)
end do
computegi = unity
end function computegi
end module aiibijcij

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

142

Fortran 90/95
module aiibijcij_x
use data_type
use constants
implicit none
contains
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computebij_x(x)
use global_data, only : m0, bij
use wall_functions, only : p, deriv_p
use ijmn_transfer, only : i, j
real(double) :: computebij_x, x, px, dpx, aux1
! computing p(x) and its derivative
px = p(x)
dpx = deriv_p(x)
aux1 = dpx/px
! filling the forth quarter
if(i == j) then
computebij_x = zero_real
else
computebij_x = bij(i,j)*aux1
end if
end function computebij_x
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computecij_x(x)
use global_data, only : m0, cij, eigenvaluessquared_y
use wall_functions, only : p, deriv_p, deriv2nd_p
use ijmn_transfer, only : i, j
real(double) :: computecij_x, x, px, dpx, d2px, aux1, aux2, aux3, aux4
! computing p(x) and its derivative
px = p(x)
dpx = deriv_p(x)
d2px = deriv2nd_p(x)
aux1 = dpx/px
aux2 = d2px/px
aux3 = aux2 + aux1*aux1
!aux4 = aux2 + 3.d0*aux1*aux1
aux4 = -aux2 + 3.d0*aux1*aux1
if(i == j) then
computecij_x = cij(i,j)*(aux1**2)
else
computecij_x = cij(i,j)* &
!
(eigenvaluessquared_y(j)*aux3 - eigenvaluessquared_y(i)*aux4)
(eigenvaluessquared_y(j)*aux3 + eigenvaluessquared_y(i)*aux4)
end if
end function computecij_x

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

143

Fortran 90/95
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computegi_x(x)
use global_data, only : m0, gi
use wall_functions, only : p, deriv_p, deriv2nd_p
use ijmn_transfer, only : i
implicit none
real(double) :: computegi_x, x, px, dpx, d2px, h
! computing p(x) and its derivative
px = p(x)
dpx = deriv_p(x)
d2px = deriv2nd_p(x)
h = (d2px-2.d0*(dpx**2)/px)/dsqrt(px) !!!!!!!!verificar
computegi_x = h*gi(i)
end function computegi_x
end module aiibijcij_x

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

144

Fortran 90/95
module bcdijmn
use data_type
use constants
implicit none
contains
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computebijmn()
use global_data, only : m0, l2, bij, eigenvalues_y, eigenvaluessquared_y
use aiibijcij_x, only : computebij_x
use ijmn_transfer
use sist_lin_data, only : eijmn
use fbfcfd, only : fb
integer(long) :: iconta, jconta, irule
real(double) :: computebijmn, errabs, errel, errest, result
iconta=0
do i=1,m0
do m=1,m0
iconta=iconta+1
jconta=0
do j=1,m0
do n=1,m0
jconta=jconta+1
!if(jconta.lt.iconta) cycle
!
errabs=1.d-6
errel=0.d0
irule=6
!
call dqdag(fb,0.d0,l2,errabs,errel,irule,result,errest)
!
eijmn(iconta,jconta) = eijmn(iconta,jconta) + result
!eijmn(jconta,iconta)=eijmn(iconta,jconta)
end do
end do
end do
end do
computebijmn = unity
return
end function computebijmn
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computecijmn()
use global_data, only : m0, l2, bij, eigenvalues_y, eigenvaluessquared_y
use aiibijcij_x, only : computecij_x
use ijmn_transfer
use sist_lin_data, only : eijmn
use fbfcfd, only : fc
integer(long) :: iconta, jconta, irule
real(double) :: computecijmn, errabs, errel, errest, result
iconta=0

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

145

Fortran 90/95
do i=1,m0
do m=1,m0
iconta=iconta+1
jconta=0
do j=1,m0
do n=1,m0
jconta=jconta+1
!if(jconta.lt.iconta) cycle
!
errabs=1.d-6
errel=0.d0
irule=6
!
call dqdag(fc,0.d0,l2,errabs,errel,irule,result,errest)
!
eijmn(iconta,jconta) = eijmn(iconta,jconta) + result
!eijmn(jconta,iconta)=eijmn(iconta,jconta)
end do
end do
end do
end do
computecijmn = unity
return
end function computecijmn
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computedijmn()
use global_data, only : m0, l2, bij, eigenvaluessquared_y, eigenvaluessquared_x
use aiibijcij_x, only : computecij_x
use ijmn_transfer
use sist_lin_data, only : eijmn
use fbfcfd, only : fd
integer(long) :: iconta, jconta, irule
real(double) :: computedijmn, errabs, errel, errest, result
iconta=0
do i=1,m0
do m=1,m0
iconta=iconta+1
jconta=0
do j=1,m0
do n=1,m0
jconta=jconta+1
!if(jconta.lt.iconta) cycle
!
errabs=1.d-6
errel=0.d0
irule=6
!
if(i == j) then
call dqdag(fd,0.d0,l2,errabs,errel,irule,result,errest)
eijmn(iconta,jconta) = eijmn(iconta,jconta) - &
eigenvaluessquared_y(i)*result
!eijmn(jconta,iconta)=eijmn(iconta,jconta)
end if

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

146

Fortran 90/95
if((m == n).and.(i==j)) then
eijmn(iconta,jconta) = eijmn(iconta,jconta) - eigenvaluessquared_x(m)
end if
end do
end do
end do
end do
computedijmn = unity
return
end function computedijmn
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computegim()
use global_data, only : m0, l2, bij, eigenvalues_y, eigenvaluessquared_y
use aiibijcij_x, only : computegi_x
use ijmn_transfer
use sist_lin_data, only : gim
use fbfcfd, only : fg
integer(long) :: iconta, irule
real(double) :: computegim, errabs, errel, errest, result
iconta = 0
do i=1,m0
do m=1,m0
iconta = iconta + 1
!
errabs=1.d-6
errel=0.d0
irule=6
!
call dqdag(fg,0.d0,l2,errabs,errel,irule,result,errest)
!
gim(iconta) = result
end do
end do
computegim = unity
return
end function computegim
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function assignyim()
use global_data, only : m0
use sist_lin_data, only : yq, yim
integer(long) :: i, m, iconta
real(double) :: assignyim
iconta = 0
do i=1,m0
do m=1,m0
iconta = iconta + 1
!
yim(i,m) = yq(iconta)

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

147

Fortran 90/95
!
end do
end do
assignyim = unity
return
end function assignyim
end module bcdijmn

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

148

Fortran 90/95
module eigenproblem
use data_type
use constants, only : unity
implicit none
contains
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computeeigenvalues_y()
use global_data, only : m0, eigenvalues_y
use constants, only : pi
! this function compute the eigenvalues_y
implicit none
integer(long) :: i
real(double) :: computeeigenvalues_y
do i = 1, m0
eigenvalues_y(i) = real(i)*pi
end do

! compute the eigenvalues

computeeigenvalues_y = unity ! return value to the main program


return
end function computeeigenvalues_y
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computeeigenvaluessquared_y()
use global_data, only : m0, eigenvalues_y, eigenvaluessquared_y
use constants
! this function compute the eigenvalues squared
implicit none
integer(long) :: i
real(double) :: computeeigenvaluessquared_y
do i = 1, m0
! compute the eigenvalues squared
eigenvaluessquared_y(i) = eigenvalues_y(i)*eigenvalues_y(i)
end do
computeeigenvaluessquared_y = unity

! return value to the main program

return
end function computeeigenvaluessquared_y
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computeeigenconstants_y()
use global_data, only : m0, eigenconstants_y
use constants
! this function compute the eigenconstants
implicit none
integer(long) :: i

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

149

Fortran 90/95
real(double) :: computeeigenconstants_y
do i = 1, m0
eigenconstants_y(i) = root_of_two
end do

! compute the eigenconstants

computeeigenconstants_y = unity

! return value to the main program

return
end function computeeigenconstants_y
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computeeigenfunctions_y(x,y)
use global_data, only : m0, eigenvalues_y, eigenfunctions_y, eigenconstants_y
use constants, only : unity
use wall_functions, only : p
! this function computes the eigenfunctions
implicit none
integer(long) :: i
real(double) :: computeeigenfunctions_y, x, y, px
px = p(x) ! compute the wall position
do i = 1, m0
! compute the eigenfunctions at the position (x,y)
eigenfunctions_y(i) = eigenconstants_y(i)*dsin(eigenvalues_y(i)*y/px)/dsqrt(px)
end do
computeeigenfunctions_y = unity

! return value to the main program

return
end function computeeigenfunctions_y
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computeeigenfunctions_ydrv_y(x,y)
use global_data, only : m0, eigenvalues_y, eigenfunctions_ydrv_y, eigenconstants_y
use constants, only : unity
use wall_functions, only : p
! this function computes the eigenfunctions derivatives regarding y-axis
implicit none
integer(long) :: i
real(double) :: computeeigenfunctions_ydrv_y, x, y, px
px = p(x) ! compute the wall position
do i = 1, m0
! compute the eigenfunctions y-derivative at the position (x,y)
eigenfunctions_ydrv_y(i) = eigenconstants_y(i)*eigenvalues_y(i)* &
dcos(eigenvalues_y(i)*y/px)/(px*dsqrt(px))
end do
computeeigenfunctions_ydrv_y = unity

! return value to the main program

return

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

150

Fortran 90/95
end function computeeigenfunctions_ydrv_y
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computeeigenfunctions_ydrv_x(x,y)
use global_data, only : m0, eigenvalues_y, eigenfunctions_ydrv_x, eigenconstants_y
use constants
use wall_functions, only : p, deriv_p
! this function computes the eigenfunctions derivatives regarding x-axis
implicit none
integer(long) :: i
real(double) :: computeeigenfunctions_ydrv_x, x, y, px, dpx
px = p(x)
dpx = deriv_p(x)

! compute the wall position p(x)


! compute derivative of p(x)

do i = 1, m0
! compute the eigenfunctions x-derivative at the position (x,y)
eigenfunctions_ydrv_x(i)=-(eigenconstants_y(i)/2.d0)*(2.d0*y*eigenvalues_y(i)* &
dcos(eigenvalues_y(i)*y/px)+px*dsin(eigenvalues_y(i)*y/px))*dpx/ &
((px**2)*dsqrt(px))
end do
computeeigenfunctions_ydrv_x = unity

! return value to the main program

return
end function computeeigenfunctions_ydrv_x
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computeeigenvalues_x()
use global_data, only : m0, eigenvalues_x, l2
use constants, only : pi, unity
! this function compute the eigenvalues
implicit none
integer(long) :: m
real(double) :: computeeigenvalues_x
do m = 1, m0
eigenvalues_x(m) = real(2*m-1)*pi/(2.d0*l2) ! compute the eigenvalues
end do
computeeigenvalues_x = unity ! return value to the main program
return
end function computeeigenvalues_x
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computeeigenvaluessquared_x()
use global_data, only : m0, eigenvalues_x, eigenvaluessquared_x
use constants, only : unity
! this function compute the eigenvalues squared
implicit none
integer(long) :: m

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

151

Fortran 90/95
real(double) :: computeeigenvaluessquared_x
do m = 1, m0
! compute the eigenvalues squared
eigenvaluessquared_x(m) = eigenvalues_x(m)*eigenvalues_x(m)
end do
computeeigenvaluessquared_x = unity

! return value to the main program

return
end function computeeigenvaluessquared_x
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computeeigenconstants_x()
use global_data, only : m0, l2, eigenconstants_x
use constants, only : root_of_two, unity
! this function compute the eigenconstants
implicit none
integer(long) :: m
real(double) :: computeeigenconstants_x
do m = 1, m0
eigenconstants_x(m) = root_of_two/dsqrt(l2) ! compute the eigenconstants
end do
computeeigenconstants_x = unity

! return value to the main program

return
end function computeeigenconstants_x
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computeeigenfunctions_x(x)
use global_data, only : m0, eigenvalues_x, eigenfunctions_x, eigenconstants_x
use constants, only : root_of_two, unity
! this function computes the eigenfunctions
implicit none
integer(long) :: m
real(double) :: x, computeeigenfunctions_x
do m = 1, m0
! compute the eigenfunctions at the position (x,y)
eigenfunctions_x(m) = eigenconstants_x(m)*dsin(eigenvalues_x(m)*x)
end do
computeeigenfunctions_x = unity
return
end function computeeigenfunctions_x
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function computeeigenfunctions_xdrv_x(x)
use global_data, only : m0, l2, eigenvalues_x, eigenfunctions_xdrv_x, &
eigenconstants_x

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

152

Fortran 90/95
use constants, only : unity
! this function computes the eigenfunctions derivatives regarding y-axis
implicit none
integer(long) :: m
real(double) :: computeeigenfunctions_xdrv_x, x
do m = 1, m0
! compute the eigenfunctions x-derivative at the position (x)
eigenfunctions_xdrv_x(m) = eigenconstants_x(m)*eigenvalues_x(m)* &
dcos(eigenvalues_x(m)*x)
end do
computeeigenfunctions_xdrv_x = unity
return
end function computeeigenfunctions_xdrv_x
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function eigenfunctions_x_v2(m,x)
use global_data, only : m0, eigenvalues_x, eigenconstants_x
! this function computes the eigenfunctions
implicit none
integer(long) :: m
real(double) :: x, eigenfunctions_x_v2
! compute the eigenfunctions at the position (x,y)
eigenfunctions_x_v2 = eigenconstants_x(m)*dsin(eigenvalues_x(m)*x)
return
end function eigenfunctions_x_v2
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function eigenfunctions_xdrv_x_v2(m,x)
use global_data, only : m0, l2, eigenvalues_x, eigenconstants_x
use constants
! this function computes the eigenfunctions derivatives regarding y-axis
implicit none
integer(long) :: m
real(double) :: eigenfunctions_xdrv_x_v2, x
! compute the eigenfunctions x-derivative at the position (x)
eigenfunctions_xdrv_x_v2 = eigenconstants_x(m)*eigenvalues_x(m)* &
dcos(eigenvalues_x(m)*x)
return
end function eigenfunctions_xdrv_x_v2
end module eigenproblem

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

153

Fortran 90/95
module fbfcfd
use data_type
use constants
implicit none
contains
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function fb(x)
use ijmn_transfer, only : m,n
use aiibijcij_x, only : computebij_x
use eigenproblem, only : eigenfunctions_x_v2, eigenfunctions_xdrv_x_v2
implicit none
real(double) :: x, fb
fb = computebij_x(x)*eigenfunctions_x_v2(m,x)*eigenfunctions_xdrv_x_v2(n,x)
end function fb
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function fc(x)
use ijmn_transfer
use aiibijcij_x, only : computecij_x
use eigenproblem, only : eigenfunctions_x_v2
implicit none
real(double) :: x, fc
fc = computecij_x(x)*eigenfunctions_x_v2(m,x)*eigenfunctions_x_v2(n,x)
end function fc
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function fd(x)
use ijmn_transfer
use eigenproblem, only : eigenfunctions_x_v2
use wall_functions, only : p
implicit none
real(double) :: x, fd
fd = eigenfunctions_x_v2(m,x)*eigenfunctions_x_v2(n,x)/(p(x)**2)
end function fd
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function fg(x)
use ijmn_transfer
use eigenproblem, only : eigenfunctions_x_v2
use wall_functions, only : p
use aiibijcij_x, only : computegi_x
implicit none
real(double) :: x, fg

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

154

Fortran 90/95
fg = computegi_x(x)*eigenfunctions_x_v2(m,x)
end function fg
end module fbfcfd

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

155

Fortran 90/95
module grid
use data_type
use constants
implicit none
contains
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function basicgrid()
use velocity_field_data, only : mx, my, xpos, ypos
integer(long) :: i, j
real(double) :: basicgrid, x, y
do i = 1, my
y = real(i-1)/real(my-1)
do j = 1, mx
x = real(j-1)/real(mx-1)
xpos(i,j) = x
ypos(i,j) = y
end do
end do
basicgrid = unity
return
end function basicgrid
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function modifiedgrid()
use velocity_field_data, only : mx, my, xpos, ypos
use global_data, only : l2
use wall_functions, only : p
integer(long) :: i, j
real(double) :: modifiedgrid
do i = 1,my
do j = 1,mx
xpos(i,j) = xpos(i,j)*l2
ypos(i,j) = ypos(i,j)*p(xpos(i,j))
end do
end do
modifiedgrid = unity
return
end function modifiedgrid
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function fieldsstreamfunctionvelsuv()
use velocity_field_data, only : mx, my, xpos, ypos
use velocity_field_data, only : psi, u, v
use global_data, only : m0
use global_data, only : eigenfunctions_y, eigenfunctions_x
use global_data, only : eigenfunctions_ydrv_y, eigenfunctions_ydrv_x

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

156

Fortran 90/95
use global_data, only : eigenfunctions_xdrv_x

use wall_functions, only : p, deriv_p


use sist_lin_data, only : yim
use eigenproblem, only : computeeigenfunctions_y, computeeigenfunctions_x
use eigenproblem, only : computeeigenfunctions_ydrv_y, computeeigenfunctions_ydrv_x
use eigenproblem, only : computeeigenfunctions_xdrv_x
integer(long) :: s, t, i, m
real(double) :: fieldsstreamfunctionvelsuv, x , y, void, px, dpx
real(double) :: soma_psi, soma_u, soma_v
do s = 1,my
do t = 1,mx
x = xpos(s,t)
y = ypos(s,t)
px = p(x)
dpx = deriv_p(x)
void = computeeigenfunctions_y(x,y)
void = computeeigenfunctions_x(x)
void = computeeigenfunctions_ydrv_y(x,y)
void = computeeigenfunctions_ydrv_x(x,y)
void = computeeigenfunctions_x(x)
soma_psi = 0.d0
soma_u = 0.d0
soma_v = 0.d0
do i = m0, 1, -1
do m = m0, 1, -1
soma_psi = soma_psi + yim(i,m)*eigenfunctions_y(i)*eigenfunctions_x(m)
soma_u = soma_u + yim(i,m)*eigenfunctions_ydrv_y(i)*eigenfunctions_x(m)
soma_v = soma_v+yim(i,m)*(eigenfunctions_ydrv_x(i)*eigenfunctions_x(m)+&
eigenfunctions_y(i)*eigenfunctions_xdrv_x(m))
end do
end do
psi(s,t) = soma_psi + y/px
u(s,t) = soma_u + 1.d0/px
v(s,t) = -soma_v + y*dpx/(px**2)
end do
end do
fieldsstreamfunctionvelsuv = unity
end function fieldsstreamfunctionvelsuv
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function axialquantities()
use velocity_field_data, only : mx, my, xpos
use velocity_field_data, only : u, v

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

157

Fortran 90/95
use velocity_field_data, only : uw, vw, pw, u0, v0, p0, x_axis
integer(long) :: t
real(double) :: axialquantities, x
do t = 1,mx
x = xpos(1,t)
x_axis(t) = x
u0(t) = u(1,t)
v0(t) = v(1,t)
p0(t) = unity - u0(t)*u0(t) - v0(t)*v0(t)
uw(t) = u(my,t)
vw(t) = v(my,t)
pw(t) = unity - uw(t)*uw(t) - vw(t)*vw(t)
end do
axialquantities = unity
end function axialquantities
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function averagevelocityu()
use velocity_field_data, only : mx, my, xpos
use velocity_field_data, only : u, uav
use wall_functions, only : p
use integrationlib, only : simpson
integer(long) :: s, t
real(double) :: averagevelocityu, x, px, delta_y, result
real(double), dimension(my) :: aux_uav
do t = 1,mx
x = xpos(1,t)
px = p(x)
delta_y = px/real(my-1)
do s = 1, my
aux_uav(s) = u(s,t)
end do
call simpson(my,aux_uav,delta_y,result)
uav(t) = result/px
end do
averagevelocityu = unity
end function averagevelocityu
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function averagevelocityv()
use velocity_field_data, only : mx, my, xpos
use velocity_field_data, only : v, vav

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

158

Fortran 90/95
use wall_functions, only : p
use integrationlib, only : simpson
integer(long) :: s, t
real(double) :: averagevelocityv, x, px, delta_y, result
real(double), dimension(my) :: aux_vav
do t = 1,mx
x = xpos(1,t)
px = p(x)
delta_y = px/real(my-1)
do s = 1, my
aux_vav(s) = v(s,t)
end do
call simpson(my,aux_vav,delta_y,result)
vav(t) = result/px
end do
averagevelocityv = unity
end function averagevelocityv
end module grid

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

159

Fortran 90/95
module ijmn_transfer
use data_type
implicit none
save
integer(long) :: i, j, m, n
end module ijmn_transfer

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

160

Fortran 90/95
module integrationlib
implicit none
contains
!=========================
! this routine computes a integral algorithm using simpson's rule...
!====================
subroutine simpson(n,vet,delta,result)
use data_type
use constants
implicit none
integer(long) :: i, n !n must be odd.
real(double) :: delta, result, summ, summ2, summ4
real(double), dimension(n) :: vet
summ2=zero_real
summ4=zero_real
do i=2,n-1,2
summ4=summ4+vet(i)
end do
do i=3,n-2,2
summ2=summ2+vet(i)
end do
summ=vet(1)+4.d0*summ4+2.d0*summ2+vet(n)
result=delta*summ/3.d0
return
end subroutine simpson
end module integrationlib

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

161

Fortran 90/95
module outputwriting
use data_type
use constants
contains
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function printing()
use velocity_field_data, only : u, v, psi, mx, my, xpos, ypos
use velocity_field_data, only : uw, vw, pw, u0, v0, p0, uav, vav, x_axis
use wall_functions
use global_data, only : l2

implicit none
integer(long) :: s, t
real(double) :: x, y, aux, printing
open(unit = 10, file='u.dat',status = 'unknown')
!open(unit = 20, file='v.dat',status = 'unknown')
open(unit = 30, file='psi.dat',status = 'unknown')
open(unit = 40, file='uwvwpw.dat',status = 'unknown')
open(unit = 50, file='ppxdpx.dat',status = 'unknown')
write(10,*)'variables = "x", "y", "u"'
write(10,*)'zone i=',mx,', j=',my,', f=point'
!write(20,*)'variables = "x", "y", "v"'
!write(20,*)'zone i=',mx,', j=',my,', f=point'
write(30,*)'variables = "x", "y", "psi"'
write(30,*)'zone i=',mx,', j=',my,', f=point'
!write(40,*)'variables = "x", "uw", "vw", "pw", "u0", "v0", "p0", "px", "ipx", "dpx", "d2dpx"'
!write(40,*)'zone i=',mx,', f=point'
write(50,*)'zone i=',mx,', f=point'
do s = 1,my
do t = 1,mx
x = xpos(s,t)
y = ypos(s,t)
write(10,100) x, y, u(s,t), v(s,t)
!write(20,*) x, y, v(s,t)
write(30,*) x, y, psi(s,t)
100 format(1x,4(f14.7,1x))
end do
end do
do t = 1,mx
aux = x_axis(t)
!write(40,10)x_axis(t), uw(t), vw(t), pw(t), u0(t), p0(t), &
!
1.d0/p(aux), deriv_p(aux), vav(t)
write(40,10)x_axis(t)/l2, uw(t), vw(t), pw(t), u0(t)
10 format(1x, 9(f8.4,1x))

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

162

Fortran 90/95
end do
do t = 1,mx
aux = x_axis(t)
write(50,20)x_axis(t), p(aux), v0(t), p0(t), &
1.d0/p(aux), uav(t), deriv_p(aux), vav(t)
20 format(1x, 8(f9.4,1x))
end do

close(10)
!close(20)
close(30)
close(40)
close(50)
printing = unity
return
end function printing
end module outputwriting

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

163

Fortran 90/95
module wall_functions
use data_type
implicit none
contains
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function p(x)
use global_data, only : l1, l2, l3
! this function computes the value of p(x)
implicit none
real(double) :: p, aux, aux2
real(double), intent(in) :: x
aux = x/l2
aux2 = aux*aux
p = l1 + (l3-l1)*(3.d0 - 2.d0*aux)*aux2 ! return the value of p(x)
!write(*,*) "p = ", p
return
end function p
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function deriv_p(x)
use global_data, only : l1, l2, l3
! this function computes the derivative value of p(x)
implicit none
real(double) :: deriv_p, aux, aux2
real(double), intent(in) :: x
aux = x/l2
aux2 = aux*aux
! return the value of p(x) derivative
deriv_p = 6.d0*(l3-l1)*(1 - aux)*aux/l2
!write(*,*) "dp = ", deriv_p
return
end function deriv_p
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function deriv2nd_p(x)
use global_data, only : l1, l2, l3
! this function computes the derivative value of p(x)
implicit none
real(double) :: deriv2nd_p, aux
real(double), intent(in) :: x
aux = x/l2
! return the value of p(x) derivative
deriv2nd_p = 6.d0*(l3-l1)*(1.d0 - 2.d0*aux)/(l2*l2)
!write(*,*) "d2p = ", deriv2nd_p

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

164

Fortran 90/95
return
end function deriv2nd_p
end module wall_functions

Verso primeira de janeiro 1999. Versao atual impressa (*.pdf) em 22 de agosto de 2013
Autor: Joo Batista Aparecido jbaparecido@dem.feis.unesp.br e jbaparecido@gmail.com

165

Das könnte Ihnen auch gefallen