Beruflich Dokumente
Kultur Dokumente
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
Unidades
de sada de
dados
Unidade de controle
Memria
principal
Unidade de lgica aritmtica
Memria
secundria
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
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
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
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
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
ou
logical :: w = .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
12
Fortran 90/95
character :: r,s
character(12) :: t,q
x = Joseh da Silva
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
adio
subtrao
multiplicao
diviso
exponenciao
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.
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 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.
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)
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
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
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
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
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
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
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
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
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
26
Fortran 90/95
end program exiting
D nomes aos principais laos no programa para deixar claro quais declaraes
executveis pertencem a um determinado lao.
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
ou r(Iw.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
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)
r(Ew.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
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
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
ou r(Aw)
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
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.
33
Fortran 90/95
As regras de formatao de declaraes READ so semelhantes s de declaraes
WRITE.
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)
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)
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)
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
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./)
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
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)
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
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
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
:
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)
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)
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
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
47
Fortran 90/95
trinca_1 = indice_1 : indice_2 : incr
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)
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)
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
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.
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
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
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
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
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
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
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
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
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)
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)
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
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
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
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)
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
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
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
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
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
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
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
real(simples), intent(in) :: a, b
real(simples), intent(out) :: c
end subroutine soma3
subroutine soma4(a, b, c)
use tipo_dado
implicit none
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
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
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
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
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
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
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)
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)
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
!Redefinindo a matriz, x
!Redefinindo a matriz, y
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)
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
!
!
!
!
!
!
!
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 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
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
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
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
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
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
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
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
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
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
! 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
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
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
computeeigenconstants_y = unity
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
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
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)
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
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
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
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
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