Apostila_F9095_jba

Embed Size (px)

Citation preview

Fortran 90/95Joo Batista Aparecido [email protected]

Dezembro 1999

PREFCIO Comecei a programar em Fortran em 1977 ainda no curso de graduao em Engenharia Mecnica. O computador no caso tratava-se de um IBM-1130 com 8k de memria RAM. Desde ento tenho programado em Fortran. As pessoas no Brasil que programam usando Fortran em geral ainda praticam o padro 77. Este texto procura dar uma viso geral do atual padro da linguagem Fortran, o padro 90 j amplamente difundido nos compiladores disponveis dos principais fabricantes, tal como Microsoft, Lahey e Digital, bem como do padro 95 ainda pouco difundido.

PREFCIO CAPTULO 1 - INTRODUO LINGUAGEM FORTRAN 1.1 - O COMPUTADOR 1.1.1 - A CPU1.1.2 Memria principal e memria secundria. 1.1.3 Unidades de entrada e sada de dados. 1.2 - Representao de dados em um computador. 1.2.1 - O sistema binrio de nmeros. 1.2.2. - Tipos de dados que o Fortran 90 armazena na memria. 1.2.2.1. Dados inteiros 1.2.2.2. Dados reais 1.2.2.3. Dados alfanumricos 1.3 Linguagens de computador. 1.4 - Histria do Fortran

2 9 9 910 10 10 10 11 11 11 12 12 13

CAPTULO 2 - ELEMENTOS BSICOS DO FORTRAN 902.1 O conjunto de caracteres do Fortran 90. 2.2 A estrutura de uma declarao Fortran 90. 2.2.1 Formato livre do cdigo fonte. 2.3 A estrutura de um programa Fortran 90. 2.3.1 Estilo de programao 2.3.2. Primeiro programa em Fortran 90 2.4 Constantes e Variveis 2.4.1. Constantes e variveis inteiras 2.4.2. Constantes e variveis reais 2.4.3. Constantes e variveis lgicas 2.4.4. Constantes e variveis alfanumricas 2.4.5. Definindo variveis inteiras ou reais por Default ou explicitamente. 2.4.6. Mantendo as constantes consistentes em um programa

1414 14 14 15 15 15 16 16 17 17 17 18 18

2.5 Declarao de atribuio e clculos aritmticos 2.5.1 Aritmtica inteira 2.5.2 Aritmtica real 2.5.3. Hierarquia das operaes 2.5.4 Aritmtica mista 2.5.5. Aritmtica mista e exponenciao 2.6 Declarao de atribuio e clculos lgicos 2.6.1 Operadores relacionais lgicos 2.6.2 Operadores combinatoriais lgicos 2.7 Declarao de atribuio e variveis do tipo caracter 2.7.1 Sub-especificao de variveis do tipo caracter 2.7.2 Operador de concatenao 2.7.3. Operadores relacionais lgicos com variveis do tipo caracter 2.8 Funes intrnsecas 2.9 Declaraes de entrada e sada de dados 2.10 Inicializao de variveis 2.11 Declarao IMPLICIT NONE

18 19 19 19 20 20 21 21 22 22 23 23 23 24 25 25 26

CAPTULO 3 - ESTRUTURAS DE CONTROLE3.1 Estruturas de controle: bifurcaes 3.1.1. Estrutura do tipo bloco IF 3.1.2. Estrutura do tipo ELSE e ELSE IF 3.1.3. Estrutura do tipo IF, nomeado 3.1.4 Declarao IF lgico 3.1.5 A estrutura CASE 3.2 Estruturas de controle: laos 3.2.1. O lao com terminao indefinida 3.2.2. Outra implementao do lao com terminao indefinida 3.2.3. O lao com terminao bem definida 3.2.4. As declaraes CYCLE e EXIT

2727 27 27 28 29 29 30 30 31 31 32

3.2.5 Laos nomeados 3.2.6. Ninho de laos

33 34

CAPTULO 4 - CONCEITOS BSICOS DE ENTRADA E SADA DE DADOS 354.1 Descritores de formato 4.1.1 Sada de dados inteiros: O descritor I 4.1.2 Sada de dados reais: O descritor F 4.1.3 Sada de dados reais: O descritor E 4.1.4 Sada de dados reais: O descritor ES 4.1.5 Sada de dados lgicos: O descritor L 4.1.6 Sada de dados caracter: O descritor A 4.1.7 Posicionamento horizontal: Os descritores X e T 4.1.8 Trocando as linhas de sada: O descritor slash (/) 4.1.9. Declaraes READ formatadas 4.2. Introduo a arquivos e processamento de arquivos 4.2.1 A declarao OPEN 4.2.2 A declarao CLOSE 4.2.3 READs e WRITEs a arquivos em disco 4.2.4 O uso da especificao IOSTAT= nas declaraes READ 4.2.5 Posicionamento em arquivos 35 35 36 36 37 37 38 38 39 40 40 41 42 42 42 43

CAPTULO 5 - ARRAYS5.1 Declarando arrays 5.2 Usando elementos de array em declaraes Fortran 5.2.1 Usando elementos de array em declaraes Fortran 5.2.2 Inicializando elementos de array 5.2.3 Modificando a faixa de subscritos de um array 5.2.4 Subscritos de array fora da faixa de definio 5.2.5 O uso de constantes com declarao de arrays 5.3 Usando arrays completos e sub-conjuntos de arrays

4444 45 45 45 46 46 47 47

5.3.1 Operaes com arrays completos 5.3.2 Definindo e operando com subconjuntos de arrays 5.3.3 Reformatando arrays 5.4 Usando funes intrnsecas Fortran com arrays 5.4.1 Funes intrnsecas elementares 5.4.2 Funes intrnsecas de questionamento 5.4.3 Funes intrnsecas de transformao 5.5 Atribuio de arrays com mscara: a estrutura WHERE 5.5.1 A estrutura WHERE do Fortran 90 5.5.2 A estrutura WHERE do Fortran 95 5.5.3 A declarao WHERE 5.6. A estrutura FORALL 5.6.1 A forma da estrutura FORALL 5.7. Arrays alocveis

47 49 50 51 51 51 52 53 53 53 54 54 54 54

CAPTULO 6 - FUNES E SUBROTINAS6.1 Subrotinas 6.1.1 O atributo INTENT 6.1.2 Passando arrays para subrotinas 6.1.3 Passando variveis caracter para subrotinas 6.2 A declarao e o atributo SAVE 6.3 Arrays automticos 6.4 Compartilhando dados usando mdulos (modules) 6.5 Sub-programas mdulo 6.5.1 Usando mdulos para criar interfaces explicitas 6.5.2 Passando arrays para subrotinas usando mdulos e arrays de forma assumida. 6.6 Funes Fortran 90/95 6.7 Funes puras (pure functions) e funes elementares (elemental functions) 6.7.1 Funes puras (pure functions) 6.7.2 Funes elementares (elemental functions)

5758 60 62 64 65 65 66 67 68 69 71 72 72 73

6.8 Passando subprogramas como argumentos para outros subprogramas 6.8.1 Passando funes como argumento

73 73

CAPTULO 7 - OUTROS TIPOS DE DADOS7.1 Outros tamanhos de dados para variveis do tipo real 7.1.1 Tamanhos (kinds) de dados para variveis e constantes do tipo real 7.1.3 Definindo a preciso de uma varivel, independente do processador 7.1.4. Preciso dupla em funes intrnsecas 7.2 Outros tamanhos (kinds) de dados para variveis inteiras 7.3 O tipo de dados COMPLEX 7.3.1 Aritmtica mista com complexos 7.3.2 Utilizando operadores relacionais com complexos 7.4 Tipos de dados derivados 7.4.1 Acessando elementos de uma estrutura

7575 75 77 78 78 78 79 79 79 80

CAPTULO 8 - ASPECTOS AVANADOS DE FUNES, SUBROTINAS E MDULOS. 828.1 Subprogramas internos 8.2 Escopo de variveis e constantes 8.3 Subprogramas recursivos 8.4 Argumentos com palavras-chave e argumentos opcionais. 8.5 Interfaces para subprogramas e blocos de interfaces 8.5.1. Criando blocos de interface 8.6 Subprogramas genricos 8.6.1 Subprogramas genricos definidas pelo programador 8.6.2 Interfaces genricas para subprogramas em mdulos 8.7 Estendendo o Fortran com declaraes e operadores definidos pelo programador 8.8 Restringindo acesso ao contedo de um mdulo 8.9 Opes avanadas da declarao USE 82 82 84 85 88 88 90 90 92 93 98 98

CAPTULO 9 - PONTEIROS E ESTRUTURAS DINMICAS DE DADOS 1009.1 Ponteiros e alvos 100

9.1.1 Declarao de atribuio de ponteiro 9.1.2 Situao de um associao ponteiro-alvo 9.2 Usando ponteiros em declaraes de atribuio 9.3 Alocao dinmica de memria usando ponteiros 9.4 Usando ponteiros com estruturas derivadas de dados

101 101 102 103 104

CAPTULO 10 - PONTEIROS E ESTRUTURAS DINMICAS DE DADOS11410.1 Ponteiros e alvos 10.1.1 Declarao de atribuio de ponteiro 10.1.2 Situao de um associao ponteiro-alvo 10.2 Usando ponteiros em declaraes de atribuio 10.3 Alocao dinmica de memria usando ponteiros 10.4 Usando ponteiros com estruturas derivadas de dados 114 115 115 116 117 118

REFERNCIAS

128

Captulo 1 - Introduo linguagem FortranO 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 vinte 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 diz a ele qual seqncia de clculo necessria e em quais dados executar as instrues. 1.1 - O computador Na Figura 1.1 mostra-se um diagrama de bloco de um computador tpico, constitudo pela Unidade de Processamento Central (CPU-Central Processing Unit), pela memria principal, pela memria secundria, e pelas unidades de entrada e sada de dados.Unidade de processamento central

Unidades de entrada de dados

Memria interna (registros)

Unidades de sada de dados

Unidade de controle

Memria principal Unidade de lgica aritmtica

Memria secundria

Figura 1.1- Esquema de um computador. 1.1.1 - A CPU A parte principal do computador a Unidade de Processamento Central (CPU-Central Processing Unit). Ela constituda pela Unidade de Controle, que controle as outras partes do computador; pela Unidade de Lgica Aritmtica (ALU-Arithmetic Logic Unit); e pelas memrias internas (tambm conhecidas como registros). 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

Forttran 90//95 For ran 90 95que estes dados no so mais necessrios na CPU eles so armazenados na memria principal ou secundria. 1.1.2 Memria principal e memria secundria. 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 a mais rpida e a mais cara. Uma das caractersticas deste tipo de memria sua volatilidade, sendo usada para armazenar programas e dados a serem processados. As memrias secundrias so mais lentas e mais baratas, alguns exemplos so: disquetes, fitas magnticas e discos rgidos. So em geral no-volteis e podem armazenar, permanentemente, grandes massas de dados a um custo mais baixo que as memrias principais. 1.1.3 Unidades de entrada e sada de dados. Dados so introduzidos no computador via teclado, microfone, unidades de disco, unidades de fita, scanners, e placas de aquisio de dados. Os dados podem sair do computador via impressora, tela, plotter, e auto-falante. 1.2 - Representao de dados em um computador. A memria de um computador constituda de chaves que podem estar apenas nos estados ligado (on) e desligado (off). Cada chave ento representa apenas um dgito 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. Da conclumos que a representao interna do computador binria. 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 que o byte a palavra (word), que pode usar 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. Pode-se representar nmeros em diferentes bases, por exemplo o nmero 354 no sistema decimal pode ser escrito como segue na bases binria 35410 = 3 10 2 + 5 101 + 4 10 0 = = 1 2 8 + 0 2 7 + 1 2 6 + 1 2 5 + 0 2 4 + 0 2 3 + 0 2 2 + 1 21 + 0 2 0 O maior nmero que pode ser representado em um byte 11111111 que corresponde ao nmero 255 (28-1)na base 10, que em geral atravs de translaes leva a nmeros variando de 128 a +127. Da mesma forma com dois bytes pode-se

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

10

Forttran 90//95 For ran 90 95representar nmeros de 32.768 a +32.767 (65.535 = 216-1). At o momento discutimos apenas o armazenamento na memria de nmeros inteiros, na prxima seo veremos outros tipo de dados. Quando entramos via teclado com um nmero decimal em um programa Fortran, este nmero ento convertido para o sistema de armazenamento natural do computador, o binrio. Quando o computador vai imprimir um nmero, ele converte o nmero que est no sistema binrio para decimal e imprime. Como o sistema decimal pode ser convertido em binrio, outros sistemas de nmeros tambm podem ser convertidos para binrios e vice-versa. Os outros sistemas de nmeros que o Fortran 90 suporta so o Octal (base 8) e o Hexadecimal (base 16). Desta forma o nmero 77 decimal pode ser representado da seguinte maneira nas diferentes bases

7710 = 10011012 = 1158 = 4 D16 .1.2.2. - Tipos de dados que o Fortran 90 armazena na memria.

Manipulando-se a quantidade de bytes que se utiliza e o tipo de uso feito destes bytes em uma palavra pode-se armazenar na memria outros tipo de dados que no apenas inteiros. Os tipo comuns de dados que se pode armazenar so: inteiros, reais, alfanumricos, complexos e lgicos. No momento trataremos apenas dos inteiros, reais e alfanumricos. Existe tambm os tipos de dados derivados a partir destes cinco tipos fundamentais, mais adiante voltaremos aos tipos derivados ou especiais.1.2.2.1. Dados inteiros

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 menor inteiro = -2n-1, onde n a quantidade de bits da palavra.1.2.2.2. Dados reais

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 na forma inteira, 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 8. No computador o sistema semelhante, apenas a base numrica binria ao invs de decimal. Os nmeros reais mais comuns nos processadores o real de 4 bytes ou 32 bits, dividido em duas partes, a mantissa com 24 bits e o expoente com 8 bits. A mantissa contm um nmero entre 1 e +1 e o expoente contm uma potncia de 2 suficientes para recuperar o valor do nmero representado, como segue

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

11

Forttran 90//95 For ran 90 95valor do numero = mantissa 2 exp oente .

Os dados do tipo real so caracterizados por dois indicadores: a preciso e a faixa. Preciso a quantidade dgitos significativos que so preservados em um nmero, e faixa a diferena entre o maior e o menor nmero que pode ser representado. A preciso depende do nmero de bits na mantissa e a faixa depende do nmero de bits no expoente. Uma mantissa com 24 bits pode armazenas nmeros de -223 e +223, aproximadamente. Convertendo para a base decimal tem nmeros de 107 a +107, ou seja com este tipo de representao a preciso que se obtm de aproximadamente 7 dgitos decimais. Um expoente com 8 bits pode representar nmeros entre 2-128 e 2128, ou seja entre 10-38 e 10+38. Note que o tipo real de dados pode representar nmeros muito maiores ou muito menores que o tipo inteiro pode, porm no caso de usar 4 bytes tem-se apenas uma preciso de 7 dgitos decimais. Neste caso impossvel distinguir qualquer diferena entre os nmeros 1234567.1 e o 1234567.2. Isto ocorre porque quando um nmero com mais de 7 dgitos decimais armazenado em um tipo real com mantissa de 24 bits, o dgitos alm do stimo estaro perdidos para sempre. Este o erro de arredondamento (round-off error).1.2.2.3. Dados alfanumricos

O tipo de dado alfanumrico (character) consiste de caracteres e smbolos. Um sistema tpico para representao de uma linguagem ocidental deve incluir os seguintes smbolos: 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 qualquer 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, 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 umaVerso preliminar. Escrito em 12/01/99. Impresso em 08/25/0512

Forttran 90//95 For ran 90 95linguagem 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 objeto orientadas (SmallTalk), as rotina orientadas (Fortran, Pascal e C), e as mistas (C++). Hoje, as linguagens dentro de cada grupo so muito parecidas na sua concepo geral, diferindo em detalhes e na sintaxe. 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. 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 passa por uma grande mudana. O Fortran 90 um superconjunto do Fortran 77 e estende a linguagens 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 (Microsoft, Lahey e Digital). Outro grande aspecto do Fortran 90 suportar processamento paralelo SIMD (Single Instruction Multiple Data). Em 1995 surgiu uma pequena atualizao do Fortran 90, o Fortran 95. Ainda no popular no Brasil (1999). Vamos nos dedicar prioritariamente ao Fortran 90, porm mostrando os aditivos feitos no Fortran 95.

Obsoleto

A forma fixa do cdigo fonte foi declarada obsolescente no Fortran 95, significando que candidata a ser deletada do padro nas futuras verses do Fortran.

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

13

Forttran 90//95 For ran 90 95Captulo 2 - Elementos Bsicos do Fortran 90Neste 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 86 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 26 letras minsculas a-z 10 nmeros 0-9 1 underscore _ 5 smbolos aritmticos +-*/** 17 smbolos variados ( ) . = , $ : ! % & ; < > ? branco2.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, as declaraes 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 obrigado o uso de labels, no Fortran 90 eles continuam existindo mas so praticamente desnecessrios. 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.

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

14

Forttran 90//95 For ran 90 95

Boa Prtica Evite Usar

Sempre use o cdigo fonte no formato livre quando escrevendo programas em Fortran 90/95.

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.

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 dizendo ao compilador onde o programa termina.2.3.1 Estilo de programao

Talvez a principal conveno (no obrigatria) de estilo em Fortran 90 seja usar letras maisculas para as palavras-chave, tais como: PROGRAM, READ, WRITE; e minsculas para todo o restante. O Fortran case insensitive, isto , no diferencia entre letras maisculas e minsculas. Como os compiladores atuais mostram na tela as palavras-chave em cor diferenciado do restante, vou usar preferencialmente letras minsculas nos programas.

Boa Prtica

Adote um estilo de programao e siga-o em todos os programas.

2.3.2. Primeiro programa em Fortran 90

Na Figura 2.1 apresenta-se um primeiro programa em Fortran 90 que contm os principais elementos de todo programa Fortran 90.!programador: joo batista aparecido !data: 03 de dezembro de 1999 program meu_primeiro_programa !Objetivo: !Mostrar alguns aspectos bsicos de um programa Fortran 90. !Somar dois nmeros reais x e y, colocar em uma varivel w, e imprimir. !declarao de variveis

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

15

Forttran 90//95 For ran 90 95real:: x,y,w !atribui valores a x e y x=2.0 y=3.0 w=x+y !imprime x,y e w write(*,*) ' x = ',x,' y = ',y,' w = ',w !termina o programa stop end program meu_primeiro_programa !soma x e y

Figura 2.1 Um programa Fortran 90 simples.2.4 Constantes e Variveis

Uma constante em Fortran um dado que definido antes do programa rodar, ou seja durante a compilao, e no ser alterado durante a execuo do programa. Uma varivel em Fortran um dado que podem mudar durante a execuo do programa. O valor de uma varivel Fortran pode ser ou no ser inicializado antes do programa ser executado. Quando o compilador Fortran encontra uma constante ou uma varivel ele reserva uma posio de memria para armazen-la. Uma varivel ou constante em Fortran possui nome nico e duas destas grandezas no podem ter o mesmo nome.

Boa Prtica Boa Prtica

Use nomes de variveis com algum significado sempre que possvel. Crie um dicionrio de dados (variveis e constantes) para cada programa, visando facilitar a manuteno.

2.4.1. Constantes e variveis inteiras

Conforme discutido anteriormente o tamanho (kind)de uma constante ou varivel inteira depende da quantidade de bits utilizado para armazenar a informao. Para declarar que uma varivel ou constante inteira numero_alunos procede-se da seguinte maneirainteger :: numero_alunos numero_alunos = 30

ou de uma forma mais econmicainteger :: numero_alunos = 30

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

16

Forttran 90//95 For ran 90 952.4.2. Constantes e variveis reais

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

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

Para declarar uma constante ou varivel real procede-se da seguinte formareal :: x x = 10.33

2.4.3. Constantes e variveis lgicas

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

oulogical :: w = .true.

2.4.4. Constantes e variveis alfanumricas

O tipo de dados character consiste de grupos de smbolos alfanumricos. Pode-se declara o tipo e atribuir valores a uma constante ou varivel caracter das seguintes maneirascharacter (len = 14) :: x, y, w character :: r,s character(12) :: t,q x = Joseh da Silva ! variaveis com 14 caracteres ! variaveis com 1 caracter ! variaveis com 12 caracteres

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

17

Forttran 90//95 For ran 90 95O 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.2.4.5. Definindo variveis inteiras ou reais por Default ou explicitamente.

Se no for definido o tipo de uma variveis, 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.

Boa Prtica

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.

2.5 Declarao de atribuio e clculos aritmticos

Clculos so feitos em Fortran 90 utilizando-se declaraes de atribuio do tiponome_da_variavel = expresso_aritmtica,

por exemplo k = k + 1. Os operadores aritmticos do Fortran 90 so + * / ** adio subtrao multiplicao diviso exponenciao

Os operadores aritmticos mencionados acima so operadores binrios significando que devem aparecer entre duas variveis tal comoa + b, a b, a*b, a/b, a**b,

adicionalmente os smbolos + e podem ocorrer como operadores unrios, significando que podem ser aplicados a apenas uma varivel, como segue

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

18

Forttran 90//95 For ran 90 95+a ou b.

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

Cuidado2.5.2 Aritmtica real

Preste ateno na aritmtica com inteiros. Diviso de inteiros sempre fornece resultados inesperados.

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 exemplo1./3. = 0.333333, 2./3. = 0.666666, 3./3. = 1., 4./3. = 1.333333.

Cuidado

Preste ateno na aritmtica com inteiros. 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.

Boa Prtica

Use parnteses o suficiente fazer que as equaes fiquem claras e simples para entender.

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

19

Forttran 90//95 For ran 90 952.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 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 a varivel continua 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 exemplo2.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. Uma soluo para este problema transformar (durante a operao) todos os valores inteiros para reais. Veremos como fazer isto mais adiante.

Cuidado

Expresses do tipo misto so perigosas por que so difceis de entender e podem produzir resultados enganosos. Evite-as sempre que possvel.

2.5.5. Aritmtica mista e exponenciao

Existe uma situao onde a aritmtica mista desejvel, na exponenciao. Se temos uma expressow = y**n

onde y um real negativo e n um inteiro. Os compiladores atuais interpretam esta expresso como: tome o valor y e multiplique-o por si mesmo n vezes. Por outro lado se temos a seguinte expressow = y**x

onde y real negativo e x tambm real, esta expresso ser calculada internamente no computador da seguinte forma w = exp(x*lny),Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/0520

Forttran 90//95 For ran 90 95como 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.

Boa Prtica Cuidado

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 nome_da_variavel_logica = expresso_logica 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 5 = .false.; 3=, , = e =1) then call fatorial(i-1,aux) x = i*aux else x=1 end if return end subroutine fatorial

No caso de definio de funes recursivas existe um complicao extra. Como j vimos anteriormente para invocar uma funo necessrio que ela esteja em uma

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

84

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

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

8.4 Argumentos com palavras-chave e argumentos opcionais.

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

Forttran 90//95 For ran 90 95associao correta, mesmo com o argumentos embaralhados na lista. Um argumento nomeado um argumento com a seguinte formapalavra_chave = argumento_verdadeiro

onde palavra_chave o nome do argumento que est sendo associado com o argumento verdadeiro. Se a invocao do 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 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

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

86

Forttran 90//95 For ran 90 95saber 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 dos 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 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

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

87

Forttran 90//95 For ran 90 95O programa acima capaz de suportar e identificar os argumentos fora de ordem, se existe algum argumento ausente, e se existe algum, consegue identificar qual. Evidentemente, se existe algum argumento faltando necessrio executar procedimentos compatveis. Assim implementou-se algumas somas que levaram em considerao apenas os argumentos presentes.8.5 Interfaces para subprogramas e blocos de interfaces

Conforme j foi dito anteriormente desejvel que o programador coloque as subrotinas e funes dentro de um mdulo, de tal forma que tenham automaticamente uma interface explicita. No entanto nem sempre possvel colocar-se estas informaes dentro de um mdulo. So vrias as situaes: imagine um conjunto de rotinas que no se tm o cdigo fonte para fazer as modificaes; ou uma biblioteca antiga e muito grande que ficaria muito cara re-escreve-la novamente; ou ainda uma biblioteca escrita em outra linguagem. Desta forma til alguma ferramenta que permita a construo de interfaces explicitas sem necessariamente ter que mexer no cdigo original. A maneira de se fazer isto utilizando blocos de interface.8.5.1. Criando blocos de interface

Os blocos de interface so criados no programa que invoca os subprogramas, colocados na seo de declarao de variveis. Uma interface criada duplicando as informaes das declaraes de atributo de todas as variveis da lista de argumentos, e colocadas entre as declaraes INTERFACE e END INTERFACE. A forma geral para criar um bloco de interface interface subroutine nome_da_subrotina (lista_argumentos) declaracoes_de_atributos_dos_argumentos end subroutine nome_da_subroutine function nome_da_function (lista_argumentos) declaracoes_de_atributos_dos_argumentos end function nome_da_function end interface

A forma mostra 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.program interface_explicita implicit none !Definindo o bloco de interface interface subroutine sub1(r,s,t,u) implicit none

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

88

Forttran 90//95 For ran 90 95real, 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

Estes 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.

Boa Prtica

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.89

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

Forttran 90//95 For ran 90 95

Boa Prtica8.6 Subprogramas genricos

Se for necessrio criar vrios blocos de interface, ento coloque os dentro de mdulo e as acesse via uma declarao USE.

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 que temos vrias rotinas capazes de somar dois dados de diferentes tipos e tamanhos, e queremos produzir apenas um rotina que seja capaz de operar sobre todos os tipos 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) !Interface da subrotina que soma inteiros longos use tipo_dado implicit none integer(longo), intent(in) :: a,b

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

90

Forttran 90//95 For ran 90 95integer(longo), intent(out) :: c end subroutine soma2 subroutine soma3(a,b,c) !Interface da subrotina que soma reais simples 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 !Interface da subrotina que soma reais duplos

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

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

91

Forttran 90//95 For ran 90 95implicit none 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

Boa Prtica

Use blocos de interface genricos para definir subprogramas que podem operam com tipos de dados variveis. Subprogramas genricos facilitam operaes com diferentes tipos de dados.

8.6.2 Interfaces genricas para subprogramas em mdulos

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

onde procedure lista_nome_procedure a lista de subprogramas que compe funo genrica. Para o caso mostrado no programa acima, a interface genrica para a subrotina soma deve ser da seguinte formainterface soma module procedure soma1 module procedure soma2 module procedure soma3 module procedure soma4 end interface

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

92

Forttran 90//95 For ran 90 95O 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

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 novas 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, como a devida imaginao possvel dar novos sentidos para adio, subtrao, multiplicao, diviso e comparaes de dados derivados. Como isto pode ser feito? O primeiro passo construir um subprograma que execute o desejado e coloc-lo em um mdulo. O segundo passo associar este subprograma com um operador (smbolo) usando um bloco de interface de operador. A forma desta interface interface operator (simbolo_do_operador) module procedure nome_da_function end interface

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

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

93

Forttran 90//95 For ran 90 95Pode-se estender tambm o sentido da declarao de atribuio (=) de uma maneira similar. Para se fazer isto utiliza-se o bloco interface de atribuio, que tem a seguinte formainterface assignment (=) module procedure nome_subroutine end interface

Para o operador de atribuio a interface deve ter uma subrotina ao invs de uma function. A subrotina dever ter dois argumentos O primeiro o argumento de sada e deve ter o atributo intent(out). O segundo o argumento de entrada e deve ter o atributo intent(in). O argumento da esquerda corresponde ao lado esquerdo da atribuio e o direito ao da direita.Use blocos de interface de operadores e de atribuio para criar novos operadores ou estender o significado dos j existentes para trabalhar com tipos de dados derivados. Uma vez tendo definido estes operadores fica muito mais fcil operar com este tipo de dados..

Boa Prtica

Abaixo apresenta-se uma aplicao executar operaes sobre um tipo de dado derivado que um vetor com trs componentes.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 * ! !IL 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

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

94

Forttran 90//95 For ran 90 95! 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.) 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

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

95

Forttran 90//95 For ran 90 95vector_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 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

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

96

Forttran 90//95 For ran 90 95FUNCTION 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: 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. /)

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

97

Forttran 90//95 For ran 90 95vec_2 = (/ -1., 1., 1. /) WRITE (*,*) vec_1, vec_2, vec_1*vec_2 END PROGRAM test_vectors

8.8 Restringindo acesso ao contedo de um mdulo

At o momento todos os dados que foram colocados nos mdulos estavam totalmente disponveis e acessveis. No entanto as vezes no h interesse que determinados dados dos interior de um mdulo esteja disponvel fora do mdulo. Ento a questo : Como esconder alguns dados do interior de um mdulo? O Fortran dois atributos para tratar esta questo, o PUBLIC e o PRIVATE. Se declararmos uma varivel interna de um mdulo de PRIVATE, ela ficar totalmente indisponvel fora do ambiente do mdulo. Por outro lado ela continuar totalmente disponvel no interior do mdulo. O atributo PUBLIC o default e torna uma varivel totalmente disponvel, quer seja internamente ao mdulo quer seja externamente. Abaixo tem-se alguns exemplos de como efetuar esta declaraointeger, private :: conta real, public :: tension type (caixa), private :: caixa_sapato aconselhvel esconder qualquer dado ou subprograma de um mdulo que no precisem ser acessados de fora. A melhor maneira para ser fazer isto incluir o atribute PRIVATE em cada mdulo, e listar os itens especficos que se quer deixar visveis em uma declarao especfica com o atributo PUBLIC.

Boa Prtica

8.9 Opes avanadas da declarao USE

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

onde nome_do_modulo o nome do mdulo e lista_only a lista dos itens do mdulo a serem usadas. Nesta lista o 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.Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/0598

Forttran 90//95 For ran 90 95As formas de usar a declarao USE para permitir ao programador renomear algum dado ou subprograma souse nome_do_modulo, lista_para_renomear use nome_do_modulo, only: lista_para_renomear

onde lista_para_renomear toma a formanome_no_modulo => nome_local

Na declarao abaixouse data_fit, only : sp_real_least_square_fit => lsqfit

est utilizando-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 preliminar. Escrito em 12/01/99. Impresso em 08/25/05

99

Forttran 90//95 For ran 90 95Captulo 9 - Ponteiros e Estruturas Dinmicas de DadosPonteiros 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. 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 ponteirosreal, pointer :: 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. Pode 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 sointeger, dimension(:), pointer :: p_y real, pointer, dimension(:,:) :: p_w pointer, real, dimension(:,:,:) :: p_z Os ponteiros acima apontam para arrays rank 1, rank 2 e rank 3, respectivamente. Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05100

Forttran 90//95 For ran 90 95Para 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 alvoreal, target :: x integer, dimension(5), target :: y real, target, dimension(5,10) :: w 9.1.1 Declarao de atribuio de ponteiro

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

onde ponteiro o nome da varivel ponteiro que ir conter o endereo do alvo, e alvo a varivel apontada pelo ponteiro. Depois que um ponteiro foi associado a uma varivel alvo, qualquer referncia ao ponteiro em realidade uma referncia varivel alvo. Se um ponteiro est associado a uma varivel alvo e ento novamente associado a uma segunda varivel alvo, a primeira associao ser desfeita. Em outras palavras um ponteiro no pode apontar para dois alvos simultaneamente, no entanto um alvo pode ser apontado por um, dois ou mais ponteiros. Quando um alvo est sendo apontado por dois ponteiros e um dos ponteiros movido, o outro ponteiro no ser modificado. Um valor que est armazenado em uma varivel alvo pode ser obtido referenciado a varivel alvo ou ento referenciado o ponteiro que est apontado para ela. Um ponteiro pode apontar para outro ponteiro, neste caso em realidade os dois ponteiros estaro apontando para o mesmo alvo.

Boa Prtica

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.2 Situao de um associao ponteiro-alvo

A situao da associao de um ponteiro e 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 formatonullify(lista_de_ponteiros)

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

101

Forttran 90//95 For ran 90 95onde nullify ir desassociar todos os ponteiros lista na lista_de_ponteiros de todos os seus alvos. A situao de todos os ponteiros da lista passar ento para desassociados. Um ponteiro ter sua situao indefinida desde que 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 associado a 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 caractersticas que 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 argumentosvariavel_logica = associated(ponteiro, alvo)

a qual retornar a situao da associao de ponteiro e alvo.9.2 Usando ponteiros em declaraes de atribuio

Quando um ponteiro aparece em uma expresso aritmtica, no lugar de um valor numrico ento o valor da varivel para a qual ele est apontando usado. Quando se escrevep_x = p_y

o valor que est na varivel alvo apontada por p_y atribuda posio de memria da varivel alvo apontada por p_x. Adicionalmente, se escrevemosp_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 matrizesprogram usando_pointer !Objetivo: Mostrar o uso de ponteiros ! !programador: joo batista aparecido ilha solteira, 16 de dezembro, 1999 ! implicit none integer, parameter :: i_max = 100, j_max =100 integer :: i,j real :: aux

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

102

Forttran 90//95 For ran 90 95real, 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 p_y =>y !Atribuindo o ponteiro p_y x = 1.0 y = 5.0 !Inicializando a matriz, x !Inicializando a matriz, y

!Fazendo o swap das matrizes da forma clssica do i = 1, i_max do j = 1, j_max aux = x(i,j) x(i,j) = y(i,j) y(i,j) = aux end do end do !Fazendo o swap das matrizes usando ponteiros p_aux => p_x p_x => p_y p_y => p_aux stop end program usando_pointer

9.3 Alocao dinmica de memria usando ponteiros

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

onde ponteiro_1 o nome do primeiro ponteiro a ser alocado, e assim por diante, forma_do_ponteiro_1 a forma, 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 de zero e depender 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

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

103

Forttran 90//95 For ran 90 95chamado vazamento de memria. Por isto importante que memria que foi alocada usando ALLOCATE seja desalocada usando DEALLOCATE, da seguinte maneiradeallocate(ponteiro, stat = status)

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

!Fazendo o swap das matrizes usando ponteiros p_aux => p_x p_x => p_y p_y => p_aux deallocate(p_x, stat=status) !Desalocando memria deallocate(p_y, stat=status) !Desalocando memria deallocate(p_aux, stat=status)!Desalocando memria stop end program usando_pointer

9.4 Usando ponteiros com estruturas derivadas de dados

Pode-se colocar ponteiros dentro de estruturas derivadas de dados. Assim seja a seguinte estrutura derivada de dadostype :: real_value real :: value type(real_value), pointer :: p end type

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

104

Forttran 90//95 For ran 90 95Esta estrutura de dados acima toda vez que definida 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. Abaixo apresenta-se um exemplo de utilizao deste tipo de dados 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 ! Pointer to head of list CHARACTER(len=20) :: filename ! Input data file name INTEGER :: nvals = 0 ! Number of data read TYPE (real_value), POINTER :: ptr ! Temporary pointer TYPE (real_value), POINTER :: tail ! Pointer to tail of list INTEGER :: istat ! status: 0 for success REAL :: temp, aux ! Temporary variable ! Get the name of the file containing the input data. WRITE (*,*) 'Enter the file name with the data to be read: ' READ (*,'(A20)') filename ! open input data file. OPEN ( UNIT=9, FILE=filename, STATUS='OLD', ACTION='READ',IOSTAT = istat )

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

105

Forttran 90//95 For ran 90 95! Was the OPEN successful? fileopen: IF ( ISTAT == 0 ) THEN ! open successful ! The file was opened successfully, so read the data from ! it, and store it in the linked list. input: Do 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 ! No values in list ALLOCATE (head,STAT=istat) ! Allocate new value tail => head ! Tail pts to new value NULLIFY (tail%p) ! Nullify p in new value tail%value = temp ! Store number ELSE ! Values already in list ALLOCATE (tail%p,STAT=istat) ! Allocate new value tail => tail%p ! Tail pts to new value NULLIFY (tail%p) ! Nullify p in new value tail%value = temp ! Store number 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 ELSE fileopen ! Else file open failed. Tell user. WRITE (*,*) 'File open failed--status = ', istat END IF fileopen END PROGRAM

! Pointer valid? ! Yes: Write value ! Get next pointer

A seguir um exemplo de arquivo de dados para se testar o programa acima1.0 -2.0 3.0 -4.0 5.0 -6.0 7.0 -8.0 9.0

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

106

Forttran 90//95 For ran 90 95-10.000

A estrutura derivada de dados utilizada acima pode ser estendida para conter no seu interior vrios valores reais, inteiros, lgicos, caracteres, complexos, assim uma extenso nesta direo seria, por exemplo, o que seguetype :: 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

Um outro tipo de extenso, na estrutura de dados acima, incorporar mais de uma 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 seriatype :: various_values_and_two_pointers complex :: c1 integer :: int1, int2 real :: value1, value2, value3 character(20) :: nome1, nome2 logical :: logic1, logic2, logic3 type(various_values_and_two_pointers), pointer :: p1, p2 end type

Imagine-se uma arvore binria para armazenar e disponibilizar os primeiro, segundo e terceiro nomes de uma pessoa bem como o seu respectivo telefone. A seguir o programa que usa esta estrutura de dadosMODULE btree ! ! Purpose: ! To define the derived data type used as a node in the ! binary tree, and to define the operations >, ), OPERATOR() MODULE PROCEDURE greater_than END INTERFACE INTERFACE OPERATOR ( 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

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

108

Forttran 90//95 For ran 90 95! 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 ! 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

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

109

Forttran 90//95 For ran 90 95greater_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 ! 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 )

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

110

Forttran 90//95 For ran 90 95CALL 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 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) alvo

onde ponteiro o nome da varivel ponteiro que ir conter o endereo do alvo, e alvo a varivel apontada pelo ponteiro. Depois que um ponteiro foi associado a uma varivel alvo, qualquer referncia ao ponteiro em realidade uma referncia varivel alvo. Se um ponteiro est associado a uma varivel alvo e ento novamente associado a uma segunda varivel alvo, a primeira associao ser desfeita. Em outras palavras um ponteiro no pode apontar para dois alvos simultaneamente, no entanto um alvo pode ser apontado por um, dois ou mais ponteiros. Quando um alvo est sendo apontado por dois ponteiros e um dos ponteiros movido, o outro ponteiro no ser modificado. Um valor que est armazenado em uma varivel alvo pode ser obtido referenciado a varivel alvo ou ento referenciado o ponteiro que est apontado para ela. Um ponteiro pode apontar para outro ponteiro, neste caso em realidade os dois ponteiros estaro apontando para o mesmo alvo.

Boa Prtica

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.

10.1.2 Situao de um associao ponteiro-alvo

A situao da associao de um ponteiro e 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 formatonullify(lista_de_ponteiros)

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

115

Forttran 90//95 For ran 90 95onde nullify ir desassociar todos os ponteiros lista na lista_de_ponteiros de todos os seus alvos. A situao de todos os ponteiros da lista passar ento para desassociados. Um ponteiro ter sua situao indefinida desde que 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 associado a 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 caractersticas que 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 argumentosvariavel_logica = associated(ponteiro, alvo)

a qual retornar a situao da associao de ponteiro e alvo.10.2 Usando ponteiros em declaraes de atribuio

Quando um ponteiro aparece em uma expresso aritmtica, no lugar de um valor numrico ento o valor da varivel para a qual ele est apontando usado. Quando se escrevep_x = p_y

o valor que est na varivel alvo apontada por p_y atribuda posio de memria da varivel alvo apontada por p_x. Adicionalmente, se escrevemosp_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 matrizesprogram usando_pointer !Objetivo: Mostrar o uso de ponteiros ! !programador: joo batista aparecido ilha solteira, 16 de dezembro, 1999 ! 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

Verso preliminar. Escrito em 12/01/99. Impresso em 08/25/05

116

Forttran 90//95 For ran 90 95real, 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 p_y =>y !Atribuindo o ponteiro p_y x = 1.0 y = 5.0 !Inicializando a matriz, x !Inicializando a matriz, y

!Fazendo o swap das matrizes da forma clssica do i = 1, i_max do j = 1, j_max aux = x(i,j) x(i,j) = y(i,j) y(i,j) = aux end do end do !Fazendo o swap das matrizes usando ponteiros p_aux => p_x p_x => p_y p_y => p_aux stop end program usando_pointer

10.3 Alocao dinmica de memria usando ponteiros

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

onde ponteiro_1 o nome do primeiro ponteiro a ser alocado, e assim por diante, forma_do_ponteiro_1 a forma, 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 de zero e depender 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 associ