Zrhans.weebly.com



UNIVERSIDADE FEDERAL DE SANTA MARIA

CENTRO DE CIÊNCIAS NATURAIS E EXATAS

DEPARTAMENTO DE FÍSICA

APOSTILA COM NOTAS DE AULA DA DISCIPLINA

Computação Básica para Física

FORTRAN (FSC1004)

Prof. Ernani de Lima Nascimento

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 1

1.0. Estrutura dos computadores: uma visão geral

* Os dois componentes mais básicos de um sistema computacional são: HARDWARE e SOFTWARE.

* HARDWARE

Memória: memória cache, memória RAM, disco rígido, disco rígido externo, pen-drives, CDs, DVDs, etc..

Unidade de Processamento Central (ou CPU): processadores.

Periféricos de entrada e saída (I/O): teclado, monitor, impressora, modems, etc...

Componentes multimídia: CD-ROM, leitor/gravador de DVD, alto-falantes, web-cam, etc...

* SOFTWARE

(1) Softwares de sistema:

Sistemas Operacionais: Windows, Linux, UNIX, etc...

Compiladores (linguagens de programação): Fortran 77, Fortran 90/05, Pascal, C, C++, JAVA, etc...

Processadores de texto: Latex, Word for Windows, Open Office Writer, VI, nedit, OpenOffice Kate, Power Point, etc...

Planilhas Eletrônicas: Excel, Open Office Calc, etc...

Bibliotecas: MATLAB, IMSL, etc...

Jogos...

(2) Softwares de aplicação:

Criados pelo usuário para resolver um problema específico, sob demanda.

1.1. Linguagem de Programação:

* Neste curso estudaremos um software que é a linguagem de programação. Mais especificamente a linguagem FORTRAN (FORmula TRANslation; “tradução de fórmula”).

* Uma linguagem é um meio de comunicação. A linguagem de programação é uma linguagem que permite a comunicação homem/computador. Programar um computador significa fornecer uma sequência de instruções para o computador executar.

Para quê programar um computador?

Quando compramos um computador ele geralmente já possui instalado um Sistema Operacional (por exemplo, Windows ou Linux) e alguns programas (por exemplo, no caso do Windows, o Microsoft Office, pelo menos por um período de avaliação...).

Estes programas já estão prontos para ser executados e, no caso do Windows, não temos acesso ao chamado código fonte destes programas. Assim, quando há um problema de execução do programa não temos como corrigi-lo. Só nos resta entrar em contato com a Microsoft para relatar o problema e eles corrigem para nós. Mas agora será diferente....

Um código fonte é o que vamos aprender a escrever neste curso! Programar um computador significa, primeiro, criar um código fonte. Vamos aprender a criar nossos próprios códigos fonte e depois aprenderemos a gerar um programa executável a partir deste código fonte. (Lógico, nossos programas serão simples.).

Para quê queremos fazer isto? Porque em Física muitas vezes precisaremos resolver problemas muito específicos, como, por exemplo, calcular a velocidade de uma partícula em MRU. Não existe um pacote “Calcular a velocidade de uma partícula em MRU para Windows”. Temos que nós mesmos programar o computador a resolver este problema.

Então, colocando de forma bem simples, programar um computador é fazer o computador resolver problemas para nós; geralmente serão problemas de execução repetitiva e trabalhosa; geralmente serão problemas do NOSSO interesse específico, mas que não interessarão a outros. Por isto, a Microsoft não se interessará em criar um pacote para resolver um problema que apenas poucas pessoas precisam. Isto na verdade é algo muito positivo, pois nos obrigará a estarmos qualificados a programar um computador e deixarmos de ser meros usuários de “caixas pretas” as quais não sabemos como funciona.

Para programar um computador precisaremos aprender uma linguagem de alto nível.

1.1.1. Linguagens de Programação de Alto Nível (ou simplesmente Linguagens de Programação) e o compilador.

O computador é uma máquina; e uma máquina “burra”, incapaz de pensamento independente. É incapaz de interpretar o que o programador “quis dizer”; é capaz apenas de interpretar literalmente as instruções fornecidas.

O computador não entenderá uma instrução dada em Português, Inglês, Francês, Árabe, etc... O computador entende apenas a LINGUAGEM DE MÁQUINA. Mas programar um computador em linguagem de máquina é extremamente trabalhoso, além do fato de ser dependente de cada fabricante (isto é, uma instrução em linguagem de máquina para um processador AMD será diferente da instrução em linguagem de máquina um processador INTEL).

Foi necessário então criar um padrão de linguagem mais acessível ao programador (isto é, mais fácil de ser compreendida por um ser humano) e que fosse relativamente universal para todos os tipos de processadores. Estas são as chamadas LINGUAGENS DE ALTO NÍVEL. Exemplos de linguagens de alto nível: FORTRAN, PASCAL, BASIC, C, C++, JAVA, etc...

O FORTRAN (de “FORmula TRANslation”) foi a primeira linguagem de programação de alto nível a se tornar popular, criada em 1957. De lá para cá diversas versões desta linguagem foram desenvolvidas: FORTRAN II, FORTRAN IV, FORTRAN 66, FORTRAN 77, FORTRAN 90, FORTRAN 95, FORTRAN 2003. O objetivo deste curso é ensinar a linguagem FORTRAN 77.

O FORTRAN (assim como todas as outras linguagens de alto nível) é de fácil entendimento para o ser humano, mas demasiadamente complexa para um computador entender. Assim, se quisermos programar um computador em FORTRAN (ou C, ou PASCAL, etc...) é necessário primeiro instalar um COMPILADOR.

O compilador é um programa que faz a “tradução” da linguagem de alto nível para a linguagem de máquina (que é uma “linguagem de baixo nível”). Felizmente não precisaremos criar um compilador, pois ele já foi criado por um programador experiente e altamente especializado. Precisamos apenas instalar o compilador no nosso computador.

Para deixar mais claro a forma como vamos trabalhar, considere a seguinte comparação:

Um usuário de programas/pacotes executáveis tipo “caixas pretas” (ou “plug-and-play”) trabalha assim:

No esquema acima o usuário não tem NENHUM controle sobre a etapa (2).

Neste curso aprenderemos a trabalhar assim:

No esquema acima o usuário tem TOTAL controle de todas as etapas. Não é um esquema “plug-and-play”. O compilador é o programa que permitirá criar um arquivo executável a partir do código fonte (isto é, realizar ligação entre as etapas (1) e (2)).

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 2

2. Declaração de variáveis e o conceito de alocação de memória no computador.

Na grande maioria das vezes utilizaremos a linguagem FORTRAN para escrever programas que realizarão cálculos (repetitivos) para nós. Assim, é necessário ter uma noção de como os números são representados e armazenados na memória do computador.

Em qualquer linguagem de computador (incluindo o FORTRAN), valores aritméticos são atribuídos a variáveis. Por exemplo, seja a expressão aritmética:

z = x + y

Se x=58 e y=12, então z será igual a 70. Neste exemplo x, y e z são as três variáveis envolvidas no cálculo. Como escrever isto em FORTRAN? Através de um código fonte, como no exemplo abaixo:

program soma

implicit none

integer x,y,z

x=58

y=12

z=x+y

print*,z

stop

end

Não se preocupe com os detalhes do programa acima. Por ora apenas saiba que TODAS as variáveis a serem utilizadas em um programa têm que ser declaradas. O que significa “declarar uma variável”? Significa alocar (reservar) um espaço de memória no computador onde os valores a serem atribuídos àquela variável serão armazenados. Assim, quando o programa precisar utilizar o valor daquela variável ele vai saber exatamente onde encontrar. No exemplo acima a linha

integer x,y,z

declara três variáveis do tipo inteiro (em inglês ( INTEGER): a variável x, a variável y e a variável z (note que as vírgulas são usadas para separar as variáveis). Ou seja, estamos “informando” ao compilador que para a execução do nosso programa precisaremos utilizar estas três variáveis. E ao fazermos isto estamos então solicitando ao compilador que reserve (ou aloque) três ENDEREÇOS (1 endereço para cada variável) na memória do computador onde serão armazenados os valores que vamos atribuir a estas variáveis. Como fornecemos valores para as variáveis? Através do sinal de “=”

x=58

y=12

z=x+y

Quando a variável x receber o valor 58, este número é imediatamente enviado para o endereço de memória do computador referente à variável x (obs: Aonde exatamente é este endereço de memória não importa para nós. É o compilador que é responsável por isto.). Mais adiante, quando usarmos a variável x (na expressão z=x+y) o programa resgata o valor 58 e utiliza para realizar a soma.

Mas como os números são representados na memória do computador? O computador não reconhece os números no sistema decimal! Reconhece apenas o sistema binário (ou base 2), onde os únicos dígitos possíveis são 0 ou 1. Como é feita a conversão?

base 10 base 2

58 = (1 ( 25) + (1 ( 24) + (1 ( 23) + (0 ( 22) + (1 ( 21) + (0 ( 20) = 1110102

32 + 16 + 8 + 0 + 2 + 0

onde o subscrito 2 indica que temos um número representado no sistema binário. Então, o número 58 no sistema decimal (base 10) se transforma em 111010 no sistema binário (base 2). Por exemplo, de 1 a 10, a representação binária é:

Decimal Binário

0 0

1 1

2 10

3 11

4 100

5 101

6 110

7 111

8 1000

9 1001

10 1010

Em computação cada dígito binário, 0 ou 1, é chamado de BIT. O bit pode ser interpretado como sendo uma informação do tipo SIM ou NÃO (por exemplo; 0=não, 1=sim). Qualquer informação armazenada em um computador é representada por um conjunto de bits. Cada conjunto de 8 bits forma 1 BYTE (1 byte = 8 bits).

Os bytes são agrupados em “palavras”, mas o conceito de “palavra” aqui é diferente do conceito de “palavra” a que estamos acostumados. Em computação o chamado “tamanho da palavra” é o número máximo de bits que 1 endereço da memória pode armazenar. Este tamanho difere de computador para computador, mas costuma ser 16bits (= 2 bytes), ou 32bits (= 4 bytes), ou 64bits (= 8 bytes). Associado com cada “palavra” existe um endereço de memória que pode ser usado para armazenar o valor de uma variável durante a execução de um programa.

Assim, no exemplo do programa acima, quando a variável x é declarada o compilador reserva um endereço de memória (cujo tamanho depende do “tamanho da palavra” do computador usado) para que possa receber valores durante a execução do programa. Se for, por exemplo, um computador 16bits:

Na compilação: 1 (um) endereço de memória no tamanho de 16bits é reservado para a variável x.

Durante a execução do programa, a variável x recebe o valor 58:

Na execução: o valor 1110102 é armazenado no endereço de memória alocado para variável x.

REPRESENTAÇÃO DO NÚMERO 58 NA MEMÓRIA (16BITS):

|0 |

É neste ambiente que vamos efetuar as seguintes tarefas (nesta sequência):

1) EDITAR os códigos fonte (como se estivéssemos em um editor de texto);

2) COMPILAR os programas (isto é, gerar os arquivos executáveis (os binários));

3) EXECUTAR os programas.

4.1. EDIÇÃO.

Na fase de edição do código fonte o FORCE2.0 funcionará como um editor de texto. Mas é um editor de texto específico para criarmos um código FORTRAN77.

Repare que existem duas linhas verticais na janela de edição. Estas linhas delimitam uma “faixa” de edição para um programa FORTRAN77, faixa esta localizada entre a 7ª e a 72ª colunas de cada linha (para se convencer disto, utilize o cursor para contar os espaços necessários para se chegar nas duas linhas partindo-se da margem esquerda da janela de edição).

Todo o conteúdo do programa FORTRAN77 deve ser escrito entre as colunas 7 e 72 (com exceção de alguns poucos parâmetros que veremos mais tarde). Ou seja, exceto por estes poucos parâmetros, qualquer texto escrito fora desta faixa de edição será ignorado pelo compilador o que certamente acarretará em erro. Respeitar esta faixa de edição é obrigatório em todos os programas FORTRAN77, independentemente do compilador FORTRAN77 que esteja sendo usado (isto é, esta não é uma característica específica do FORCE2.0; é universal para todos os programas FORTRAN77). [obs: Nas versões mais recentes do FORTRAN (90, 95, 2003) esta restrição não existe mais!].

OBS: De vez em quando precisaremos escrever nas colunas 1 a 5, que serão usadas para numerar (“rotular”) um determinado comando do FORTRAN77. Quando necessário, a coluna 6 poderá ser utilizada para indicar uma continuação de linha (veremos isto mais tarde). Mas por enquanto não faremos uso das colunas 1 a 6; logo não escreva nada nelas ainda. As colunas 73 em diante nunca serão usadas.

Vamos a um exemplo bem simples. Escreva no FORCE2.0 o seguinte programa FORTRAN (cujo nome é primeiro_programa):

|[pic] |

Obs: A numeração de linhas no lado esquerdo da janela de edição surge automaticamente à medida que acrescentamos linhas ao código fonte. Esta numeração de linhas funciona apenas para facilitar a localização das mesmas e não faz parte da linguagem FORTRAN.

| |

Temos acima um código fonte em linguagem FORTRAN77. No FORCE2.0 todos os comandos do FORTRAN aparecerão em azul (no exemplo acima: program, print, stop, end).

PROGRAM

Comando ao lado do qual é fornecido o nome do programa.

PRINT*,

Escreve na tela do computador tudo aquilo que se segue após a vírgula. Se o que desejamos escrever na tela for um texto (uma frase, por exemplo) o mesmo deve estar entre aspas (simples ou duplas), e neste caso o FORCE2.0 vai ressaltar o texto em vermelho no código fonte.

STOP

Interrompe a execução do programa.

END

Indica o fim do programa.

Nesta disciplina aprenderemos diversos outros comandos do FORTRAN77.

4.2. COMPILAÇÃO.

Uma vez concluída a edição do código fonte partimos para a compilação (“tradução” do nosso código para a linguagem de máquina, que será um arquivo executável). Mas antes disto é aconselhável salvar o teu trabalho. No menu principal clique em “Arquivo” e em “Salvar como” e salve o código fonte com um nome à tua escolha (por exemplo, programa1). (O FORCE2.0 salvará este arquivo com uma extensão .f).

Agora compilamos o programa:

No menu principal clique em “Executar”, escolha “Compilar” e aguarde. Se o programa estiver corretamente escrito não ocorrerá nenhum erro de compilação e uma mensagem de “Pronto. Compilado” surgirá numa janela. Se houver um erro no conteúdo do programa (por exemplo, se você digitar um comando erradamente), ocorrerá um erro de compilação e o FORCE2.0 informará em que linha está o erro. Corrija o erro, salve a modificação e compile de novo.

Para dar uma idéia de como o compilador é “exigente” e não admite nem mesmo o menor dos erros de edição, experimente apagar a vírgula que vem depois do comando PRINT*, salve o programa e compile. Veja o erro de compilação que surgirá. O FORTRAN, assim como qualquer outra linguagem computacional, é muito sensível quanto à sintaxe do código fonte e “exige” que esteja tudo perfeitamente escrito – lembre-se, o computador é burro; não espere que ele tente entender o que você “quis dizer”, ele só saberá entender o que você “disse exatamente”.

4.3. EXECUÇÃO.

Se a compilação obteve sucesso então o FORCE2.0 terá criado um arquivo executável (no mesmo diretório em que está o código fonte). Agora você pode executar seu programa clicando em “Executar” e “Executar”. Se tudo estiver certo uma janela com fundo preto será aberta onde constará a frase “Este é meu primeiro programa”.

Experimente escrever outra frase na tela: modifique a frase, salve a modificação, compile o código fonte, e execute o programa.

5.0. Um primeiro contato com a sintaxe do FORTRAN77

Na aula passada falamos da declaração de variáveis e seu significado em termos de endereçamento de memória no computador. Mas no exemplo que vimos acima não usamos variável nenhuma. Apenas criamos um programa que escreve uma frase (boba) na tela. Vamos agora gerar um programa onde variáveis do tipo INTEIRO são usadas.

Seguindo o que foi descrito no item anterior, ESCREVA, SALVE, COMPILE e EXECUTE o seguinte programa:

program soma

integer k,n,m

n=1

m=3

k=m+n

print*,k

stop

end

Se ao final de todos os passos tudo estiver correto uma janela será aberta onde constará o resultado “4”.

Todo programa FORTRAN começa com o comando program seguido de um nome para o programa (você escolhe o nome, apenas tendo cuidado de evitar alguns caracteres da Língua Portuguesa como c-cedilha, til, acento agudo, etc...).

Como vimos aula passada a linha

integer k,n,m

é uma declaração de variáveis. Neste exemplo estamos declarando 3 variáveis do tipo inteiro: k, n, m.

As linhas

n=1

e

m=3

são atribuições de valores para as variáveis n e m. Ou seja, a partir deste ponto do programa a variável n é igual a 1 e a variável m é igual a 3.

A linha

k=m+n

é também uma atribuição de valor (no caso, para a variável k), mas na forma de uma operação aritmética (soma). Ou seja, a partir deste ponto do programa a variável k é igual a 4 (isto é, 1 + 3).

Na linha

print*,k

temos o comando print seguido de um asterisco. Este é um comando de impressão na tela. No caso acima é uma impressão na tela do computador. Ao chegar nesta linha o programa irá mostrar na tela o resultado da soma m+n.

E finalmente temos:

stop

end

Sempre devemos terminar nossos programas com estes dois comandos: stop (interrompe a execução do programa) e end (finaliza o programa).

Então, em resumo, todo programa FORTRAN terá a sequência geral: nome do programa, declaração de variáveis, execução de comandos de entrada de valores ou de atribuição de valores, execução de contas, execução de comandos de saída dos resultados, finalização do programa.

Façamos agora um programa (com nome soma2) com variáveis do tipo REAL. Salve o programa com outro nome, compile e execute.

program soma2

real k,n,m

n=2.3

m=3.1

k=n+m

print*,k

stop

end

Se ao final de todos os passos tudo estiver correto uma janela será aberta onde constará o resultado 5.4.

5.1. Convenção padrão do FORTRAN para associar nomes com tipos de variáveis, e o comando IMPLICIT NONE.

Vimos o importante conceito de declaração de variáveis em FORTRAN; mas o fato é que a rigor não somos obrigados a declarar as variáveis explicitamente (mas não declarar é um exemplo de péssima prática de computação!). O FORTRAN possui uma convenção padrão para as variáveis que é a seguinte:

(a) Todas as variáveis (não declaradas) cujos nomes começam com I, J, K, L, M, ou N serão consideradas do tipo INTEIRO. Por exemplo: j, index, marte, k2, nano, etc...

(b) Todas as variáveis (não declaradas) cujos nomes não começam com I, J, K, L, M, ou N serão consideradas do tipo REAL. Por exemplo: ast, raio, helio, d25, zum, etc...

Então agora volte ao programa soma e apague a linha de declaração das variáveis, assim:

program soma

n=1

m=3

k=m+n

print*,k

stop

end

Salve, compile e execute o programa e veja se o resultado é alterado.

Agora volte ao programa soma2 e apague a linha de declaração das variáveis, assim:

program soma2

n=2.3

m=3.1

k=n+m

print*,k

stop

end

Salve, compile e execute o programa e veja se o resultado é alterado. A resposta é “Sim, foi alterado!”. Ao invés de fazer 2.3 + 3.1 = 5.4, o FORTRAN interpretou as variáveis n, m e k como sendo do tipo inteiro (pois esta é a convenção padrão para estas variáveis quando não são declaradas) e truncou os valores atribuídos a estas variáveis, fazendo então 2 + 3 = 5 , o que modifica o resultado.

Sempre declare todas as variáveis de seus programas.

Uma maneira de te obrigar a declarar explicitamente todas as variáveis é usar o comando IMPLICIT NONE (traduzindo ao pé da letra: “nenhum implícito”) logo após o nome do programa, assim:

program soma

implicit none

integer k,n,m

n=1

m=3

k=m+n

print*,k

stop

end

e

program soma2

implicit none

real k,n,m

n=2.3

m=3.1

k=n+m

print*,k

stop

end

Com o implicit none, o FORTRAN “neutraliza” a convenção padrão e o compilador exigirá que todas as variáveis sejam declaradas. Sempre inclua o implicit none nos seus programas.

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 4

5.2. Recomendações sobre os nomes das variáveis.

Ao dar um nome a uma variável, escolha um nome que te ajude a identificar o que ela significa no contexto do teu programa, seja do ponto de vista físico ou matemático.

Por exemplo, se você escreve um programa que calcula o perímetro de um círculo a partir do seu raio r (perímetro = 2(r), então é conveniente declarar a variável que recebe o valor do raio como sendo raio, a variável que recebe o valor de perímetro como sendo perimetro ou perim (sem o acento agudo no i porque a acentuação não é aceita no FORTRAN), e a variável que recebe o valor de ( como sendo pi.

Estes nomes para as variáveis são mais adequados para deixar o programa mais legível. Compare a diferença de clareza nos dois trechos abaixo para um programa que calcula o perímetro de um círculo com raio de 5,3 cm:

real a,b,c

a=3.1416

b=5.3

c=2.*a*c [obs: o asterisco (*) representa a multiplicação, como veremos abaixo.]

e:

real pi, raio, perimetro

pi=3.1416

raio=5.3

perimetro=2.*pi*raio

Fica evidente que o segundo exemplo é muito mais claro para o leitor.

6.0. Comentários nos programas FORTRAN

Muitas vezes é importante acrescentar comentários ao programa (código fonte). Tipicamente, estes comentários são empregados para explicar (para o leitor do código fonte) o que o programa irá executar. Para acrescentar um comentário ao teu código fonte coloque um C (C maiúsculo), ou * (asterisco), ou ! (exclamação) na coluna 1 da janela de edição.

Todas as linhas contendo algum destes caracteres na coluna 1 da janela serão consideradas linhas de comentário e serão ignoradas pelo compilador. Ou seja, o compilador entenderá que estas linhas não fazem parte da sequência de expressões e comandos que executarão o programa. Assim, seja por exemplo:

program perimetro

* Este programa calcula o perímetro de um círculo dado o seu raio.

implicit none

! Declarando as variáveis:

real pi, raio, perimetro

pi=3.1416

C Fornecendo o raio do círculo:

raio=5.3

C Calculando o perímetro do círculo:

perimetro=2.*pi*raio

! Fornecendo o resultado na tela:

print*, perímetro

stop

end

Observe que quando acrescentamos um comentário o FORCE2.0 imediatamente torna a linha itálica e com cor cinza. É uma forma do FORCE2.0 te ressaltar que esta linha é apenas um comentário.

Recomendação: Comente teus programas sempre que possível. Principalmente os programas mais complicados. Assim, se no futuro você precisar voltar ao código fonte, terá uma documentação do quê exatamente está sendo feito no programa.

Obs: Como serão ignorados pelo compilador, os comentários podem começar antes da coluna 7 e passar da coluna 72.

Obs: Quando usamos o ponto de exclamação (!) podemos posicionar o comentário após um comando ou expressão do FORTRAN, na mesma linha. Assim:

program perímetro

C Este programa calcula o perímetro de um círculo dado o seu raio.

implicit none

real pi, raio, perimetro ! Declarando as variáveis.

pi=3.1416

raio=5.3 ! Fornecendo o raio do círculo.

perimetro=2.*pi*raio ! Calculando o perímetro do círculo.

print*, perimetro ! Fornecendo o resultado na tela.

stop

end

Obs: Veremos que a capacidade de “comentar uma linha” será muito útil quando estivermos depurando um programa para corrigir um erro de compilação ou execução. Vamos supor que, no exemplo acima, queiramos testar o impacto de alterar a expressão que calcula o perímetro do círculo mudando-se 2. (real) para 2 (inteiro). Podemos fazer:

! perimetro=2.*pi*raio

perimetro=2*pi*raio

A linha começando com (!) será ignorada pelo compilador (dizemos que a linha foi “comentada”) e a execução será feita com a segunda expressão (onde trocamos “2.” por “2”). Em seguida, para comparar, podemos “descomentar” a primeira expressão e “comentar” a segunda expressão:

perimetro=2.*pi*raio

! perimetro=2*pi*raio

Refazemos a compilação e execução para ver se há diferença no resultado. (Repare que neste segundo teste é a segunda expressão que será ignorada pelo compilador).

Logo, sempre que você ouvir dizer para “comentar” uma determinada linha significa adicionar um caractere de comentário na primeira coluna daquela linha.

7.0. Operações aritméticas em FORTRAN

A grande maioria dos programas que escreveremos será para a realização de contas. Assim, precisamos entender como funcionam as operações aritméticas no FORTRAN.

Em FORTRAN, adição e subtração são representadas por seus sinais usuais de (+) e ((), respectivamente. No programa soma que escrevemos aula passada, vimos um exemplo de programa contendo a adição de duas variáveis.

k=m+n

Outros exemplos:

raio=38.2+23.5

celsius=kelvin(273.15

A multiplicação é sempre representada pelo asterisco (*), como vimos nos exemplos do programa que calcula o perímetro de um círculo.

C=A*B ( representando C = A ( B

diam=2.*r ( representando diam = 2.0 ( r

perim=2.0*pi*r ( representando perim = 2.0 ( ( ( r

Obs: Não tente representar a multiplicação “2 vezes N” como “2N” pois o FORTRAN não entende esta maneira implícita de representar a multiplicação. Faça explicitamente 2*N ou N*2.

A divisão é representada pela barra (/):

4.0 / 2.5

resto / 3.0

numer / denom

Tome cuidado para evitar divisões por zero (por exemplo, a variável denom acima jamais poderá receber o valor zero).

Obs: Lembre-se de sempre usar variáveis do mesmo tipo nas expressões aritméticas do FORTRAN; não porque isto seja obrigatório (não é!), mas para evitar uma má prática de programação.

Se for inevitável combinar variáveis de tipos diferentes em uma mesma expressão aritmética, é possível transformar os valores de inteiro para real ou vice versa usando os seguintes comandos:

float() ( converte um valor inteiro para valor real; p.ex.:

integer k

real teste

k=3 ( a variável de tipo inteiro, k, recebe o valor inteiro 3

teste=float(k)/5. ( o comando FLOAT converte o valor inteiro 3 para valor real 3.0 e a divisão é então realizada inteiramente com valores reais. O resultado é atribuído à variável real teste.

int() ( converte um valor real para valor inteiro, desprezando-se a casa decimal; p.ex.:

integer teste2

real bump

bump=6.8 ( a variável de tipo real, bump, recebe o valor real 6.8

teste2=int(bump)/2 ( o comando INT converte o valor real 6.8 para valor inteiro 6 e a divisão é então realizada inteiramente com valores inteiros. O resultado é atribuído à variável inteira teste2.

nint() ( converte um valor real para valor inteiro, arredondando-se para o inteiro mais próximo; p.ex.:

integer teste2

real bump

bump=6.8 ( a variável de tipo real, bump, recebe o valor real 6.8

teste2=nint(bump)/2 ( o comando NINT converte o valor real 6.8 para o valor inteiro 7 e a divisão é então realizada inteiramente com valores inteiros. O resultado é atribuído à variável inteira teste2. Neste exemplo o resultado seria 3.5, mas como teste2 é do tipo inteiro a casa decimal é desprezada e teste2 recebe o valor 3

A potenciação é representada por dois asteriscos (**). Assim temos, por exemplo:

4.**2 ( quatro elevado ao quadrado.

resto**3 ( o valor da variável resto é elevado ao cubo.

4.**resto ( o valor real 4 elevado à potência indicada pelo valor da variável resto, que neste caso deve ser preferencialmente uma variável inteira.

Por exemplo,veremos que na solução da equação do segundo grau a expressão abaixo será útil:

B**2 – 4.*A*C

Na potenciação o expoente deve ser (preferencialmente) inteiro, pois o FORTRAN irá avaliar a expressão da seguinte forma:

2.0**3 ( 2.0 * 2.0 * 2.0

Já caso o expoente seja do tipo real o FORTRAN avaliará o a expressão de outra maneira:

2.0**3.0 ( exp[3.0 ln(2.0)]

No exemplo acima não haveria problema algum; mas caso o argumento seja negativo:

(2.0**3.0 ( exp[3.0 ln((2.0)]

haverá um problema já que o logaritmo não é definido para valores negativos, gerando erro de execução.

Note, entretanto, que o uso de expoentes reais será inevitável quando quisermos realizar a operação de raízes. Por exemplo, a raiz quadrada de um determinado valor pode ser calculada por:

var**0.5 ( o valor de var elevado a ½

Ou a raiz cúbica por:

var**(1./3.) ( o valor de var elevado a 1/3

Obs: Repare que no último exemplo acima é obrigatório usar o expoente real já que o resultado de 1/3 (usando valores inteiros) daria 0 (zero).

Atenção: No caso da raiz quadrada podemos optar por usar uma função pré-definida do FORTRAN que calcula a raiz quadrada. É a função sqrt(). Por exemplo, seja o cálculo:

determ= B**2 – 4.*A*C

raizq=sqrt(determ) ( calcula a raiz quadrada do valor recebido por determ

Atenção: o argumento da função sqrt no FORTRAN deve ser sempre do tipo real. Por exemplo:

k=3 ( k é uma variável inteira e, portanto, recebe um valor inteiro.

raiz=sqrt(float(k)) ( Na hora de calcular a raiz quadrada de k, convertemos o valor inteiro para real dentro do argumento da função sqrt.

7.1. Regras de prioridade para as operações aritméticas

Expressões aritméticas são avaliadas de acordo com as seguintes regras de prioridade:

(a) Todas as potenciações são realizadas primeiro; potenciações consecutivas são realizadas da direita para a esquerda:

2.*4.**2 = 2.*16.

34.+8.**3 = 34.+512.

2**3**2 = 2**9

(b) Após as potenciações, são realizadas as multiplicações e divisões, de acordo com a ordem em que aparecem da esquerda para a direita:

2 + 8 / 2 = 2 + 4

10. * 5. – 3. = 50. – 3.

4 * 5 * 8 / 4 = 20 * 8 / 4 = 160 / 4

5.0 * 8.0 ** 2 + 3.0 = 5.0 * 64.0 + 3.0 = 320.0 + 3.0

(c) Após as potenciações, divisões e multiplicações, são realizadas as adições e subtrações de acordo com a ordem em que aparecem da esquerda para a direita:

3 + 4 + 5 – 8 * 4 = 3 + 4 + 5 – 32 = 7 + 5 – 32 = 12 – 32 = -20

As regras de prioridade podem ser neutralizadas pelo uso de parênteses que definem sub-expressões dentro de uma expressão maior. As sub-expressões dentro dos parênteses mais internos são resolvidas primeiro. Por exemplo:

(5 * (11 - 5) ** 2) * 4 + 9 = (5 * 6 ** 2) * 4 + 9 = (5 * 36) * 4 + 9 = 180 * 4 + 9 = 720 + 9 = 729

Cuidado com os valores negativos: por exemplo, o valor (2 é corretamente interpretado como um valor negativo em FORTRAN, mas na hora de escrevê-lo dentro de uma expressão poderá haver problemas. Por exemplo:

N * (2

não é uma expressão aceita em FORTRAN! O compilador “reclamará” porque vai interpretar o sinal de “(” como sendo um sinal de subtração e não como um sinal de número negativo. É necessário fazer:

N * ((2)

8.0. Declaração de constantes.

Nos nossos programas em Física e Matemática não será raro trabalhar com valores constantes (por exemplo, ( = 3,14159...). Em FORTRAN não é muito aconselhável declarar valores constantes como sendo variáveis comuns. Para declarar uma constante utilizamos a expressão PARAMETER, assim:

program perímetro

C Este programa calcula o perímetro de um círculo dado o seu raio.

implicit none

real pi, raio, perimetro ! Declarando as variáveis.

parameter (pi=3.14159) ! Declarando a constante pi.

raio=5.3 ! Fornecendo o raio do círculo.

perimetro=2.*pi*raio ! Calculando o perímetro do círculo.

print*, perimetro ! Fornecendo o resultado na tela.

stop

end

Note que primeiro pi foi declarado como uma variável real (pois é de fato um número real!), para logo em seguida ser indicado como sendo uma constante (PARAMETER) e ter seu valor definido (pi=3.14159) . Nós definimos o valor de ( a ser usado no programa. Poderíamos ter definido como sendo 3.14, ou 3.14159265, ou 3.1415926535898. Fica a nosso critério!

Ao contrário das variáveis comuns, uma constante não poderá ter seu valor mudado no meio do programa. Tente mudar o valor de pi no meio do programa exemplificado acima e veja o que o compilador vai dizer.

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 5

NOTA IMPORTANTE 1: Cuidados no cálculo da raiz cúbica de números negativos:

Vimos aula passada que para se calcular no FORTRAN a raiz cúbica de um determinado valor é inevitável ter que elevar este valor a um expoente do tipo real, como por exemplo, no caso da raiz cúbica de oito [[pic](= 81/3)]:

Em FORTRAN é escrito como ( 8.**(1./3.)

Vimos que, como o expoente é um número real, o FORTRAN avaliará a raiz cúbica da seguinte forma:

8.**(1./3.) ( exp[0.3333 ln(8.0)]

O resultado será fornecido corretamente: 2.

Mas e se quiséssemos calcular [pic]? Neste caso corremos o risco de cair no conflito:

exp[0.3333 ln((8.0)]

, o que acarretaria em erro já que o logaritmo natural não é definido para valores ( 0.0. De fato, este erro acontecerá se no FORTRAN escrevermos [pic] assim:

((8.) **(1./3.) ( errado

Entretanto, o FORTRAN fará a conta correta se escrevermos:

(8.**(1./3.) ( correto

(1.*8.**(1./3.) ( correto

((1.)*8.**(1./3.) ( correto

E no caso de ser a raiz cúbica de um valor negativo que foi atribuído a uma variável?

arg= (8.0

raizcub=arg**(1./3.)

Neste caso haverá erro de execução. Uma forma de se resolver este problema seria, primeiro, multiplicar o valor negativo da variável por (1 e depois multiplicar o resultado da raiz cúbica por (1, assim:

arg = (8.0

raizcub=((1.*arg)**(1./3.)*( (1.)

Neste caso o programa funciona, fornecendo o resultado correto (2. Mas esta é uma solução pouco inteligente porque se depois precisarmos atribuir à variável arg um valor positivo, teremos que mudar de novo a equação da raiz cúbica. Veremos mais adiante, quando falarmos em estruturas de programação estruturada, que podemos criar uma bifurcação no programa de modo que uma equação seja empregada no caso de arg ser positivo, outra equação seja usada no caso de arg ser negativo, e uma terceira equação seja usada no caso de arg ser igual a zero.

Obs: Note que a discussão acima é válida também para todas as raízes de índice ímpar (raiz quinta, raiz sétima, etc...), pois nestas o radicando pode ser negativo.

NOTA IMPORTANTE 2: Cuidado com a interpretação do sinal de igual “=”.

Até o momento vimos o uso do “=” como um comando de atribuição, e não como uma expressão comparativa de igualdade.

Quando fazemos:

teste=300.8

estamos atribuindo à variável real teste o valor de 300.8 (isto é, o espaço na memória reservado para a variável teste vai armazenar o valor 300.8).

Assim temos, por exemplo:

teste1=300.8

teste2=23.8

teste1=teste2

No final destas três linhas as variáveis teste1 e teste2 terão o mesmo valor de 23.8, pois o valor de 300.8, originalmente atribuído para teste1, foi substituído pelo valor 23.8 quando fizemos teste1 = teste2.

Da mesma forma:

teste1=300.8

teste2=23.8

teste2=teste1

No final destas três linhas as variáveis teste1 e teste2 terão o mesmo valor de 300.8, pois o valor de 23.8, originalmente atribuído para teste2 , foi substituído pelo valor 300.8 quando fazemos teste2 = teste1.

Considere este outro exemplo:

teste1=256.98

teste1=teste1 + 30.0

Na segunda linha somamos o valor 30.0 ao valor 256.98 originalmente atribuído à teste1; em outras palavras, somamos 30.0 ao valor que está armazenado na memória do computador no endereço guardado para a variável teste1. O valor armazenado neste endereço de memória é imediatamente atualizado para 256.98 + 30.0 quando fazemos a soma acima. Logo, ao final destas duas linhas o valor armazenado pela variável teste1 passa a ser de 286.98. Fica claro neste exemplo que é possível atribuir a uma variável o seu próprio valor modificado por alguma expressão aritmética qualquer.

9.0. Algumas funções intrínsecas do FORTRAN

Existem várias funções pré-definidas em FORTRAN (chamadas de funções intrínsecas), que podem ser usadas em qualquer parte do programa. Na última aula fomos apresentados a algumas destas funções: int(), anint(), float(), e sqrt() [respectivamente: transforma um valor real em inteiro (int e anint); transforma um valor inteiro em real (float); calcula a raiz quadrada de um valor real (sqrt)].

Abaixo seguem tabelas com algumas funções intrínsecas importantes do FORTRAN.

9.1. Funções trigonométricas:

NOME DESCRIÇÃO VALOR DE VALOR DE

ENTRADA SAÍDA

|sin(x) |Calcula o seno de um ângulo x fornecido em radianos. |REAL |REAL |

|asin(x) |Calcula o ângulo em radianos cujo seno é igual a x (ou seja, |REAL, entre -1.0 e 1.0|REAL |

| |calcula o arco-seno) | | |

|cos(x) |Calcula o cosseno de um ângulo x fornecido em radianos. |REAL |REAL |

|acos(x) |Calcula o ângulo em radianos cujo cosseno é igual a x (ou seja, |REAL, entre -1.0 e 1.0|REAL |

| |calcula o arco-cosseno). | | |

|tan(x) |Calcula a tangente de um ângulo x fornecido em radianos. |REAL |REAL |

|atan(x) |Calcula o ângulo em radianos cuja tangente é igual a x (ou seja, |REAL |REAL |

| |calcula o arco-tangente) | | |

|sinh(x) |Calcula o seno hiperbólico de um ângulo x fornecido em radianos. |REAL |REAL |

|cosh(x) |Calcula o cosseno hiperbólico de um ângulo x fornecido em radianos.|REAL |REAL |

|tanh(x) |Calcula a tangente hiperbólica de um ângulo x fornecido em |REAL |REAL |

| |radianos. | | |

9.2. Funções diversas (mais empregadas):

NOME DESCRIÇÃO VALOR DE VALOR DE

ENTRADA SAÍDA

|exp(x) |Calcula o exponencial de x (i.e., ex) |REAL |REAL |

|log10(x) |Calcula o logaritmo decimal de x |REAL |REAL |

|log(x) |Calcula o logaritmo natural (ou neperiano) de x |REAL |REAL |

|abs(x) |Fornece o valor absoluto (ou módulo) de x |REAL |REAL |

| | |INTEIRO |INTEIRO |

|int(x) |Converte o valor real de x para um valor inteiro, |REAL |INTEIRO |

| |desprezando-se as casas decimais (isto é, truncando-se o valor| | |

| |de x) | | |

|nint(x) |Converte o valor real de x para um valor inteiro, |REAL |INTEIRO |

| |arredondando-se o valor para o inteiro mais próximo | | |

|anint(x) |Arredonda o valor real de x para o inteiro mais próximo, mas |REAL |REAL |

| |mantendo o resultado como sendo do tipo real | | |

|float(x) |Converte o valor inteiro de x para um valor real |INTEIRO |REAL |

|real(x) |Converte o valor inteiro de x para um valor real (É igual à |INTEIRO |REAL |

| |função float(x)) | | |

|sign(x,y) |Fornece o valor positivo de x se y ( 0, e o valor negativo de |REAL |REAL |

| |x se y < 0 |INTEIRO |INTEIRO |

| | | | |

|mod(x,y) |Fornece o resto da divisão de x por y |REAL |REAL |

| | |INTEIRO |INTEIRO |

|sqrt(x) |Calcula a raiz quadrada de x (que deve ser real e > 0). |REAL |REAL |

|max(x1,x2...xn) |Fornece o valor máximo entre os xn indicados (n ( 2) |REAL |REAL |

| | |INTEIRO |INTEIRO |

|min(x1,x2...xn) |Fornece o valor mínimo entre os xn indicados (n ( 2) |REAL |REAL |

| | |INTEIRO |INTEIRO |

Exemplos:

ABS:

arg= (2 ( abs(arg)=2

arg= (8. ( abs(arg)=8.

INT, NINT, ANINT:

arg= 45.9 ( int(arg)=45

arg= 45.9 ( nint(arg)=46 anint(arg)=46.

FLOAT, REAL:

arg= (13 ( float(arg)= (13. real(arg)= (13.

SIGN:

arg1= (12. , arg2=15. ( sign(arg1,arg2)= 12.

arg1= (12. , arg2= (15. ( sign(arg1,arg2)= (12.

arg1= 10 , arg2= (200 ( sign(arg1,arg2)= (10

obs: note que a função sign(x,y) representa uma transferência do sinal de y para x.

MOD:

arg1=23. , arg2=2. ( mod(arg1,arg2)= 1.

arg1=23. , arg2=4. ( mod(arg1,arg2)= 3.

arg1= (23 , arg2=5 ( mod(arg1,arg2)= (3

MAX:

arg1=12.5 , arg2=400.0 ( max(arg1,arg2)= 400.

arg1=12.5 , arg2= (12.0 , arg3=7.0 ( max(arg1,arg2,arg3)= 12.5

MIN:

arg1= (30 , arg2= 0 ( min(arg1,arg2)= (30

arg1= (0.01 , arg2= (0.001 , arg3= (0.0001 ( min(arg1,arg2,arg3)= (0.01

Abaixo mostramos alguns exemplos simples da utilização destas funções. Escreva, compile e execute estes programas.

program calcula_pi

C Este programa calcula o valor de pi, que é o arco cujo cosseno é igual a (1.

implicit none

real pi

pi=acos((1.0)

print*,(O valor de pi encontrado com a funcao acos eh: (,pi

stop

end

program resto_divisao

C Este programa calcula o resto da divisão entre dois valores reais.

implicit none

real var1, var2, resto

var1=9.9

var2=3.2

resto=mod(var1,var2)

print*,(O resto da divisao entre (,var1,( e (,var2,( eh: (,resto

stop

end

NOTA IMPORTANTE 3: Lembre-se que as funções trigonométricas no FORTRAN só funcionam com ângulos em radianos. É comum, quando se aprende a programar, cometer-se o erro de se fornecer os ângulos em graus para estas funções, acarretando em erros nos cálculos.

program converte

C Este programa converte um ângulo de graus para radianos e depois

C calcula o seu seno.

implicit none

real graus,radianos,seno,pi

C Obtém o valor de pi

pi=acos((1.0)

graus=30.0

C Converte de graus para radianos

radianos=graus*pi/180.

C Calcula o seno

seno=sin(radianos)

print*,(O seno de (,graus,( graus eh igual a : (,seno

stop

end

10. Variáveis do tipo CARACTERE (CHARACTER)

Vimos que as variáveis do tipo inteiro (INTEGER) e real (REAL) recebem valores numéricos. Mas e se quisermos definir uma variável que receba caracteres alfanuméricos, como por exemplo palavras e nomes? Como fazemos? Neste caso declaramos esta variável com o sendo do tipo CHARACTER.

Sintaxe geral da declaração de uma variável do tipo CHARACTER:

program caractere

implicit none

character*N var

, onde N é um número inteiro que indica o número máximo de caracteres que poderão formar a expressão a ser associada à variável caractere var. Por exemplo:

program caractere

implicit none

character*8 var

No caso acima a variável var poderá receber uma expressão (alfanumérica) composta de no máximo 8 caracteres. Para atribuir uma expressão à variável CHARACTER usamos aspas simples. Por exemplo:

program caractere

implicit none

character*9 var1,var2

var1=´Teste.´ ! var1 recebe 6 caracteres, ok.

var2=´Isto eh um teste.´ ! Total de 17 caracteres. A variável receberá apenas os ! primeiros nove caracteres: “Isto eh u”

print*,var1

print*,var2

stop

end

Note que a expressão a ser atribuída à variável tipo caractere é fornecida entre aspas (simples ou duplas), e que caso existam espaços dentro da expressão (como em ‘Isto eh um teste’), estes espaços também ocuparão um caractere.

Para que no programa acima a frase atribuída à variável var2 seja impressa na tela de forma completa precisamos declarar var2 de forma a receber pelo menos 17 caracteres.

character*17 var1,var2 ! var1 e var2 podem receber até 17 caracteres.

ou

character*25 var1,var2 ! var1 e var2 podem receber até 25 caracteres.

ou

character*10 var1 ! var1 pode receber até 10 caracteres, enquanto que...

character*20 var2 ! var2 pode receber até 20 caracteres.

Todas as opções acima funcionariam para o nosso exemplo.

10.1. Manipulações com as variáveis do tipo caractere:

É possível também realizar algumas “operações” com as variáveis tipo caractere. Por exemplo, podemos concatenar (isto é, juntar) duas ou mais expressões em uma só bastando separar cada expressão por duas barras // em uma mesma linha e atribuir o resultado a uma variável caractere. Por exemplo:

program caractere2

implicit none

character*15 nome

nome=´CENTI´ // ´METROS´ ! Concatenando as expressões CENTI e METROS

print*, nome

stop

end

O resultado na tela será , pois o comando de // concatenou a expressão CENTI com a expressão METROS.

Outra forma de realizar concatenação de caracteres é utilizando uma outra variável tipo caracter. Por exemplo:

program caracteres

implicit none

character*15 var1

character*30 var2

var1=´quadrados´ ! Atribuimos à variável var1 a expressão quadrados.

var2=´Centi´ // ´metros´ // ´ ´ // var1 ! Concatenação de expressões.

print*, var2

stop

end

O resultado na tela será . Note que na concatenação realizada acima não precisamos colocar aspas em torno de var1 porque var1 é uma variável do tipo caractere e não uma expressão em si. Compare com:

program caracteres2

implicit none

character*15 var1

character*30 var2

var1=´quadrados´

var2=´Centi´ // ´metros´ // ´ ´ // ´var1´

print*, var2

stop

end

O resultado na tela será literalmente , porque ao colocarmos aspas em torno de var1 o compilador passou a entendê-la como sendo uma expressão literal e não como uma variável caractere. Portanto tome cuidado ao lidar com variáveis do tipo caractere.

Obs: Da mesma forma como variáveis inteiras e reais, cuidado para não “misturar” variáveis caracteres com reais ou inteiras numa mesma expressão de atribuição, porque acarretará em erro (já na compilação). Veja um exemplo que geraria um erro:

program caracteres3

implicit none

character*15 var1

character*30 var2

integer valor

valor=3

var1=’quadrados’

var2=valor // ´Centi´ // ´metros´ //´ ´// ´var1´ ! Concatenação ERRADA

print*, var2

stop

end

A variável valor é do tipo inteiro e portanto não pode ser incluída numa concatenação como se fosse uma variável caractere.

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 6

NOTA IMPORTANTE: Continuação de linha:

Aprendemos que no FORTRAN77 temos que editar todos os comandos do programa entre as colunas 7 e 72. Haverá situações, entretanto, em que temos que escrever uma linha mais longa, que inevitavelmente passaria da coluna 72.

Para fazer isto funcionar, o FORTRAN permite que usemos um indicador de continuação de linha. Este indicador pode ser qualquer caractere numérico ou alfabético (exceto o “zero”) posicionado obrigatoriamente na sexta coluna da linha imediatamente abaixo da linha que queremos continuar. Por exemplo, a linha abaixo vai além da coluna 72:

print*,´O resultado da divisão entre ´,variavel1,´ e ´,variavel2,´ eh ´:,variavel3

1 7 72 ( colunas

Com a utilização de um indicador de continuação de linha a mesma linha pode ser escrita como:

print*,´O resultado da divisão entre ´,variavel1,´ e ´,variavel2,´

&eh ´:,variavel3

1 6 7 72

O caractere “&”, posicionado na coluna 6 da linha imediatamente abaixo, indica para o compilador que tudo que for escrito nesta nova linha será, na verdade, uma continuação da linha anterior. Em outras palavras, as duas linhas serão interpretadas pelo compilador como sendo 1 única linha:

print*,´O resultado da divisão entre ´,variavel1,´ e ´,variavel2,´ eh ´:,variavel3

Com isto podemos escrever linhas longas no FORTRAN77. Por meio deste artifício podemos continuar uma determinada linha por até um máximo de 19 linhas de edição.

Lembre-se que você pode usar qualquer caractere alfanumérico na coluna 6 para ser um indicador de continuação de linha (exceto o “0”), inclusive o ponto de exclamação (!). Ou seja, quando posicionado na sexta coluna, o ponto de exclamação não será um indicador de comentário mas sim de continuação de linha, mesmo que o FORCE2.0 graficamente indique esta linha como sendo um comentário (através de italização da linha e atribuição de uma cor cinza a esta linha), como por exemplo:

print*,´O resultado da divisão entre ´,variavel1,´ e ´,variavel2,´

!eh ´:,variavel3

O FORCE2.0 italiza qualquer trecho que comece com (!), mas no caso acima a linha italizada não será um comentário porque o (!) foi posicionado na coluna 6. Portanto, cuidado.

Obs: Por uma questão de estilo, a maioria dos programadores opta por usar o “&” como indicador de continuação de linha.

Atenção: a linha a ser continuada não precisa obrigatoriamente ocupar todas as colunas 7 a 72 a que tem disponível. Veja o exemplo:

1 6 7 72

print*,´O resultado da exponenciacao entre ´,variavel1,´ e ´,varia

&vel2,´ eh ´:,variavel3

No caso acima utilizamos todas as colunas 7 a 72 da linha superior, mas com isto ficou muito estranho dividir o nome de variavel2 em varia numa linha e vel2 na continuação. Logo é melhor fazer:

1 6 7 72

print*,´O resultado da exponenciacao de ´,variavel1,´ por ´,

&variavel2,´ eh ´:,variavel3

Na versão acima não fomos até a coluna 72 na primeira parte da linha. Mas isto não acarreta em erro nem de compilação nem de execução.

11. Comandos de entrada e saída de dados em FORTRAN (input/output; I/O)

Nos programas que vimos até agora o comando de atribuição de valores para as variáveis utilizou apenas o sinal de “=”. Assim, a entrada de dados para os programas tem sido feita diretamente pela edição do código fonte, como em:

program converte

C Este programa converte um ângulo de graus para radianos e depois

C calcula o seu seno.

implicit none

real graus,radianos,seno,pi

pi=acos((1.0)

graus=30.0

radianos=graus*pi/180.

seno=sin(radianos)

print*,(O seno de (,graus,( graus eh igual a : (,seno

stop

end

Acima, se quiséssemos mudar o valor do ângulo em graus (isto é, alterar o dado de entrada) teríamos que editar o código fonte − mudando o ângulo, por exemplo, de 30( para 45( − salvá-lo, compilá-lo de novo e executá-lo. Isto é muito trabalhoso!

O FORTRAN admite outras maneiras de entrarmos com dados para os programas.

11.1. O comando READ para entrada (input) de dados.

A forma mais simples/básica de entrada de dados para o programa FORTRAN é diretamente via teclado no momento da execução do programa, sem precisar recompilar o código fonte a cada novo valor de entrada desejado. No exemplo do programa acima o ideal é que o usuário tenha total liberdade para fornecer o valor do ângulo em graus no momento da execução do programa. Para isto, usamos o comando READ, cuja sintaxe mais geral é:

READ(*,*) >

Obs: O que representam os asteriscos entre parênteses? Por enquanto basta que você saiba que o primeiro asterisco indica que o(s) dado(s) de entrada será(ão) fornecido(s) pelo usuário via teclado. O segundo asterisco indica que o(s) dado(s) de entrada não precisa(m) seguir uma formatação específica; mais adiante no curso voltaremos a estudar isto.

Com o comando READ o programa de conversão de graus para radianos pode ser re-escrito assim:

program converte

implicit none

real graus,radianos,seno,pi

pi=acos((1.0)

read(*,*) graus

radianos=graus*pi/180.

seno=sin(radianos)

print*,(O seno de (,graus,( graus eh igual a : (,seno

stop

end

Ao executarmos o programa acima ele aguardará que o usuário forneça o ângulo em graus (qualquer valor!) via teclado. Assim que o usuário digitar o valor desejado e teclar este valor será imediatamente atribuído à variável graus e o programa prosseguirá com a execução exatamente da mesma forma como na versão anterior, convertendo o valor de graus para radianos e escrevendo o resultado na tela. Logo, o usuário terá a oportunidade de executar o programa para qualquer valor de entrada desejado, sem precisar re-editar e re-compilar o programa a cada valor diferente.

Esta é uma forma alternativa (e mais eficiente) de atribuir valores às variáveis.

Naturalmente, no exemplo acima o usuário terá que saber qual o objetivo do programa na hora da execução do mesmo, pois senão ele ficará sem saber o quê fornecer como dado de entrada, e enquanto isto o programa ficará “parado” aguardando a ação do usuário.

Para tornar o programa mais interativo com o usuário o melhor é fazê-lo escrever na tela, logo no início da execução, uma mensagem que explique exatamente o quê deve ser fornecido como dado de entrada. Para isto podemos usar mais uma vez o comando (de saída) PRINT*:

program converte

implicit none

real graus,radianos,seno,pi

pi=acos((1.0)

print*,´Este programa converte angulos de graus para radianos.´

print*,´Forneca o angulo em graus:´

read(*,*) graus

radianos=graus*pi/180.

seno=sin(radianos)

print*,(O seno de (,graus,( graus eh igual a : (,seno

stop

end

Obs: Repare que sempre há uma vírgula separando o comando PRINT* daquilo que queremos que apareça na tela (seja uma frase ou o valor de uma variável). Mas não há vírgula separando o comando READ(*,*) daquilo que será lido.

read(*,*) variavel

print*, variavel

Atente para isto quando estiver escrevendo seu programa porque a falta de vírgula após PRINT* ou a presença de vírgula após READ(*,*) acarretará em erro de compilação.

É possível fazer o comando READ ler mais de um valor, bastando para isto separar cada variável por vírgula no código fonte:

READ(*,*) >

Por exemplo:

program resto_divisao

C Este programa calcula o resto da divisão entre dois valores reais.

implicit none

real num1,num2,resto

print*,´Este programa calcula o resto da divisão entre dois

&valores fornecidos pelo usuario.´

print*,´Forneca os dois valores (na ordem: dividendo e divisor):´

read(*,*) num1,num2

resto=mod(num1,num2)

print*,(O resto da divisao entre (,num1,( e (,num2,( eh: (,resto

stop

end

No momento da execução o usuário deverá escrever, na mesma linha, os dois valores separados por espaço e teclar . Ou então digitar o primeiro valor e teclar e depois digitar o segundo valor e teclar de novo; por exemplo:

34.4 15.0

ou:

34.4

15.0

O valor 34.4 será atribuído à variável num1 e o valor 15.0 será atribuído à variável num2.

Atente para a seguinte fonte de conflito: se a variável de entrada for do tipo real, como no exemplo acima, o usuário poderá fornecer via teclado um dado no formato real ou inteiro. Por exemplo, o valor 15.0 fornecido acima poderia ter sido escrito como 15, e no momento da atribuição para a variável real num2 o programa faria a conversão inteiro ( real automaticamente.

Mas no caso inverso poderá haver problema. Se a variável que recebe o dado de entrada for do tipo inteiro e o usuário fornecer este dado no formato real aí haverá erro de execução pois a conversão real ( inteiro automática não será realizada. Neste caso, para evitar conflitos, avise ao usuário (pelo comando PRINT*) que aquele dado TEM que ser fornecido no tipo inteiro.

O dado de entrada de um programa não tem que ser necessariamente um valor numérico. Pode ser também uma expressão alfabética (palavra, nome, ou frase); para isto basta que a variável que recebe a expressão seja declarada como do tipo caractere (CHARACTER). Por exemplo:

program subserviente

implicit none

character*30 meunome

print*,´Por favor, forneca teu nome (ateh 30 caracteres):´

read(*,*) meunome

print*, meunome, ( eh meu mestre!’

stop

end

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 7

11.1. O comando WRITE para saída (output) de dados.

De uma maneira geral a execução de um programa se dá segundo o seguinte fluxo de informação:

ENTRADA DE DADOS (input)

EXECUÇÃO DE CÁLCULOS

SAÍDA DOS RESULTADOS (output)

Para a entrada de dados vimos, na aula passada, o comando READ(*,*).

Já a saída dos resultados tem sido feita usando o comando print* (com os resultados sendo escritos na tela):

PRINT*, >

Mas existe uma maneira alternativa de executar esta tarefa, usando o comando WRITE, cuja sintaxe mais geral é:

WRITE(*,*) >

Obs: O primeiro asterisco indica que o resultado será escrito na tela; o segundo asterisco indica que o(s) dado(s) de saída não seguirá(ão) uma formatação específica.

Com o comando WRITE o programa de conversão de graus para radianos poderia ser re-escrito como:

program converte

implicit none

real graus,radianos,seno,pi

pi=acos((1.0)

read(*,*) graus

radianos=graus*pi/180.

seno=sin(radianos)

write(*,*) (O seno de (,graus,( graus eh igual a : (,seno

stop

end

Da mesma forma como feito com o comando print, o comando write também pode ser usado para aumentar a interatividade com o usuário antes da entrada dos dados:

write(*,*) ´Este programa calcula o seno do angulo fornecido.´

write(*,*) ´Forneca o angulo em graus:´

read(*,*) graus

Ou seja, o comando write (assim como o print) não se resume a um comando de saída de resultados, mas é um comando de saída de qualquer informação que o programador deseje.

Além disto, repare na sintaxe que, ao contrário do comando print, não há vírgula separando o comando write da informação de saída.

Quando usar o comando print e quando usar o write?

Os dois comandos são equivalentes, mas o comando write fornece mais funções do que o comando print. Veremos, mais adiante, que o comando write permite a opção de se escrever a informação de saída em um arquivo externo. Ao contrário, o comando print só permite que se escreva a informação de saída na tela do computador. Por isto um programador pode simplesmente “abolir” o uso do print se assim desejar.

O comando print é uma opção mais “prática” quando queremos escrever na tela uma informação que não contenha dados com uma formatação específica. Como, por exemplo, no caso da interatividade com o usuário:

print*, ´Este programa calcula o seno do angulo fornecido.´

print*, ´Forneca o angulo em graus:´

Ou então, quando simplesmente queremos pular uma linha na saída:

print*, ´Este programa calcula o seno do angulo fornecido.´

print*,

print*, ´Forneca o angulo em graus:´

Entretanto, quando a informação de saída se trata de resultados numéricos é mais comum (mas não obrigatório) optar-se pelo comando write. O comando write passa a ser obrigatório quando a saída precisar ser escrita em um arquivo externo – veremos isto mais adiante.

Abaixo estudaremos o que vem a ser a formatação da entrada e saída no FORTRAN.

12. Formatação de dados de entrada e saída:

A formatação controla a forma como os dados/variáveis devem ser fornecidas e/ou escritas. Por exemplo, podemos impor que a entrada ou saída de um determinado número real seja como uma das maneiras abaixo:

10.25

10.2

10.2567892

0.10257E+02

Até agora vimos apenas comandos de entrada (read) e saída (print e write) com formatação livre. Você já deve seguir se perguntado o que representa(m) aquele(s) asterisco(s) que aparece(m) junto com estes comandos; por exemplo:

print*,vari

read(*,*) vari

write(*,*) vari

Em print* o asterisco significa que a variável vari será impressa com formatação livre − isto é, o compilador FORTRAN utilizará uma formatação default de acordo com o tipo da variável vari.

Em read(*,*) e em write(*,*) o segundo asterisco dentro dos parênteses indica que o valor de vari será lido (no caso do read) ou impresso (no caso do write) com formatação livre.

Assim, se durante a execução do programa a variável vari receber, por exemplo, o valor 15.539 e imprimirmos o seu valor na tela com o comando

print*, vari

ou

write(*,*) vari

o resultado que aparecerá na tela será:

_15.359

(No exemplo acima e no restante da aula o símbolo “_” antes de um número é empregado para representar espaço em branco)

Mas e se quisermos impor que o valor de vari seja impresso com apenas 2 casas decimais? Neste caso poderíamos fazer:

print ‘(f5.2)’, vari

ou

write(*,’(f5.2)’) vari

ou ainda:

write(*,100) vari

100 format(f5.2)

No exemplo acima ao invés de utilizarmos um asterisco para indicar formatação livre, nós impomos um formato de saída, e o valor de vari (originalmente 15.359) será escrito como:

15.36

Veremos abaixo como fazer isto. Para cada tipo de variável (inteira, real, etc...) teremos uma maneira diferente de indicar a formatação desejada (seja no print, read ou write).

12.1. Formatação de variáveis inteiras:

A formatação de uma variável inteira (INTEGER) segue a sintaxe:

nIw ou niw

onde n é o número de vezes que aquela formatação específica será repetida e w é o número de espaços (ou o “comprimento”) que a variável ocupará na linha. Se n for igual a 1, então n poderá ser emitido.

Para ver como isto funciona considere o exemplo de saída formatada:

program formaint

implicit none

integer int1,int2,int3 ! Declaramos 3 variáveis inteiras.

print*, ‘Entre com três números inteiros positivos:’

read(*,*) int1,int2,int3 ! Leitura com formatação livre.

Vamos supor que o usuário forneça:

13 14 15

Em seguida escrevemos na tela com o comando print:

print*,int1,int2,int3 ! Formatação livre.

_13_14_15 ( na tela (três valores separados por 1 espaço)

print´(i7)´,int1 ! Apenas 1 variável inteira é impressa na tela, e ocupará 7 espaços

_ _ _ _ _13 ( na tela (5 espaços em branco + o número inteiro de 2 dígitos = total de 7 espaços).

print´(i5)´,int1 ! Apenas 1 variável inteira é impressa na tela, e ocupará 5 espaços

_ _ _ 13 ( na tela (3 espaços em branco + o número inteiro de 2 dígitos = total de 5 espaços).

print´(i10)´,int1 ! Apenas 1 variável inteira é impressa na tela, e ocupará 10 espaços

_ _ _ _ _ _ _ _ _13 ( na tela (8 espaços em branco + o número inteiro de 2 dígitos = total de 10

espaços).

print´(2i6)´,int1,int2 ! 2 variáveis inteiras serão impressas na tela, e cada uma

! ocupará 6 espaços.

_ _ _ _ 13_ _ _ _ 14 ( na tela (2 vezes [4 espaços em branco + o número inteiro de 2 dígitos = total de

6 espaços] )

print´(i6,i8)´,int1,int2 ! 2 variáveis inteiras serão impressas na tela: a primeira

! ocupará 6 espaços e a segunda 8 espaços.

_ _ _ _ 13 _ _ _ _ _ _ 14 ( na tela (primeiro: 4 espaços em branco + o número inteiro de 2 dígitos = total

de 6 espaços; segundo: 6 espaços em branco + o número inteiro de 2 dígitos =

total de 8 espaços ]

print´(3i5)´,int1,int2,int3 ! 3 variáveis inteiras serão impressas na tela, e cada uma

! ocupará 5 espaços.

_ _ _ 13_ _ _ 14_ _ _15 ( na tela (3 vezes [3 espaços em branco + o número inteiro de 2 dígitos = total

de 5 espaços] )

A formatação acima (3i5) é o mesmo que fazer (i5,i5,i5).

print 20, int1 ! Outra forma de fornecer a formatação em que apenas 1 variável

20 format(i5) ! inteira é impressa na tela, ocupando 5 espaços.

_ _ _ 13 ( na tela (3 espaços em branco + o número inteiro de 2 dígitos = total de 5 espaços).

print 100, int1,int2 ! Outra forma de fornecer a formatação em que 2 variáveis

100 format(2i6) ! inteiras são impressas na tela, ocupando 6 espaços cada uma.

_ _ _ _ 13_ _ _ _ 14 ( na tela (2 vezes [4 espaços em branco + o número inteiro de 2 dígitos = total de

6 espaços] )

Agora a mesma sequência com o comando write:

write(*,*) int1,int2,int3 ! Formatação livre

_13_14_15 ( na tela

write(*,´(i7)´) int1 ! Apenas 1 variável inteira é impressa na tela, e ocupará 7 espaços.

_ _ _ _ _13 ( na tela

write(*,´(i5)´) int1 ! Apenas 1 variável inteira é impressa na tela, e ocupará 5 espaços.

_ _ _13 ( na tela

write(*,´(i10)´) int1 ! Apenas 1 variável inteira é impressa na tela, e ocupará 10 espaços.

_ _ _ _ _ _ _ _ _13 ( na tela

write(*,´(2i6)´) int1,int2 ! 2 variáveis inteiras serão impressas na tela, e cada uma

! ocupará 6 espaços.

_ _ _ _ 13_ _ _ _ 14 ( na tela

write(*,´(i6,i8)´) int1,int2 ! 2 variáveis inteiras serão impressas na tela: a primeira

! ocupará 6 espaços e a segunda 8 espaços.

_ _ _ _ 13 _ _ _ _ _ _ 14 ( na tela

write(*,´(3i5)´) int1,int2,int3 ! 3 variáveis inteiras serão impressas na tela, e cada

! uma ocupará 5 espaços.

_ _ _ 13_ _ _ 14_ _ _15 ( na tela

write(*,FMT=´(3i5)´) int1,int2,int3 ! Uma outra maneira de fornecer a formatação 3i5

write(*,FMT=21) int1,int2,int3 ! Uma terceira maneira de fornecer a formatação 3i5

21 format(3i5)

write(*,22) int1,int2,int3 ! Uma quarta maneira de fornecer a formatação 3i5

22 format(3i5)

Nota importante 1: A última maneira acima é a mais empregada. O número usado como “endereço” para o formato é chamado de rótulo ou label.

write(*,22) int1,int2,int3

22 format(3i5)

O programador pode usar qualquer número inteiro de até 5 dígitos como rótulo. Não é obrigatório indicar o formato associado ao rótulo imediatamente após a linha em que o formato é usado. Os rótulos com os formatos podem, por exemplo, ser escritos todos nas últimas linhas do programa (na verdade esta é a maneira mais empregada):

program exemplo

implicit none

integer var1,var2,var3

print*,´Forneca 3 valores inteiros:´

read(*,*)var1,var2,var3

........

write(*,45) var1,var2,var3

........

45 format(i10,i4,i12)

stop

end

Nota importante 2: E se tentarmos imprimir um número cujo tamanho (“comprimento”) ultrapasse aquele da formatação? Por exemplo:

var1=35679 ! Um número inteiro de 5 dígitos

write(*,25) var1 ! Saída com formato I3 => 3 espaços apenas

25 format(I3)

Na tela o número 35679 não aparecerá! Apenas uma seqüência de asteriscos ***. Logo, sempre que ao invés de um valor aparecer esta seqüência de asteriscos significa que existe um conflito entre o valor e a respectiva formatação de saída.

O mesmo problema ocorreria se var1 recebesse o valor abaixo:

var1= −134

write(*,15) var1

15 format(I3)

Apesar do número inteiro ter apenas 3 dígitos, ele é negativo. O sinal de (−) também ocupa 1 espaço e portanto a formatação I3 não será capaz de acomodá-lo. Neste exemplo a formatação I4 (ou I5, ou In com qualquer n > 3) funcionaria.

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 8

ALGUNS EXERCÍCIOS PRÁTICOS:

Edite, salve, compile e execute os programas abaixo:

(1) Programa que concatena variáveis do tipo caractere:

program concatena

C Este programa exercita a manipulação de caracteres.

implicit none

character*6 nom1,nom2,nom3

character*20 nom4

print*,“Este programa exemplifica o processo de concatenacao de ca

&racteres.”

print*,“Forneca tres nomes de ateh 6 letras:”

read(*,*) nom1,nom2,nom3

C Combina os nomes.

nom4=nom1 // “ ” // nom2 // “ ” // nom3

write(*,*) nom4

stop

end

(2) Programa que converte velocidades de metros por segundo para quilômetros por hora (1 m/s = 3,6 km/h):

program conversao_vel

C Este programa converte velocidades de m/s para km/h.

implicit none

real mps,kmph

print*,“Este programa converte velocidades de m/s para km/h:”

print* ! Pulando 1 linha

C Entrada de dados.

print*,“Forneca a velocidade em m/s:”

read(*,*) mps

C Conversão:

kmph=mps*3.6

C Saída dos resultados:

write(*,*) “A velocidade de ” ,mps,“ metros por segundo equivale a

&”,kmph,“quilometros por hora.”

stop

end

(3) Programa que calcula a hipotenusa [h2 = (a2+b2)] e a área [(base × altura) / 2] de um triângulo (retângulo) dados os seus catetos a e b.

program pitagoras

C Este programa calcula a hipotenusa e a área de um triângulo retângulo.

implicit none

integer cateto1,cateto2

real hipo,area

print*,“Este programa utiliza o Teorema de Pitagoras para calcular

& a hipotenusa de um triangulo retangulo dados seus dois catetos, e

& fornece tambem a area deste triangulo.”

print* ! Pula 1 linha

print*,“Forneca os catetos do triangulo (valores inteiros!):”

read(*,*) cateto1,cateto2

C Calcula a hipotenusa:

hipo=sqrt(float(cateto1**2+cateto2**2)) ! O radicando tem que ser real

C Calcula a área: (Não é obrigatório usar o comando float abaixo, mas é recomendável)

area=float(cateto1*cateto2)/2.

C Escreve os resultados

print*

print*,“RESULTADOS:”

print*,“A hipotenusa eh:”

write(*,21) int(hipo)

C Apenas para exercitar a formatação de números inteiros:

write(*,'(i4)') int(hipo)

write(*,'(i4,i6,i8)') int(hipo),int(hipo),int(hipo)

write(*,FMT=23) int(hipo),int(hipo),int(hipo)

print* ! Pula 1 linha

print*,“A area eh:”

write(*,*) area

print* ! Pula 1 linha

C Lista de formats

21 format(i12)

23 format(i6,2i8)

stop

end

(4) Programa que calcula a posição e velocidade finais e o deslocamento total de uma partícula em movimento retilíneo uniformemente variado (MRUV).

S = So + Vo t + At2/2 (posição)

V = Vo + At (velocidade)

S-So ( (deslocamento total)

program MRUV

C Este programa calcula para um dado instante a posição final, o

C deslocamento total e a velocidade final de uma partícula em movimento

C retilíneo acelerado (com aceleração constante; MRUV).

implicit none

real s_ini,s_fim,delta_s,vel_ini,vel_fim

real acel,tempo

print*,“Este programa calcula, para um dando instante, a posicao

&e velocidade finais e o deslocamento total de uma particula em

&movimento retilineo uniformemente variado (MRUV).”

print*

print*,“ENTRADA DE DADOS:”

print*,“Forneca a posicao (m) e velocidade (m/s) iniciais da parti

&cula:”

read(*,*) s_ini,vel_ini

print*,“Forneca a aceleracao da particula (em m/s**2):”

read(*,*) acel

print*,“Forneca o instante (em segundos) para o qual deseja ter os

& resultados (tem que ser um valor maior que zero):”

read(*,*) tempo

C Calcula a posição final:

s_fim=s_ini+vel_ini*tempo+(acel/2.)*tempo**2

C Calcula o deslocamento total

delta_s=s_fim−s_ini

C Calcula a velocidade final

vel_fim=vel_ini+acel*tempo

C Escreve os resultados

print*

print*,“RESULTADOS:”

print*,“A posicao final da particula eh:”

write(*,*) s_fim,“ metros.”

print*,“O deslocamento total da particula eh de:”

write(*,*) delta_s,“ metros.”

print*,“A velocidade final da particula eh de:”

write(*,*) vel_fim,“ m/s.”

print*

stop

end

(5) Programa que calcula o período (T) de um pêndulo simples dados seu comprimento (L) e o ângulo de deslocamento (().

T = 2( (L / g)1/2 [1 + (1/4)sin2((/2)]

program pendulo

C Este programa calcula o período de um pêndulo simples dados o seu comprimento

C e o ângulo de deslocamento (em relação à posição de equilíbrio).

implicit none

real pi,grav

real comp,ang,termo1,termo2,periodo

parameter (grav=9.81) ! Declarando a aceleração constante da gravidade

print*,“Este programa calcula o periodo de um pendulo simples ”,

&“dados o seu comprimento e o angulo de deslocamento.”

print*

print*,“ENTRADA DE DADOS:”

print*,“Forneca o comprimento do pendulo (em cm):”

read(*,*) comp

print*,“Forneca o angulo de deslocamento da particula (em graus):”

read(*,*) ang

C Convertendo o comprimento de centímetros para metros:

comp=comp/100.

C Convertendo o ângulo de graus para radianos:

pi=acos(−1.0)

ang=ang*pi/180.

C Calculando o período do pêndulo:

termo1=2.*pi*sqrt(comp/grav)

termo2=1.+(1./4.)*(sin(ang/2.))**2

periodo=termo1*termo2

C Escrevendo os resultados:

print*

print*,“RESULTADO:”

print*,“O periodo do pendulo (em segundos) eh:”,periodo

print*

stop

end

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 9

12.1. Formatação de variáveis reais: formatação tipo F.

A formatação de uma variável REAL segue a sintaxe:

nfw.d ou nFw.d

, onde n é o número de vezes que a formatação será repetida, w é o número TOTAL de espaços (ou o “comprimento”) que a variável ocupará na linha, e d é o número de dígitos à direita do ponto decimal (i.e., o número de casas decimais). A seguinte condição deve ser satisfeita: w ( d + 3 sempre. Se n for igual a 1, então n poderá ser omitido.

Por exemplo, vamos supor que as variáveis reais var1 e var2 recebam, no meio de um programa, os seguintes valores:

var1= (17.5704365

var2=203.664

Em seguida escrevemos na tela (os exemplos abaixo são com o comando write, mas poderiam ser com o comando print também):

**Exemplo 1:

write(*,100) var1

100 format(F11.3) ! Apenas 1 variável é impressa na tela, e ocupará 11 espaços no total,

! dos quais 3 espaços serão reservados para as casas decimais.

_ _ _ _(17.570 ( na tela

Repare que o sinal negativo “(” e o ponto “.” ocupam 1 espaço cada um.

**Exemplo 2:

WRITE(*,202) var1

202 FORMAT(f10.5) ! Apenas 1 variável é impressa na tela, e ocupará 10 espaços no total,

! dos quais 5 espaços serão reservados para as casas decimais.

_(17.57044 ( na tela

Repare que ocorre arredondamento na última casa decimal (compare com o valor originalmente atribuído a var1).

**Exemplo 3:

write(*,121) var1,var2

121 FORMAT(2F10.5) ! Duas variáveis são impressas na tela, com cada uma ocupando 10

! espaços no total, dos quais 5 são reservados para as casas decimais.

_(17.57044_203.66400 ( na tela

Repare que as duas últimas casas decimais foram preenchidas com “0”, porque o valor originalmente atribuído a var2 tem apenas três casas decimais.

**Exemplo 4:

WRITE(*,99) var1,var2

99 format(f12.2,f10.1) ! Duas variáveis são impressas na tela: a primeira ocupará 12

! espaços no total, dos quais 2 serão reservados para as casas

! decimais; a segunda ocupará 10 espaços no total, dos quais 1 será

! reservado para as casas decimais.

_ _ _ _ _ _(17.57_ _ _ _ _203.7 ( na tela

**Exemplo 5

WRITE(*,99) var2,var1

99 format(f12.2,f10.1) ! É igual à formatação do exemplo anterior, mas note que agora

! invertemos a ordem das variáveis.

_ _ _ _ _ _203.66_ _ _ _ _(17.6 ( na tela

**Exemplo 6: e se imprimirmos duas variáveis mas com uma formatação para n=1?

write(*,100) var1,var2 ! Duas variáveis na tela.

100 format(f10.5) ! Formato para 1 única variável, pois n foi omitido.

_(17.57044

_203.66400 ( os dois valores serão impressos com a mesma formatação mas em

linhas diferentes.

**Exemplo 7:

var1= (17.5704365

var2=203.664

var3=15.0

write(*,150) var1,var2,var3 ! Três variáveis na tela.

150 format(2f10.5) ! Formato para duas variáveis apenas.

_( 17.57044_203.66400

_ _15.00000 ( todos os valores serão impressos com a mesma formatação. Os dois primeiros na mesma linha porque a formatação foi declarada com n=2.

Ou seja, as formatações ilustradas nos exemplos 6 e 7 funcionam, mas o mais adequado é declarar uma formatação coerente com o número de variáveis que serão impressas. E veremos mais adiante que é possível controlar explicitamente o comando de “pular linha”.

Nota importante 1: a saída pode ser formatada também para uma combinação de variáveis inteiras e reais; mas atente para a correspondência entre a formatação declarada e a ordem com que as variáveis são impressas.

**Exemplo 8: considere que as variáveis var1 e var2 sejam reais e var3 e var4 inteiras:

var1= (17.5704365

var2=203.664

var3=234

var4=10021

write(*,100) var1,var2,var3,var4

100 format(2F12.2,I5,I9) ! As variáveis var1 e var2 recebem a formatação F12.2

! A variável var3 recebe a formatação I5

! A variável var4 recebe a formatação I9

_ _ _ _ _ _(17.57_ _ _ _ _ _ 203.66_ _234_ _ _ _10021 ( na tela

write(*,110) var1,var2,var3,var4

110 format(F12.4,F10.1,2I6) ! A variável var1 recebe a formatação F12.4

! A variável var2 recebe a formatação F10.1

! As variáveis var3 e var4 recebem a formatação I6

_ _ _ _(17.5704_ _ _ _ _203.7_ _ _234_10021 ( na tela

write(*,111) var3,var1,var4,var2

111 format(i10,f11.5,i10,f11.5) ! As variáveis var1 e var2 recebem a formatação f11.5

! As variáveis var3 e var4 recebem a formatação i10

_ _ _ _ _ _ _234_ _(17.57044_ _ _ _ _ 10021_ _203.66400 ( na tela

Outra forma de escrever a mesma seqüência acima é:

write(*,111) var3,var1,var4,var2

111 format(2(i10,f11.5)) ! Uma maneira alternativa de declarar a formatação:

! i10,f11.5,i10,f11.5 ( 2(i10,f11.5)

Mas haverá erro se você tentar escrever:

write(*,112) var3,var1,var4,var2

112 format(2i12,2f10.5) ! Na correspondência a formatação inteira i12 será

! atribuída à variável real var1e a formatação real f10.5

! será atribuída à variável inteira var4: isto ocasionará um

! erro de execução.

Portanto muito cuidado quando formatar a saída de uma seqüência de variáveis.

12.2. Formatação de variáveis reais: formatação tipo E [notação científica].

O número 12.540,5 pode ser escrito em notação científica como 0,125405 ( 105. E o número (0,000345 em notação científica fica (0,345 ( 10- 3. Este tipo de notação também pode ser usada em FORTRAN, como ilustrado abaixo:

0,125405 ( 105 em FORTRAN é escrito como: 0.125405E+05

(0,345 ( 10- 3 em FORTRAN é escrito como: (0.345E(03

Observe que 4 espaços são sempre reservados para escrever o expoente de dez: E(**

A formatação de uma variável REAL em notação científica segue a sintaxe:

new.d ou nEw.d

, onde n é o número de vezes que a formatação será repetida, w é o número TOTAL de espaços que a variável ocupará na linha [incluindo], e d é o número de dígitos à direita do ponto decimal (i.e., o número de casas decimais). A seguinte condição deve ser satisfeita: w ( d + 7 sempre. Se n for igual a 1, então n poderá ser omitido.

Vamos supor que as variáveis reais var1, var2 e var3 recebam os seguintes valores:

var1= (174.5704365

var2=0.09203664

var3=0.1456

Em seguida escrevemos na tela:

write(*,100) var1,var2,var3

100 format(E11.3,e10.1,e12.3)

_(0.175E+03_ _ _0.9E(01_ _ _0.146E+00

3 casas decimais 1 casa decimal 3 casas decimais

12.3. Formatação de caracteres:

É comum, nas saídas de resultados, combinarmos valores numéricos com caracteres alfabéticos, como em uma frase por exemplo:

write(*,*) “O resultado da divisão entre”,v1,“ e ” ,v2, “ é: ”,v3

Neste caso, se quisermos formatar a saída teremos que levar em consideração a presença dos caracteres. Para isto usamos a formatação “A”, cuja sintaxe geral é:

nA ou na

, onde n é o número de vezes que a formatação será repetida.

No exemplo acima vamos supor que v1, v2 e v3 sejam variáveis do tipo real. Então podemos formatar a saída assim:

write(*,100) “O resultado da divisão entre”,v1,“ e ” ,v2, “ é: ”,v3

100 format(A,F5.1,A,F5.1,A,F5.1)

, cuja correspondência é:

“O resultado da divisão entre”,v1,“ e ” ,v2, “ é: ”,v3

A , F5.1 , A , F5.1 , A , F5.1

ou alternativamente:

write(*,100) “O resultado da divisão entre”,v1,“ e ” ,v2, “ é: ”,v3

100 format(3(A,F5.1)) ! Uma maneira alternativa de declarar a formatação:

! A,F5.1,A,F5.1,A,F5.1 ( 3(A,F5.1)

O mesmo vale para variáveis do tipo caractere, como em:

character*28 plv1 ! Declarando as variáveis do tipo caractere

character*3 plv2

character*4 plv3

real v1,v2,v3 ! Declarando as variáveis do tipo real

....< programa >....

plv1=“ O resultado da divisão entre”

plv2=“ e ”

plv3=“ é: ”

write(*,100) plv1,v1,plv2,v2,plv3,v3 ! Saída utilizando variáveis caracteres

100 format(3(A,F5.1))

stop

end

12.4 Outras opções de controle:

Na formatação da saída de resultados de um programa é possível acrescentar a opção de adicionar espaço(s) em branco (utilizando a letra X) e saltar linha(s) (utilizando /), assim:

/ Salta 1 linha

// Salta 2 linhas

///// Salta 5 linhas

< isto é, cada “/” indica 1 linha a ser saltada >

nX Acrescenta n espaços em branco (p.ex. 3X significa “acrescente 3 espaços”)

Por exemplo, suponha uma variável inteira chamada val:

val=360

write(*,30) val

30 format(/,6X,i5) ! Pula 1 linha, depois acrescenta 6 espaços, e depois imprime ! val com cinco espaços.

Na tela sairá:

______________ < salta 1 linha inteira >

_ _ _ _ _ _ _ _360 < salta 6 espaços e só depois escreve 360 com formato i5 >

Outro exemplo:

val1=360

val2=45

write(*,31) val1,val2

31 format(///,2X,i5,//,3X,i9) ! Pula 3 linhas, depois acrescenta 2 espaços, depois ! imprime va1l com cinco espaços, depois pula 2 linhas,

! depois acrescenta 3 espaços, e depois imprime val2 com 9

! nove espaços.

Na tela sairá:

_____________

_____________

_____________ < salta 3 linha inteiras consecutivamente >

_ _ _ _360 < salta 2 espaços e só depois escreve 360 com formato i5 >

_____________

_____________ < salta 2 linha inteiras consecutivamente >

_ _ _ _ _ _ _ _ _ _45 < salta 3 espaços e só depois escreve 360 com formato i9 >

12.5 As formatações utilizando o comando READ (formatação da entrada de dados):

Assim como a saída de dados do programa pode ser formatada com os comandos print e write, a entrada de dados no programa também pode ser formatada, utilizando o comando read.

A forma de declarar a formatação de entrada dos dados é idêntica àquela descrita acima para a saída de dados. Assim, considere os exemplos:

integer var1,var2

read(*,100) var1,var2 ! Leitura de dois valores inteiros via teclado.

100 format(2i6) ! Os dois valores inteiros têm que ser fornecidos com formato i6.

real var1,var2,var3

read(*,101) var1,var2,var3 ! Leitura de três valores reais via teclado.

101 format(f10.2,f9.3,f8.1) ! O primeiro valor real tem que ser fornecido com formato

! f10.2, o segundo valor com formato f9.3 e o terceiro valor

! com formato f8.1

integer int1,int2

real teste,marte

read(*,102) int1,int2,teste,marte ! Leitura de dois valores inteiros e dois valores reais ! via teclado.

102 format(2I3,2F9.2) ! Os dois valores inteiros têm que ser fornecidos com

! formato I3, e os dois valores reais com formato f9.2

Em todos os exemplos acima a formatação dos dados de entrada tem que ser seguida rigorosamente, caso contrário ocorrerá erro de execução porque as variáveis receberão valores incorretos. Seja o exemplo:

program teste

implict none

real v1,v2 ! Declara duas variáveis reais

print*, “Forneça dois valores reais:”

read(*,202) v1,v2 ! Lê dois valores reais com formato F5.1

write(*,*) v1,v2

202 format(2F5.1)

stop

end

Suponha que o usuário forneça via teclado os três valores sem obedecer a formatação declarada pelo rótulo 202, como em:

_14.25_13.5 < formatação não obedecida >

A atribuição dos valores (caso ela ocorra!) será realizada de maneira completamente equivocada:

_14.25 v1 receberá o valor 14.2

_14.25_13.5 v2 (possivelmente )receberá o valor 513.

Com isto a execução do programa (caso ela prossiga) estará completamente comprometida.

Como é muito fácil um usuário cometer um erro na formatação ao digitar os valores de entrada via teclado, geralmente não declaramos uma formatação de entrada para os dados fornecidos via teclado ( isto é, deixamos a entrada de dados (via teclado) ser feita com formatação livre (READ(*,*)).

Mais adiante veremos que a entrada de dados no programa pode ser feita via um arquivo de dados. Neste caso sim podemos exigir que a entrada siga uma formatação específica.

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 10

13. PROGRAMAÇÃO ESTRUTURADA

Em um programa estruturado o “escoamento lógico” da informação é governado por três estruturas básicas de controle: SEQUÊNCIA, SELEÇÃO E REPETIÇÃO. Em todos os exemplos que vimos até este momento, a lógica dos programas possuía apenas a estrutura de seqüência, que pode ser esquematizada assim:

início do programa

comando 1

comando 2

comando 3

.....

final do programa

Entretanto, na vida prática, raramente conseguiremos executar um programa contendo apenas esta estrutura seqüencial simples. Geralmente um programa terá bifurcações/desvios ou repetições no seu “escoamento lógico”. Por exemplo, considere o programa abaixo:

program divisao

implicit none

integer val1,val2

print*,“Este programa realiza a divisão entre dois valores

&inteiros.”

print*,“Forneca os dois valores (inteiros):”

read(*,*) val1,val2

write(*,*) “A divisão de ”,val1,“ por ”,val2,“ eh: ”,val1/val2

stop

end

Caso o usuário forneça o segundo valor como sendo igual a zero a execução do programa será interrompida com uma mensagem de erro, pois a divisão por zero gerará um problema de “overflow” (isto é, a geração de um número maior que a capacidade máxima de memória do computador). Porém, este problema pode ser eliminado caso façamos, antes da divisão, um teste para saber se o segundo valor fornecido pelo usuário é igual a zero. Algo do tipo:

O valor fornecido pelo usuário para a variável val2 é igual a zero? Caso sim, escreva na tela uma mensagem informando que o programa não poderá executar a divisão pois o divisor é igual a zero. Caso não, realize a divisão e escreva na tela o resultado.

Este procedimento representa uma estrutura de seleção que gera um desvio ou bifurcação no “escoamento lógico” do programa porque a tarefa de realizar a divisão fica submetida à condição do divisor ser diferente de zero. Como fazer isto? Primeiro precisamos conhecer as expressões lógicas relacionais.

13.1. Expressões lógicas (relacionais) simples e variáveis do tipo LOGICAL:

Em FORTRAN77 as expressões lógicas relacionais são:

.LT. [menor que (Less Than)] <

.GT. [maior que (Greater Than)] >

.EQ. [igual a (EQual to)] =

.LE. [menor ou igual a (Less or Equal to)] (

.GE. [maior ou igual a (Greater or Equal to)] (

.NE. [diferente de (Not Equal to)] (

Importante: os pontos “.” antes e depois das letras são partes integrantes das expressões lógicas relacionais. E podemos usar também letras minúsculas: .lt. , .gt. , .eq. , .le. , .ge. , .ne.

O resultado destas expressões só pode ser verdadeiro (.TRUE.) ou falso (.FALSE.). Por exemplo, suponha que uma determinada variável real var1 receba o valor 5.1:

var1=5.1

Então:

var1 .EQ. 0.0 ( Testa se o valor de var1 é igual a zero. O resultado desta expressão relacional é falso (.FALSE.) porque o valor atribuído a var1 [5.1] não é igual 0.

(var1 * 2.) .GT. 8.5 ( Testa se o valor de var1 multiplicado por 2 é maior do que 8.5. O resultado desta expressão relacional é verdadeiro (.TRUE.) porque o valor atribuído a var1 multiplicado por 2 [10.2] é maior que 8.5

var1 .LE. 5.1 ( Testa se o valor de var1 é menor ou igual a 5.1. O resultado desta expressão relacional é verdadeiro (.TRUE.) porque o valor atribuído a var1 [5.1] é igual a 5.1

var2=123.2

var1 .NE. var2 ( Testa se o valor de var1 é diferente do valor de var2. O resultado desta expressão relacional é verdadeiro (.TRUE.) porque o valor atribuído a var1 [5.1] é diferente do valor atribuído a var2 [123.2].

Ou seja, repare que em FORTRAN não lidamos apenas com informações alfanuméricas, mas também com informações de natureza lógica (verdadeiro ou falso).

Observação: neste ponto podemos apresentar um outro tipo de variável: a variável do tipo LOGICAL (lógico). Por exemplo:

program exemplo

implicit none

real var1,var2

logical teste ! Declarando uma variável do tipo logical

var1=33.2

var2=999.0

teste=(var1 .NE. var2)

No exemplo acima a variável lógica teste receberá o valor .TRUE. (verdadeiro) porque 33.2 (valor atribuído a var1) é diferente de 999.0 (valor atribuído a var2).

Também é possível atribuir a uma variável lógica os valores verdadeiro ou falso de forma direta, assim:

teste=.TRUE.

ou

teste=.FALSE.

Edite, salve, compile e execute o programa abaixo. Experimente diversos pares de valores e veja o resultado que aparece na tela.

program logico

implicit none

real var1,var2

logical t1,t2,t3,t4 ! Declarando 4 variáveis do tipo LOGICAL

print*,“Forneca dois valores reais à sua escolha:”

read(*,*) var1,var2

t1=(var1 .LT. var2)

t2=(var1 .EQ. var2)

t3=(var1 .GT. var2)

t4=(var1 .NE. var2)

print*

print*,“Resultados” ! “F” representa .FALSE. e “T” representa .TRUE.

print*,“Resultado do teste (var1 .LT. var2) eh:”,t1

print*,“Resultado do teste (var1 .EQ. var2) eh:”,t2

print*,“Resultado do teste (var1 .GT. var2) eh:”,t3

print*,“Resultado do teste (var1 .NE. var2) eh:”,t4

stop

end

13.2. Expressões lógicas compostas:

Em FORTRAN-77 as duas expressões lógicas compostas mais usadas são:

.AND. [e]

.OR. [ou]

Como antes, os pontos “.” antes e depois das letras são partes integrantes das expressões compostas. Além disto, podemos também usar letras minúsculas: .and. , .or.

Por exemplo, suponha que uma determinada variável real var1 tenha recebido o valor 5.1, e uma variável var2 recebido o valor 90.3.

var1=5.1

var2=90.3

Então:

var1 .GT. 0.0 .AND. var1 .GT. var2

( Testa se o valor de var1 é maior do que zero e (ao mesmo tempo!) maior que o valor de var2. O resultado desta expressão relacional é falso (.FALSE.) porque apesar do valor atribuído a var1 [5.1] ser maior que zero, ele não é maior que o valor atribuído a var2 [90.3]. Isto é, o fato de var1 ser maior que zero é condição necessária mas não suficiente para que o resultado da expressão composta seja verdadeira.

var1 .GT. 0.0 .AND. var2 .GT. var1

( Testa se o valor de var1 é maior do que zero e (ao mesmo tempo!) se o valor de var2 é maior do que o de var1. O resultado desta expressão relacional é verdadeiro (.TRUE.) porque o valor atribuído a var1 [5.1] é maior que zero e , ao mesmo tempo, o valor de var2 [90.3] é maior que o de var1.

var1 .GT. 0.0 .OR. var1 .GT. var2

( Testa se o valor de var1 é maior que zero ou se o valor de var1 é maior do que o valor de var2. O resultado desta expressão relacional é verdadeiro (.TRUE.) porque o valor atribuído a var1 [5.1] é maior que zero e esta é condição necessária e suficiente para que o resultado da expressão composta seja verdadeiro.

var1 .GT. 200.0 .OR. var2 .GT. var1

( Testa se o valor de var1 é maior que 200.0 ou se o valor de var2 é maior do que o valor de var1. O resultado desta expressão relacional é verdadeiro (.TRUE.) porque apesar do valor atribuído a var1 (5.1) não ser maior que 200.0, o valor associado a var2 é maior que o de var1, e esta é uma condição necessária e suficiente para o resultado da expressão composta ser verdadeiro.

Observação: Para deixar o programa mais legível, nas expressões compostas é recomendável separar cada condição por um par de parênteses. Por exemplo:

(var1 .GT. 0.0) .AND. (var1 .GT. var2)

(var1 .GT. 0.) .AND. (var2 .GT. var1)

(var1 .GT. 200.) .OR. (var2 .GT. var1)

Edite, salve, compile e execute o programa abaixo. Experimente diversos pares de valores e veja o resultado que aparece na tela. (Repare que o valor atribuído a teste5 advém de uma expressão lógica composta consistindo de 3 condições.)

program logico2

implicit none

real var1,var2

logical teste1,teste2,teste3,teste4,teste5

print*,'Forneca dois valores reais quaisquer:'

read(*,*),var1,var2

teste1=(var1 .LT. 0.) .AND. (var2 .GT. var1)

teste2=(var1 .GT. 3.) .AND. (var1 .GE. var2)

teste3=(var1 .GT. (12.0) .OR. (var2 .GT. var1)

teste4=(var1 .LE. 200.) .OR. (var2 .GT. var1)

teste5=(var1 .LT. 0.) .AND. (var1 .NE. (5.2) .AND. (var2 .GT. var1)

print*

print*,“Resultados” ! “F” representa .FALSE. e “T” representa .TRUE.

write(*,*) teste1,teste2,teste3,teste4,teste5

stop

end

13.3 Desvios condicionais no fluxo do programa (1): o comando IF ( ) THEN

Vamos supor agora que queiramos que uma determinada seqüência de comandos no programa seja condicionada por uma expressão lógica (seja ela simples ou composta). Este é o caso do programa divisão que exemplificamos antes. Queremos escrever uma mensagem para o usuário caso ele forneça um divisor igual a zero. É aí que entra o comando if ( ) then (que em inglês significa “se ( ) então”). A sintaxe deste comando é assim:

if (expressão lógica condicional) then

seqüência de comandos

endif [ou end if]

A seqüência de comandos contida entre o if ( ) then e o endif só será executada caso o resultado da expressão lógica condicional seja verdadeiro. Se o resultado for falso o programa não executará esta seqüência (ela será ignorada).

Edite, salve, compile e execute o programa abaixo. Na execução tente fazer uma divisão por 0 e veja o que acontece.

program divisao

implicit none

integer int1,int2,int3

print*,“Este programa realiza a divisão de 2 valores inteiros.”

print*,“Forneca dois valores inteiros (o segundo eh o divisor):”

read(*,*) int1,int2

if (int2 .NE. 0) then ! Condição imposta para a execução dos comandos

int3=int1/int2

write(*,*) “A divisão de ”,int1,“ por ”,int2,“ eh: ”,int3

endif ! Fim da seqüência condicional de comandos

print*, “Fim do programa.”

stop

end

Por causa do comando if (int2 .NE. 0) then , se fornecermos o segundo valor (isto é, o divisor) como sendo igual a zero, o programa não executará a divisão, pois o fluxo da execução do programa vai se desviar do cálculo da divisão. Em outras palavras, os comandos:

int3=int1/int2

write(*,*) “A divisão de ”,int1,“ por ”,int2,’“ eh: ”,int3

só serão executados se int2 ( 0

Observação: repare no exemplo acima que a seqüência de comandos entre o if ( ) then e o endif foi escrita com uma tabulação mais à direita. Esta tabulação é chamada de “indentação”. Fazemos isto não porque seja obrigatório, mas porque torna o programa mais legível, representando uma boa prática de programação. Ao fazermos isto, os comandos cuja execução é condicional ficam mais destacados. Sempre faça a “indentação” no comando if ( ) then.

Podemos modificar o programa acima para ele ficar um pouco mais sofisticado. Por exemplo, poderíamos escrever na tela um aviso explícito se o usuário fornecer um divisor igual a zero. Para isto precisaríamos adicionar mais um if ( ) then , assim:

program divisao2

implicit none

integer int1,int2,int3

print*,“Este programa realiza a divisão de 2 valores inteiros.”

print*,“Forneca dois valores inteiros (o segundo eh o divisor):”

read(*,*) int1,int2

C O IF abaixo é para atender a condição de int2 diferente de zero.

if (int2 .NE. 0) then

int3=int1/int2

write(*,*) “A divisão de ”,int1,“ por ”,int2,“ eh: ”,int3

endif ! Fim do primeiro IF

C O IF abaixo é para atender a condição de int2 igual a zero.

if (int2 .EQ. 0) then

print*,“Foi fornecido um divisor igual a zero.”

endif ! Fim do segundo IF

print*, “Fim do programa.”

stop

end

Apesar do programa acima ter ficado mais completo que o anterior, existe uma maneira mais eficiente (e mais elegante!) de executá-lo. Para isto precisaremos usar o if ( ) then else.

13.4 Bifurcações condicionais no fluxo do programa (2): o comando IF ( ) THEN ELSE

No caso do comando if ( ) then apenas 1 (uma) seqüência condicional de comandos é admitida: aquela a ser executada caso o resultado da expressão lógica condicional seja verdadeiro. Se quisermos que uma outra seqüência condicional seja executada, no caso do resultado ser falso, então usamos o comando if ( ) then [seqüência 1] else [seqüência 2] (que em inglês significa “se ( ) então [seqüência 1] senão [seqüência 2]”). A sintaxe deste comando é assim:

if (expressão lógica condicional) then

seqüência 1 de comandos

else

seqüência 2 de comandos

endif [ou end if]

A seqüência 1 de comandos listada entre o if () then e o else só será executada caso o resultado da expressão lógica condicional seja verdadeiro. Se o resultado for falso o programa executará a seqüência 2 (aquela entre o else e o endif).

Edite, salve, compile e execute o programa abaixo.

program divisao3

implicit none

integer int1,int2,int3

print*,“Este programa realiza a divisão de 2 valores inteiros.”

print*,“Forneca dois valores inteiros (o segundo eh o divisor):”

read(*,*) int1,int2

if (int2 .NE. 0) then ! Condição imposta para o cálculo da divisão

int3=int1/int2

write(*,*) “A divisão de ”,int1,“ por ”,int2,“ eh: ”,int3

else ! Caso contrário...

print*,“Foi fornecido um divisor igual a zero.”

endif ! Fim das seqüências condicionais de comandos

print*,“Fim do programa.”

stop

end

Tente fazer uma divisão por 0 e veja o que acontece.

Note que agora ocorre não simplesmente um desvio, mas uma bifurcação no “escoamento lógico” do programa: se int2 for diferente de zero o programa calculará a divisão; caso contrário (ou seja, se int2 for igual a zero) o programa escreverá o aviso na tela.

Observação: repare de novo na “indentação” empregada. Os respectivos if ( ) then, else e endif ficaram alinhados na mesma coluna, enquanto que os comandos de execução condicional ficaram mais à direita:

if (expressão lógica condicional) then

comando 1

comando 2

.....

comando N

else

comando a

comando b

.....

comando Y

endif

Este estilo de programação não é obrigatório (não haverá erro de compilação nem de execução se você não realizar a “indentação”), mas é altamente recomendável segui-lo para deixar seu programa mais legível para outros programadores.

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 11

Mais um exemplo do uso da construção IF ( ) THEN ELSE: solução da equação do 2º grau. Escreva, compile e execute.

program quadratica

C Este programa encontra as raízes da equação do segundo grau dados os

C três coeficientes da equação quadrática (ax^2 + bx + c = 0) fornecidos pelo usuário.

implicit none

real coefa,coefb,coefc,disc,raiz1,raiz2

print*,“Forneça os coeficientes a, b e c da equação:”

read(*,*) coefa,coefb,coefc

disc=coefb**2(4.0*coefa*coefc ! Calculando o discriminante

if (disc .LT. 0.) then

print*,“O discriminante eh negativo, igual a: ”,disc

print*,“Não há raízes reais.”

else

raiz1=((1.*coefb+sqrt(disc))/(2.*coefa)

raiz2=((1.*coefb(sqrt(disc))/(2.*coefa)

print*,“As raízes da equação são: ”,raiz1,raiz2

endif

stop

end

13.5. Bifurcações múltiplas (“aninhamento”) com o comando IF ( ) THEN ELSE

É possível realizar mais de um desvio ou bifurcação no “escoamento lógico” do programa com o uso consecutivo do comando if ( ) then else. Para isto fazemos o chamado “aninhamento” do comando, da seguinte maneira:

if (expressão lógica condicional 1) then ! Este é o IF mais externo

seqüência_1 de comandos

else

if (expressão lógica condicional 2) then ! Este é um IF interno ou “aninhado”

seqüência_2 de comandos

else

seqüência_3 de comandos

endif ! Termina o bloco if ( ) then mais interno (i.e., fecha o segundo bloco)

endif ! Termina o bloco if ( ) then mais externo (i.e., fecha o primeiro bloco)

A sequência_1 de comandos só será executada caso o resultado da primeira expressão lógica condicional seja verdadeiro. Se este resultado for falso então a seqüência 1 não será executada e o programa avaliará a segunda expressão lógica condicional. A sequência_2 de comandos só será executada caso o resultado da segunda expressão lógica condicional seja verdadeiro. Se este resultado também for falso então o programa não executará a seqüência_2 e executará a sequência_3 de comandos.

Resumindo:

Seqüência_1 de comandos ( será executada caso o resultado do primeiro if ( ) then resultar em verdadeiro (.true.); e neste caso as seqüências_2 e 3 não serão executadas.

Seqüência_2 de comandos ( será realizada caso o resultado do primeiro if ( ) then resultar em falso (.falso.) e o resultado do segundo if ( ) then (o if “aninhado”) resultar em verdadeiro (.true.); e neste caso as seqüências_1 e 3 não serão executadas.

Seqüência_3 de comandos ( será realizada caso o resultado do primeiro if ( ) then resultar em falso (.false.) e o resultado do segundo if ( ) then (o if “aninhado”) também resultar em falso (.false.); e neste caso as seqüências_1 e 2 não serão executadas.

Obs: Note que para cada bloco if ( ) then aberto, deverá haver um endif (ou end if) fechando. Podemos criar quantas bifurcações múltiplas quanto precisarmos.

Podemos usar o “aninhamento” do comando if ( ) then para re-escrever nosso programa de solução da equação do 2º grau. Escreva, compile e execute:

program quadratica2

C Este programa encontra as raízes da equação do segundo grau dados os

C três coeficientes da equação quadrática (ax^2 + bx + c = 0) fornecidos pelo usuário.

implicit none

real coefa,coefb,coefc,disc,raiz1,raiz2

print*,“Forneça os coeficientes a, b e c da equação:”

read(*,*) coefa,coefb,coefc

disc=coefb**2(4.0*coefa*coefc ! Calculando o discriminante

if (disc .LT. 0.) then ! Abre o primeiro bloco IF: verifica se disc < 0

print*,“O discriminante é negativo, igual a: ”,disc

print*,“Não há raízes reais.”

else

if (disc .EQ. 0.) then ! Abre o segundo bloco IF: verifica se disc = 0

raiz1=((1.*coefb)/(2.*coefa)

print*,“O discriminante eh igual a zero.”

print*,“A raiz repetida da equação é: ”,raiz1

else ! Se disc não for < 0 nem = 0, então...

raiz1=(-1*coefb+disc)/(2.*coefa)

raiz2=(-1*coefb(disc)/(2.*coefa)

print*,“As raizes da equação são: ”,raiz1,raiz2

endif ! Fecha o bloco if (disc .EQ. 0.) then

endif ! Fecha o bloco if (disc .LT. 0.) then

stop

end

Observação: Boa prática de programação: para cada novo bloco de if ( ) then que for aberto, faça uma nova “indentação”, tabulando a nova seqüência de comandos um pouco mais para a direita.

Uma outra sintaxe admitida para o “aninhamento” do comando if ( ) then else é da seguinte forma:

if (expressão lógica condicional 1) then

seqüência_1 de comandos

else if (expressão lógica condicional 2) then

seqüência_2 de comandos

else

seqüência_3 de comandos

endif ! Termina o dois blocos if ( )then

Esta sintaxe executará o programa da mesma forma como na sintaxe anterior, mas note algumas diferenças: apenas 1 comando endif fecha os dois blocos de if ( ) then; não fazemos a “indentação” do bloco de IF( )THEN mais interno.

Podemos escrever nosso programa de solução da equação do 2º grau também desta maneira.

program quadratica3

C Este programa encontra as raízes da equação do segundo grau dados os

C três coeficientes da equação quadrática (ax^2 + bx + c = 0) fornecidos pelo usuário.

implicit none

real coefa,coefb,coefc,disc,raiz1,raiz2

print*,“Forneça os coeficientes a, b e c da equação:”

read(*,*) coefa,coefb,coefc

disc=coefb**2(4.0*coefa*coefc ! Calculando o discriminante

if (disc .LT. 0.) then

print*,“O discriminante é negativo, igual a: ”,disc

print*,“Não há raízes reais.’

else if (disc .EQ. 0.) then

raiz1=((1.*coefb)/(2.*coefa)

print*,“O discriminante é igual a zero.”

print*,“A raiz repetida da equação é: ”,raiz1

else

raiz1=((1.*coefb+(sqrt(disc)))/(2.*coefa)

raiz2=((1.*coefb((sqrt(disc)))/(2.*coefa)

print*,“As raízes da equação são: ’,raiz1,raiz2

endif ! Fecha o bloco if (disc .EQ. 0.) then e o bloco if (disc .LT. 0.) then

stop

end

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 12

13.6. Estruturas de repetição:

Em programação é comum nos depararmos com situações em que precisamos repetir diversas vezes a execução de um determinado comando (ou sequência de comandos). Nestas situações, escrever o comando repetidamente, linha por linha, pode se transformar numa tarefa extremamente cansativa e pouco producente. Por exemplo, vamos supor que (por um motivo qualquer) você precise escrever um programa que exiba na tela a seguinte repetição:

print*,“Repetição 1.”

print*,“Repetição 2.”

print*,“Repetição 3” Escrever 500 linhas no código fonte!

.....

print*,“Repetição 500.”

Felizmente não precisamos fazer isto. Na programação FORTRAN77 estruturada existe a chamada estrutura de repetição (ou loop, ou laço) que permite a execução repetida de um ou mais comandos de uma maneira controlada. O número de vezes que a repetição é executada é controlado de duas maneiras possíveis: (a) laço controlado por um contador, ou (b) laço controlado por uma expressão lógica condicional.

13.6.1. Estrutura de repetição (1): o comando DO [ ] CONTINUE

Na sua forma mais geral, o conceito de laço de repetição pode ser entendido pelo esquema abaixo:

|[pic] |

A sintaxe para esta estrutura de repetição de comandos utiliza o comando DO ...comandos... CONTINUE (=“faça” ...comandos... “continue”), assim:

DO n contador = valor_inicial, valor_máximo

comando(s) a ser(em) repetido(s)

n CONTINUE

, onde n é um “rótulo” (número inteiro) que aponta para o comando continue que, por sua vez, delimita o final da seqüência de comandos que desejamos repetir ( em outras palavras, o(s) comando(s) a ser(em) repetido(s) é(são) aquele(s) entre o DO e o CONTINUE. O contador deve ser uma variável (recomenda-se fortemente que seja do tipo inteiro).

Vejamos um exemplo:

INTEGER count ! A variável count será o contador.

DO 10 count=1,9 ! Controla o número de vezes em que a repetição é feita.

comando ou sequência de comandos a serem repetidos.

10 CONTINUE

No exemplo acima os comandos serão repetidos nove vezes; em outras palavras, os comandos serão repetidos até que a variável count, que começa com valor 1, atinja o valor 9 numa contagem que avança de 1 em 1. Neste exemplo o rótulo é dado pelo número 10. Assim, todos os comandos presentes entre a linha que começa com DO e a linha 10 CONTINUE serão repetidos nove vezes.

A variável inteira count representa o contador que controla o laço de repetição (count=1: executa os comandos uma primeira vez; count=2: executa os comandos pela segunda vez; count=3: executa os comandos pela terceira vez; count=4: executa os comandos pela quarta vez; ....count=9: executa os comandos pela nona e última vez). Observe que não precisamos escrever explicitamente o avanço da contagem (count=count+1); este incremento é realizado automaticamente quando chega-se em continue.

Escreva, compile e execute o programa abaixo:

program laco

implicit none

integer count

do 10 count=1,9 ! Controla o número de vezes em que a repetição é feita.

print*,“Aprendendo o comando DO.”

10 continue ! O comando “continue” automaticamente soma 1 ao valor de count.

stop

end

Obs: repare que entre o do e o continue é aconselhável que o(s) comando(s) seja(m) “indentado(s)” para a direita, para facilitar a leitura do código fonte.

Outro exemplo:

INTEGER i

DO 300 i=1,1000

Comando(s) a ser(em) repetido(s).

300 CONTINUE

No exemplo acima os comandos serão repetidos mil vezes, e a variável inteira i representa o contador que controla o laço de repetição.

Outro exemplo:

INTEGER j

DO 100 j=5,24

comando(s) a ser(em) repetido(s)

100 CONTINUE

No exemplo acima os comandos serão repetidos vinte vezes (e não 24 vezes!), pois o valor inicial do contador j é 5. (Ou seja, j=5 executa os comandos uma primeira vez; j=6: executa os comandos pela segunda vez; j=7: executa os comandos pela terceira vez;....j=24: executa os comandos pela vigésima e última vez).

Outra sintaxe possível:

DO n contador = valor_inicial, valor_máximo, incremento

comando(s) a ser(em) repetido(s)

n CONTINUE

, onde incremento é um número inteiro que controla o “tamanho do passo” na contagem. Por exemplo, se incremento=2 então a contagem será feita de 2 em 2 (e não de 1 em 1).

INTEGER conta

DO 12 conta=1,10,2 ! Agora incluímos um no incremento diferente de 1

comando(s) a ser(em) repetido(s)

12 CONTINUE ! O “continue” automaticamente soma 2 em count.

No exemplo acima o contador conta vai variar de 1 a 10, mas sempre “saltando” 1 valor da contagem (isto é, somando-se automaticamente 2 ao contador), assim: conta=1: executa os comandos uma primeira vez; conta=3: executa os comandos pela segunda vez; conta=5: executa os comandos pela terceira vez;.....conta=9: executa os comandos pela quinta e última vez.

Outro exemplo:

DO 100 conta=4,19,3

comando(s) a ser(em) repetido(s)

100 CONTINUE ! O “continue” automaticamente soma 3 em count.

No exemplo acima o contador conta vai variar de 4 a 16, mas sempre somando 3 ao contador (isto é, “salta” 2 valores da contagem), assim: conta=4: executa os comandos uma primeira vez; conta=7: executa os comandos pela segunda vez; conta=10: executa os comandos pela terceira vez;.....conta=19: executa os comandos pela sexta e última vez.

Os dois exemplos a seguir executam exatamente a mesma coisa um mesmo número de vezes:

DO 100 conta=4,19,3

print*,“Aprendendo o comando DO.”

100 CONTINUE

DO 20 i=1,6 ! Aqui não indicamos o valor do incremento. Então a contagem será de 1 em 1.

print*,“Aprendendo o comando DO.”

20 CONTINUE

Em ambos os casos frase “Aprendendo o comando DO.” será impressa na tela 6 vezes.

Obs: Por default, o incremento somado ao contador é 1. É por isto que não precisamos indicar este incremento quando queremos que a contagem seja feita de 1 em 1.

Cuidado com a interpretação do papel do contador; os exemplos abaixo ajudam a compreender melhor a diferença entre o valor do contador e o número de vezes que os comandos são executados:

DO 100 conta=4,19,3

print*,’O valor do contador é: ’,conta

100 CONTINUE

DO 20 i=1,6

print*,’O valor do contador é: ’,i

20 CONTINUE

Em ambos os exemplos acima a frase “O valor do contador é:” será impressa na tela 6 vezes, mas será que o valor do contador será o mesmo?

Edite, compile e execute um programa que faça os dois laços exemplificados acima. Não se esqueça de declarar o contador como sendo uma variável do tipo inteiro.

Obs: No exemplo simples acima não faz sentido optar por escrever DO 100 conta=4,19,3 quando a forma DO 100 conta=1,6 realizaria exatamente a mesma coisa com a vantagem de não precisar começar a contagem no 4 e nem somar 3 a cada passo . Entretanto, dependendo da operação que desejamos realizar, pode ser que tenhamos que começar a contagem de um número diferente de 1 ou criar “saltos” na contagem.

Os valores inicial e final do contador (assim como o incremento da contagem) podem ser fornecidos por variáveis, assim:

INTEGER comeca,termina

comeca=1

termina=20

DO 101 i=comeca,termina

comando(s) a ser(em) repetido(s)

101 CONTINUE

Seria o mesmo que fazer DO 101 i=1,20

É possível também realizar o laço com a contagem indo de trás para frente (contador regressivo). Por exemplo:

DO 13 i=50,1,-1 ! Contador regressivo

print*,“O valor do contador é: ”,i

13 CONTINUE

No exemplo acima o valor inicial de i é 50 e seu valor final é 1, com a contagem sendo regressiva de 1 em 1.

Ou ainda:

DO 13 i=50,1,-2 ! Contador regressivo

print*,“O valor do contador é: ”,i

13 CONTINUE

No exemplo acima o valor inicial de i é 50 e seu valor final é 1, com a contagem sendo regressiva de 2 em 2.

Escreva, compile e execute o programa abaixo. (Este programa lista na tela todos os pontos da curva y = (2x entre dois limites INTEIROS de x [indicados pelo usuário] em incrementos INTEIROS [também indicados pelo usuário]).

program laco2

implicit none

integer inicio,fim,incr,i,valor

print*,“Forneça os limites inferior e superior (inteiros) de x:”

read(*,*) inicio,fim

print*,“Agora forneça o incremento (inteiro) para y=-2x:”

read(*,*) incr

print*, “ X Y”

print*,“********************”

do 45 i=inicio,fim,incr

valor=(-1)*2*i

print*,i,“ ”,valor

45 continue

stop

end

Note, pelo exemplo acima, que o contador pode ser empregado em qualquer expressão matemática dentro do laço como se fosse uma variável qualquer, lembrando-se apenas que a cada novo incremento o seu valor vai mudar.

Outro exemplo, agora “aninhando” um comando if ( ) then else dentro do laço do:

program laco3

implicit none

integer inicio,fim,incr,i,valor,count1,count2

print*,“Forneça os limites inferior e superior (inteiros) de x:”

read(*,*) inicio,fim

print*,“Agora forneça o incremento (inteiro) para y=-2x:”

read(*,*) incr

count1=0

count2=0

print*, “X Y”

print*,“********************”

do 45 i=inicio,fim,incr

valor=(-1)*2*i

if (valor .gt. -10) then

count1=count1+1

else

count2=count2+1

endif

print*,i,“ ”,valor

45 continue

print*,“O número de valores acima de -10 é: ”,count1

print*,“O número de valores iguais ou abaixo de -10 é: ”,count2

stop

end

13.6.2. Estrutura de repetição (2): o comando DO [ ] ENDDO

Uma outra sintaxe para a estrutura de repetição no FORTRAN77 é a que segue abaixo:

DO contador = valor_inicial, valor_final

comando(s) a ser(em) repetido(s)

ENDDO (ou END DO)

Na sintaxe acima, não há a necessidade de usarmos um rótulo e nem a expressão continue. O final da seqüência de comandos a ser repetida é dado pelo enddo. A estrutura de repetição acima é mais moderna e elegante do que a vista na aula passada. Dê preferência por utilizar esta segunda forma.

Exemplo:

DO j=1,45

comando(s) a ser(em) repetido(s)

ENDDO

Exemplo:

DO conta=4,19,3

print*,“Aprendendo o comando DO.”

ENDDO

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 13

13.6.3. Estrutura de repetição (3): o comando DO WHILE [ ] END DO

Vimos até aqui o laço de repetição sendo controlado por um número de repetições o qual é determinado por um contador (seções 13.6.1 e 13.6.2). Podemos, alternativamente, controlar o laço de repetição por uma expressão lógica condicional. Enquanto esta expressão lógica fornecer um resultado verdadeiro (.TRUE.) a repetição continuará; quando o resultado desta expressão for falso (.FALSE.) a repetição será interrompida.

A sintaxe é:

DO WHILE (expressão lógica condicional)

comando(s) a ser(em) repetido(s)

END DO [ou ENDDO]

(“do while” = “faça enquanto”)

O programa abaixo usa o comando do while ( ) enddo para calcular o fatorial (n!) de um número inteiro n qualquer fornecido pelo usuário.

program fatorial

implicit none

integer i,numero,incr

real fator

fator=1. ! Não esquecer de começar com 1

print*, “Forneça um numero INTEIRO para o calculo do fatorial:”

read(*,*) numero

incr=numero

if (numero .LT. 0) then

print*, “O fatorial não é definido para um número negativo.”

else

if (numero .EQ. 0) then

print*, “O fatorial de 0 é igual a 1.”

else

do while (incr .GT. 0) ! Enquanto incr for maior que zero faça...

fator=fator*float(incr) ! Multiplica

print*,incr,fator

incr=incr-1

end do

print*

print*,"RESULTADO:"

print*,"O fatorial de ",numero," é igual a:",fator

print*

end if

end if

stop

end

No exemplo acima a multiplicação continua para os valores de incr regredindo um a um até que o valor 0 seja atingido. Por exemplo: se numero for igual a 4, então a sequência de execução fica:

fator = 1. ! No início fator recebe o valor 1

incr = numero = 4

Dentro do laço de repetição temos:

fator = 1.*4. = 4. ! Agora fator recebe o valor 4

incr = 4-1 = 3, que é > 0, então repete o processo:

fator = 4.*3.=12. ! Agora fator recebe o valor 12 (isto é, 4 x 3)

incr = 3-1 = 2, que é > 0, então repete o processo:

fator = 12.*2.=24. ! Agora fator recebe o valor 24 (isto é, 4 x 3 x 2)

incr = 2-1 = 1, que é > 0, então repete o processo:

fator = 24.*1.=24. ! Agora fator recebe de novo o valor 24 (isto é, 4 x 3 x 2 x 1)

incr = 1-1 = 0, que NÃO é > 0, interrompendo a repetição.

O fatorial de 4 (4! = 4 x 3 x 2 x 1) foi então calculado.

Obs: O comando do while ( ) enddo pode ser empregado para repetir a execução de um programa quantas vezes se desejar. Por exemplo, peguemos o programa que vimos aula passada e vamos modificá-lo para que seja executado quantas vezes o usuário quiser:

program laco4

implicit none

integer inicio,fim,incr,i,valor,conta,maxim

conta=0

print*, “Quantas vezes este programa deve ser executado?”

read(*,*) maxim

if (maxim .le. 0) then ! Bifurcação

print*,“Você forneceu um número menor que 1.”

else

do while (conta .lt. maxim) ! Repetição

print*

print*,“Forneça os limites inferior e superior (inteiros) de x:”

read(*,*) inicio,fim

print*,“Agora forneça o incremento (inteiro) para y=-2x:”

read(*,*) incr

print*, “ X Y”

print*,“********************”

do i=inicio,fim,incr ! Repetição aninhada

valor=(-1)*2*i

print*,i,“ ”,valor

enddo

conta=conta+1

enddo

endif

stop

end

Acima temos, então, um exemplo de um comando do [ ] enddo aninhado dentro de um comando do while [ ] enddo, que por sua vez está dentro de um bloco if ( ) then else.

14. Maneiras alternativas de fornecer dados de entrada e gerar os dados de saída:

14.1. Forma alternativa de entrada via teclado e saída para tela:

Em todos os programas que vimos até agora os dados de entrada foram fornecidos via teclado e os resultados foram impressos na tela. Por exemplo, suponhamos que existam duas variáveis chamadas grav e peso. Diversas formas de leitura ou saída dos valores foram estudadas:

read(*,*) grav,peso ! Leitura dos dados via teclado, com formatação livre.

read(*,100) grav,peso ! Leitura dos dados via teclado, com formatação especificada.

100 format(2F7.1)

print *, grav,peso ! Impressão dos valores na tela, com formatação livre.

print 121, grav,peso ! Impressão dos valores na tela, com formatação especificada.

121 format(2F7.1)

write(*,*) grav,peso ! Impressão dos valores na tela, com formatação livre.

write(*,220) grav,peso ! Impressão dos valores na tela, com formatação especificada.

220 format(1X,f6.1,f5.1)

etc....

Um forma alternativa de escrever os resultados de grav e peso na tela é utilizar a sintaxe abaixo:

write(6,*) grav,peso ! Impressão dos valores na tela, com formatação livre.

ou

write(6,211) grav,peso ! Impressão dos valores na tela, com formatação especificada.

211 format(2f5.1)

O número “6” substituindo o primeiro “*” no comando write também informa que o resultado deve ser escrito na tela. Ou seja, tanto “*” quanto “6” ocupando o primeiro campo entre parênteses após o write informam que a opção default será empregada para a saída dos resultados: na tela.

Um forma alternativa de fornecer os valores de grav e peso via teclado é utilizar a sintaxe abaixo:

read(5,*) grav,peso ! Fornecimento dos valores via teclado, com formatação livre.

ou

read(5,222) grav,peso ! Fornecimento dos valores via teclado, com formatação especificada.

222 format(2f5.1)

O número “5” substituindo o primeiro “*” no comando read também informa que os valores das variáveis serão fornecidos via teclado. “Ou seja, tanto “*” quanto “5” ocupando o primeiro campo entre parênteses após o read informam que a opção default será empregada para a entrada dos resultados: via teclado.

O exemplo abaixo utiliza as sintaxes alternativas para leitura de dados via teclado e impressão de valores na tela:

program outra_sintaxe

implicit none

real var1,var2,var3,var4

write(6,*) “Forneça 4 valores reais:” ! Tem a mesma função que write(*,*)

read(5,*) var1,var2,var3,var4 ! Tem a mesma função que read(*,*)

write(6,201) var1,var2,var3,var4 ! Tem a mesma função que write(*,201)

201 format(4F11.2)

stop

end

14.2. Arquivos de entrada e saída de dados: os comandos OPEN e CLOSE.

E se, no exemplo acima, desejarmos fornecer os valores de entrada de var1, var2, var3 e var4 não através do teclado, mas através de um arquivo texto (.txt)? Como faremos? Neste caso devemos escolher um número (diferente de 5) que servirá de identificador deste arquivo de entrada de dados, e então empregaremos o comando OPEN antes de ler os valores de var1, var2, var3, e var4. Sintaxe geral do comando open:

OPEN (UNIT=N, FILE=“nome_do_aquivo.txt”, STATUS=“old”)

ou STATUS=“unknown”

, onde N é um número inteiro diferente de 5 (pois unit=5 significa “entrada via teclado”) que servirá para identificar o arquivo de dados de entrada. Note que o nome do arquivo tem que ser indicado, para ser associado à unidade de número N.

Por exemplo, vamos supor que tenhamos um arquivo chamado dados.txt contendo os quatro valores reais (var1, var2, var3, e var4). Então, antes de ler os valores, temos que abrir este arquivo:

open (unit=3, file=“dados.txt”, status=“old”)

No exemplo acima a unidade (unit) 3 será associada ao arquivo dados.txt. Neste exemplo o arquivo de dados tem que estar localizado no mesmo diretório do arquivo FORTRAN executável (.exe). Caso este arquivo encontre-se em outro diretório qualquer precisaremos informar o caminho inteiro do arquivo. Por exemplo, se o arquivo dados.txt estiver localizado em C:\Programas então teremos que fazer:

open (unit=3, file=“C:\/Programas\/dados.txt”, status=“old”)

A barra normal “/” após a barra invertida “\” é necessária para que o programa encontre o arquivo no diretório correto. Mas isto é válido apenas para a plataforma Windows que estamos usando nesta disciplina (em uma plataforma Linux bastaria colocar “C:/Programas/dados.txt”).

Somente após o comando open é que podemos então ler os valores de var1, var2, var3 e var4:

read(3,*) var1,var2,var3,var4

Os valores var1, var2, var3 e var4 são lidos do arquivo de entrada associado à unidade 3, e não via teclado.

Se após a leitura do arquivo nós não precisarmos mais mantê-lo aberto é necessário fechá-lo com o comando close:

close(3)

Obviamente, antes de executar o programa o arquivo de dados de entrada tem que ser criado. Criamos este arquivo texto (.txt) utilizando um editor de texto simples (por exemplo o Nedit no Linux, ou o WordPad (Bloco de Notas) no Windows, salvando o arquivo no formato texto). Crie um arquivo contendo os valores de var1, var2, var3 e var4 (separar por espaço):

33.1 45.6 2345.678 2111.46

Salve este arquivo com o nome dados.txt no mesmo diretório em que você salva os seus arquivos FORTRAN.

Então edite e execute o programa abaixo: (Agora você não precisará entrar com os valores via teclado.)

program leitura

implicit none

real var1,var2,var3,var4

open (unit=10,file=“dados.txt”, status=“old”) ! Abre o arquivo dados.txt

read(10,*) var1,var2,var3,var4 ! Lê os dados do arquivo dados.txt

write(6,201) var1,var2,var3,var4

close(10) ! Fecha o arquivo dados.txt

201 format(4F11.2)

stop

end

Os valores de var1, var2, var3 e var4 aparecerão na tela.

Obs: O argumento status=“old” dentro do comando open indica que o arquivo dados.txt existe antes da execução do programa.

E se, agora, nós quisermos que a saída/resultado seja impressa em um outro arquivo ao invés de ser indicada na tela? Neste caso empregaremos de novo o comando open, mas agora para abrir um arquivo novo (não pré-existente) que conterá a saída desejada.

Por exemplo, no exemplo abaixo, após lermos os valores de var1, var2, var3 e var4 do arquivo dados.txt, nós dividimos todos os valores por 2 e depois jogamos o resultado em outro arquivo, chamado de saida.txt:

program leitura2

implicit none

real var1,var2,var3,var4

real nvar1,nvar2,nvar3,nvar4

open (unit=10,file=“dados.txt”, status=“old”) ! Arquivo de entrada

open (unit=11,file=“saida.txt”, status=“new”) ! Arquivo de saída

read(10,*) var1,var2,var3,var4

nvar1=var1/2.

nvar2=var2/2.

nvar3=var3/2.

nvar4=var4/2.

write(11,201) nvar1,nvar2,nvar3,nvar4

print*, “O resultado encontra-se no arquivo de saida.”

close(10)

close(11)

201 format(4F12.3)

stop

end

O resultado será impresso no arquivo saida.txt que será criado no mesmo diretório onde está localizado o arquivo executável.

(O argumento status=‘new’ dentro do segundo comando open indica que o arquivo saida.txt não existe antes da execução do programa. Logo, ee você for executar de novo este mesmo programa, lembre-se de deletar o arquivo saida.txt. Ou então, se quiser evitar deletar este arquivo toda vez que for rodar o programa, substitua status=“new” por status=“unknown”).

Agora refaça o programa acima, mas formatando a entrada dos dados para números reais ocupando oito espaços, sendo que destes oito espaços dois sejam reservados para as casas decimais. Você provavelmente terá que editar de novo o arquivo de entrada para satisfazer esta formatação de entrada de dados.

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 14

ALGUNS EXERCÍCIOS PRÁTICOS:

(1) Laços de repetição aninhados:

O exemplo abaixo imprime na tela uma tabela de multiplicação, que ilustra claramente o funcionamento de laços aninhados. Edite, compile e execute:

program multi

C Este programa produz uma tabela de multiplicação de

C uma sequência de dois números inteiros variando dentro

C do domínio indicado pelo usuário.

implicit none

integer inic1,inic2,fim1,fim2,i,j,mult

print*

C Entrada de dados:

print*,“Forneça o domínio de variação do primeiro número:”

read(*,*) inic1,fim1

print*,“Forneça o domínio de variação do segundo número:”

read(*,*) inic2,fim2

C Multiplicação e saída de dados:

print*

print*,“RESULTADOS (i=primeiro número, j=segundo número)”

print*,“ i j i*j”

print*,“**************”

do i=inic1,fim1

do j=inic2,fim2

mult=i*j

write(*,200) i,j,mult

enddo

enddo

200 format(3i6)

stop

end

(2) Leitura e saída de dados em arquivos:

Escreva, compile e execute um programa FORTRAN77 que leia os dados abaixo (de um arquivo) e crie um arquivo de saída contendo dados de consumo do veículo em km/litro.

km rodados litros de gasolina consumidos

371.7 56.1

399.0 37.3

486.0 48.0

141.5 10.5

426.4 50.4

90.0 7.8

(3) Física Experimental: regressão linear simples; método dos mínimos quadrados.

Suponha que em um experimento de Física Experimental avaliando a influência da temperatura sobre uma resistência elétrica você tenha coletado os seguintes dados:

Temperatura (T) [(C] Resistência (R) [ohms]

20.0 761

31.5 817

50.0 874

71.8 917

91.3 1018

Ao plotar estes resultados em um gráfico de resistência (ordenada) versus temperatura (abscissa) você percebe que a relação entre as duas variáveis é aproximadamente linear. Então você resolve ajustar uma reta (i.e., uma função linear) que melhor descreva a relação descrita por estes dados.

R = aT + b

(a coeficiente angular da reta, b coeficiente linear da reta).

Esta reta será uma EQUAÇÃO DE REGRESSÃO que poderá ser usada para “prever” o valor da resistência R dada uma temperatura T qualquer dentro da faixa acima. Para ajustar esta curva você opta então pelo método dos mínimos quadrados, no qual os coeficientes a e b são estimados por:

a = [pic] b = [pic]

onde:

[pic] é a soma dos valores de T;

[pic]é a soma dos quadrados de T;

[pic] é a soma dos produtos dos T e R correspondentes;

[pic] são as médias de R e T, respectivamente;

n é o número de medidas (R x T) feitas.

Escreva e execute um programa FORTRAN77 que leia de um arquivo os valores coletados na experiência e calcule os valores de m e b (e exiba a equação de regressão na tela). Em seguida utilize este programa para “prever” o valor de R dada uma temperatura T fornecida pelo usuário (entre 20(C e 90(C).

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 15

15. VETORES:

Em Física a noção de vetor está associada a uma grandeza cujo significado físico depende da especificação de uma magnitude e uma direção. A direção da grandeza vetorial pode ser indicada em um espaço bidimensional (2 componentes para o vetor), tridimensional (3 componentes), ou n-dimensional (n componentes). [Lógico que acima de 3 dimensões a noção de vetor é mais abstrata; mas continua sendo um vetor!].

Uma notação comumente empregada para representar um vetor é através da notação matricial. Seja por exemplo um vetor P de 3 componentes (X1,X2,X3) [X1 na direção x, X2 na direção y e X3 na direção z]. Podemos representar P como:

[pic]

Ou como: [pic]

Em FORTRAN a noção de vetor difere um pouco do conceito puramente físico de vetor, uma vez que um vetor em FORTRAN pode ser definido também para uma grandeza que fisicamente é um escalar (por exemplo, temperatura). Por outro lado, da mesma forma como em Física o conceito de vetor agrega mais de 1 informação em uma mesma variável (magnitude e direção), em FORTRAN o conceito de vetor tem a ver com o fato de que uma única variável, se declarada na forma de vetor, pode ter associada a ela mais de 1 endereço de memória, ao invés de um endereço único como vimos até agora:

integer aluno ! O compilador reservará 1 (e apenas 1) espaço de memória para

! armazenar o valor atribuído à variável “aluno”

Se, acima, aluno fosse declarada como uma variável inteira na forma de vetor o compilador reservaria n espaços de memória para esta variável, onde n é a dimensão do vetor aluno (lembrando que aluno não precisa ser necessariamente uma variável que represente fisicamente um vetor), e então aluno poderia receber n valores inteiros diferentes: 1 valor para cada um dos n espaços de memória reservados.

Para entender isto melhor considere o exemplo de um programa que leia, a partir de um arquivo, a nota de 30 alunos e calcule a média da turma:

program notas

implicit none

C Declara 31 variáveis:

real aluno1,aluno2,aluno3,aluno4,aluno5

real aluno6,aluno7,aluno8,aluno9,aluno10

real aluno11,aluno12,aluno13,aluno14,aluno15

real aluno16,aluno17,aluno18,aluno19,aluno20

real aluno21,aluno22,aluno23,aluno24,aluno25

real aluno26,aluno27,aluno28,aluno29,aluno30

real media

open(unit=2,file=(notas_de_fortran.txt(,status=(unknown()

C Lê as 30 notas contidas no arquivo:

read(2,*) aluno1,aluno2,aluno3,aluno4,aluno5,aluno6,aluno7,aluno8,

& aluno9,aluno10,aluno11,aluno12,aluno13,aluno14,aluno15,

& aluno16,aluno17,aluno18,aluno19,aluno20,aluno21,aluno22,

& aluno23,aluno24,aluno25,aluno26,aluno27,aluno28,aluno29,

& aluno30

close(2)

C Calcula a média e fornece o resultado:

media=(aluno1+aluno2+aluno3+aluno4+aluno5+aluno6+aluno7+

& aluno8+aluno9+aluno10+aluno11+aluno12+aluno13+aluno14+

& aluno15+aluno16+aluno17+aluno18+aluno19+aluno20+aluno21+

& aluno22+aluno23+aluno24+aluno25+aluno26+aluno27+aluno28+

& aluno29+aluno30)/30.

write(*,*) “A média da turma foi:”,media

stop

end

Visivelmente escrever este programa é cansativo! No exemplo acima declaramos 31 variáveis, 1 para cada nota de aluno, e 1 para a média. Ou seja, para armazenar na memória as notas, 30 endereços de memória foram reservados. Entretanto, se utilizarmos a noção de VETOR, podemos reservar os mesmos 30 endereços de memória de uma maneira muito mais simples. Primeiro, declaramos (normalmente) uma variável real chamada aluno:

program notas

implicit none

real aluno

Em seguida, atribuímos à variável aluno uma “dimensão” (que determinará o número de espaços de memória que queremos reservar), usando a seguinte sintaxe geral que inclui o comando dimension:

dimension nome_da_variavel(N)

onde N é o número de espaços de memória. Assim:

program notas

implicit none

real aluno

dimension aluno(30) ! “Aluno” agora é um vetor com 30 espaços de memória reservados.

Então, agora, a variável real aluno representa (no FORTRAN) um vetor com 30 componentes. Cada componente será a nota de um aluno, assim referenciado:

aluno(1) ( nota do aluno 1 (primeiro endereço de memória)

aluno(2) ( nota do aluno 2 (segundo endereço de memória)

aluno(3) ( nota do aluno 3 (terceiro endereço de memória)

.....

aluno(30) ( nota do aluno 30 (trigésimo endereço de memória)

Ou, em uma representação mais geral:

aluno(i) ( nota do aluno i, com i sendo um índice inteiro variando de 1 a 30.

Fica clara agora a diferença da noção de vetor em FORTRAN da noção de vetor em Física: a variável aluno no programa será um vetor, ainda que a nota de um aluno não seja uma grandeza vetorial.

Então, poderíamos re-escrever a parte do programa que lê as notas dos alunos assim:

open(unit=2,file=(notas_de_fortran.txt(,status=(unknown()

read(2,*) aluno(1),aluno(2),aluno(3),aluno(4),aluno(5),aluno(6),aluno(7),aluno(8),

& aluno(9),aluno(10),aluno(11),aluno(12),aluno(13),aluno(14),aluno(15),

& aluno(16),aluno(17),aluno(18),aluno(19),aluno(20),aluno(21),aluno(22),

& aluno(23),aluno(24),aluno(25),aluno(26),aluno(27),aluno(28),aluno(29),

& aluno(30)

close(2)

Mas isto não nos ajuda em nada, porque o programa continuou trabalhoso de se editar. Entretanto, como o índice do vetor varia de 1 a 30, podemos, ao invés de escrever explicitamente os 30 componentes, escrever um laço de repetição que faça um determinado contador (INTEIRO) variar de 1 a 30 usando o comando de repetição DO ENDDO. Primeiro devemos então declarar uma variável inteira que funcionará como índice de repetição (o “contador”).

integer ind ! Este será o índice de contagem

real aluno

dimension aluno(30)

E em seguida fazemos:

open(unit=2,file=(notas_de_fortran.txt(,status=(unknown()

do ind=1,30 ! A variável ind varia de 1 a 30

read(2,*) aluno(ind) ! A leitura de “aluno” será feita 30 vezes: aluno(1), aluno(2), etc...

enddo

close(2)

Então as 3 linhas:

do ind=1,30

read(2,*) aluno(ind)

enddo

substituem as 5 linhas:

read(2,*) aluno(1),aluno(2),aluno(3),aluno(4),aluno(5),aluno(6),aluno(7),aluno(8),

& aluno(9),aluno(10),aluno(11),aluno(12),aluno(13),aluno(14),aluno(15),

& aluno(16),aluno(17),aluno(18),aluno(19),aluno(20),aluno(21),aluno(22),

& aluno(23),aluno(24),aluno(25),aluno(26),aluno(27),aluno(28),aluno(29),

& aluno(30)

Assim, a edição do programa fonte tornou-se muito mais eficiente.

Observação importante: para que, no exemplo acima, a leitura das 30 notas seja feita de maneira correta o arquivo notas_de_fortran.txt deve conter as 30 notas em uma única coluna! Se as 30 notas estiverem em uma única linha então teríamos que usar o chamado laço implícito, assim:

open(unit=2,file=(notas_de_fortran.txt(,status=(unknown()

read(2,*) (aluno(ind),ind=1,30) ! Este também é um laço onde ind varia de 1 a 30, mas

! para o caso de termos de ler as 30 notas em uma

! mesma linha do arquivo de entrada.

close(2)

Na hora de calcularmos a média da turma, também podemos usar a noção de vetor a nosso favor. Note que, para calcularmos a média, precisamos fazer primeiro a soma das 30 notas. Esta soma pode ser feita no FORTRAN usando o vetor. No nosso exemplo vamos primeiro declarar uma variável que receberá a soma das 30 notas:

integer ind

real aluno,soma ! A variável real “soma” receberá o valor da soma

dimension aluno(30)

É conveniente também declarar a variável real que receberá o valor da nota média. Assim:

integer ind

real aluno,soma,media ! A variável real “media” receberá o valor da média dos 30 alunos

dimension aluno(30)

Note que das 3 variáveis reais, apenas a variável aluno é um vetor, pois não estamos indicando nenhuma dimensão para as variáveis soma ou media.

Na hora de calcular a média então fazemos:

soma=0.0 ! Valor inicial de “soma”

do ind=1,30

soma=soma+aluno(ind) ! Soma as 30 notas...

enddo

C Ao final do laço, a variável “soma” terá armazenado a soma das 30 notas.

media=soma/30. ! Calcula a média aritmética.

O trecho acima executa a seguinte sequência:

Para ind=1

soma=soma+aluno(1) , onde soma=0.0

Para ind=2

soma=soma+aluno(2) , onde soma=0.0 + aluno(1)

Para ind=3

soma=soma+aluno(3) , onde soma=0.0 + aluno(1) + aluno(2)

...

Para ind=30

soma=soma+aluno(30) ,onde soma=0.0 + aluno(1) + aluno(2) + aluno(3) + aluno(4) +

aluno(5) + aluno(6) + aluno(7) + aluno(8) + aluno(9) + aluno(10) + aluno(12) + aluno(13) + aluno(14) + aluno(15) + aluno(16) +aluno(17) + aluno(18) + aluno(19) + aluno(20) + aluno(21) + aluno(22) + aluno(23) + aluno(24) + aluno(25) +aluno(26) + aluno(27) + aluno(28) + aluno(29)

Logo, ao final do laço de repetição, a variável soma armazenará a soma das 30 notas. Logo em seguida o valor da variável soma é dividido por 30, fornecendo a média. O programa por extenso fica:

program notas

implicit none

integer ind

real aluno,soma,media

dimension aluno(30)

open(unit=2,file=(notas_de_fortran.txt(,status=(unknown()

do ind=1,30

read(2,*) aluno(ind)

enddo

close(2)

soma=0.0

do ind=1,30

soma=soma+aluno(ind)

enddo

media=soma/30.

write(*,*) ‘A media da turma foi:’,media

stop

end

Compare com a versão anterior e veja como o programa ficou mais “enxuto” (e mais inteligente). Edite, compile e execute o programa acima, mas para ler as notas de 10 alunos apenas (não esqueça de criar o arquivo de entrada!).

Atenção: no exemplo acima, a variável que faz o papel do índice inteiro que controla o número de vezes que o laço de repetição será executado não precisaria ser a mesma no laço de leitura e no laço da soma. Por exemplo, o programa abaixo funcionaria da mesma maneira:

program notas

implicit none

integer ind,j

real aluno,soma,media

dimension aluno(30)

open(unit=2,file=(notas_de_fortran.txt(,status=(unknown()

do ind=1,30 ! O contador do laço é controlado pela variável ind

read(2,*) aluno(ind)

enddo

close(2)

soma=0.0

do j=1,30 ! O contador do laço é controlado pela variável j

soma=soma+aluno(j)

enddo

media=soma/30.

write(*,*) “A média da turma foi:”,media

stop

end

Exercício 1: Utilizando o conceito de vetor, refaça o exercício 2 da aula 14 (aula passada): escreva, compile e execute um programa FORTRAN77 que leia os dados abaixo (de um arquivo) e crie um arquivo de saída contendo dados de consumo do veículo em km/litro.

km rodados litros de gasolina consumidos

371.7 56.1

399.0 37.3

486.0 48.0

141.5 10.5

426.4 50.4

90.0 7.8

Exercício 2: Na página seguinte segue um programa (pouco eficiente!) que resolve o problema do exercício 3 da aula 14 (aula passada) – regressão linear simples para os dados de temperatura e resistência coletados em um experimento.

DADOS (em um arquivo txt):

Temperatura (T) [(C] Resistência (R) [ohms]

20.0 761

31.5 817

50.0 874

71.8 917

91.3 1018

PROGRAMA:

program reg_linear

implicit

real coefa,coefb,mediat,mediar

real temp1,temp2,temp3,temp4,temp5

real res1,res2,res3,res4,res5

real somatr,somatt,temper,resist

C

open (unit=2,file="regressao_linear.txt",status="old")

C Entrada de dados

read(2,*) temp1,res1

read(2,*) temp2,res2

read(2,*) temp3,res3

read(2,*) temp4,res4

read(2,*) temp5,res5

close(2)

C CÁLCULOS...

C Somatório de T vezes R:

somatr=temp1*res1+temp2*res2+temp3*res3+temp4*res4+temp5*res5

C Somatório de T ao quadrado:

somatt=temp1**2+temp2**2+temp3**2+temp4**2+temp5**2

C Média de T:

mediat=(temp1+temp2+temp3+temp4+temp5)/5.

C Média de R:

mediar=(res1+res2+res3+res4+res5)/5.

C Coeficientes a e b:

coefa=(somatr(5.*mediat*mediar)/(somatt(5.*mediat**2)

coefb=mediar(coefa*mediat

C Saída de resultados

print*

print*,"RESULTADOS"

print*,"A reta de regressão é: R =",coefa," T +",coefb

print*

print*,"Prevendo um valor de R dada uma temperatura T:"

print*,"Forneça um valor de T (em Celsius), entre 20 e 90C."

read(*,*) temper

resist=coefa*temper+coefb

print*

print*,"O valor estimado de R para uma temperatura ",temper," Cels

&ius é:",resist," ohms."

stop

end

Refaça este programa utilizando o conceito de vetor.

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 16

16. MATRIZES:

Já vimos o conceito e as aplicações da noção de vetor em FORTRAN. Agora iremos 1 passo adiante e vamos lidar com as matrizes. Quando fornecemos o primeiro exemplo da aplicação do conceito de vetor, analisamos a situação em que tínhamos que ler as notas de 30 alunos e calcular a média da turma, assim:

program notas

implicit none

integer ind

real aluno,soma,media

dimension aluno(30)

open(unit=2,file=(notas_de_fortran.txt(,status=(unknown()

do ind=1,30

read(2,*) aluno(ind)

enddo

close(2)

soma=0.0

do ind=1,30

soma=soma+aluno(ind)

enddo

media=soma/30.

write(*,*) ‘A media da turma foi:’,media

stop

end

Os dados de entrada (isto é, as 30 notas) são então fornecidos em uma única coluna, como por exemplo:

3.5

9.8

7.5

8.2

.......

6.8

Os dados acima formam, na verdade, uma matriz contendo 30 linhas e 1 coluna (matriz 30 x 1).

Imagine agora que tenhamos 5 alunos e que cada um tenha 3 notas, e que queiramos calcular a média final da turma. Os dados de entrada poderiam então ser fornecidos assim:

3.5 6.2 5.9 (( 3 notas do aluno 1)

9.8 7.9 8.5 (( 3 notas do aluno 2)

7.5 5.3 7.0 (( 3 notas do aluno 3)

8.2 9.0 8.5 (( 3 notas do aluno 4)

6.8 7.9 8.3 (( 3 notas do aluno 5)

Agora temos uma matriz de 5 linhas e 3 colunas (matriz 5 x 3). Podemos então nos referir a cada uma das notas de uma maneira indicial (i, j), onde i refere-se à linha e j refere-se à coluna:

|i j |1 |2 |3 |

| | | | |

|1 |3.5 |6.2 |5.9 |

|2 |9.8 |7.9 |8.5 |

|3 |7.5 |5.3 |7.0 |

|4 |8.2 |9.0 |8.5 |

|5 |6.8 |7.9 |8.3 |

Por exemplo, a nota 1 do aluno 1 (que é 3.5) é a nota posicionada na linha 1 e coluna 1 da matriz, ou seja possui o índice (i=1,j=1). A nota 3 do aluno 5 (que é 8.3) é a nota posicionada em (i=5,j=3). Em FORTRAN podemos criar uma variável que funciona de forma semelhante ao vetor, mas que ao invés de necessitar de apenas 1 índice para determinar um endereço de memória (por exemplo, nota(4)), necessita de 2 índices para determinar este endereço (por exemplo, nota(3,4)). Esta será uma matriz! Como isto é feito? Veja abaixo:

program matrizes

implicit none

real nota

dimension nota(5,3)

Declaramos uma variável real chamada de nota. Em seguida, usando a expressão dimension, atribuímos à variável nota dois índices dimensionais: o primeiro é 5 e o segundo é 3. Isto significa que o compilador FORTRAN reservará para a variável nota um total de 15 (5 x 3) endereços de memória, e a variável nota poderá receber dados de uma matriz que tem (no máximo) 5 linhas e (no máximo) 3 colunas:

nota(1,1) nota(1,2) nota(1,3)

nota(2,1) nota(2,2) nota(2,3)

nota(3,1) nota(3,2) nota(3,3)

nota(4,1) nota(4,2) nota(4,3)

nota(5,1) nota(5,2) nota(5,3)

Ou, de uma maneira indicial:

nota(i,j), com i podendo variar de 1 a 5 e j podendo variar de 1 a 3.

Podemos agora elaborar um programa que leia a matriz de 3 notas para 5 alunos. Note que para cada linha de notas temos 3 colunas. Então a ordem em que os dados estão no arquivo é: nota(1,1), nota(1,2), nota(1,3) [isto é, i fixo em 1, com j variando de 1 a 3], nota(2,1), nota(2,2), nota(2,3) [isto é, i fixo em 2, com j variando de 1 a 3], nota(3,1), nota(3,2), nota(3,3) [isto é, i fixo em 3, com j variando de 1 a 3], nota(4,1), nota(4,2), nota(4,3) [isto é, i fixo em 4, com j variando de 1 a 3], nota(5,1), nota(5,2), nota(5,3) [isto é, i fixo em 5, com j variando de 1 a 3]. Logo, para cada i fixo temos j variando de 1 até 3, enquanto que no geral i varia de 1 até 5:

Primeira linha i=1 j=1

j=2

j=3

Segunda linha i=2 j=1

j=2

j=3

Terceira linha i=3 j=1

j=2

j=3

Quarta linha i=4 j=1

j=2

j=3

Quinta linha i=5 j=1

j=2

j=3

Então o algorítmo acima evolui na forma de laços aninhados, com o laço mais externo (controlado por i) variando de 1 a 5 e o laço mais interno (controlado por j) variando de 1 a 3. Então a leitura da matriz de dados pode ser feita como:

program matrizes

implicit none

integer i,j

real nota

dimension nota(5,3)

open(unit=2,file=(notas_de_fortran.txt(,status=(unknown()

do i=1,5 ! Laço externo, variando o índice para cada aluno

read(2,*) (nota(i,j), j=1,3) ! Laço aninhado, implícito, variando para cada nota

enddo

close(2)

Logo, para cada valor de i o programa lerá três notas: nota(1,1)=3.5, nota(1,2)=6.2, nota(1,3)=5.9, nota(2,1)=9.8, etc... até chegar em nota(5,3)=8.3

Em seguida podemos colocar o resultado na tela:

do i=1,5

do j=1,3

write(*,*) ‘A nota ’,j,’ do aluno ’,i,’ eh: ’,nota(i,j)

enddo

enddo

stop

end

No exemplo acima sabíamos de antemão quantas linhas e quantas colunas compõem a matriz de dados de entrada. E se não soubéssemos? Podemos criar um procedimento em que o arquivo de entrada informa quantas linhas e quantas colunas têm a matriz de dados, por exemplo:

5 3

3.5 6.2 5.9

9.8 7.9 8.5

7.5 5.3 7.0

8.2 9.0 8.5

6.8 7.9 8.3

A primeira linha, que contém dois valores inteiros (5 e 3), informa respectivamente o número de linhas e colunas da matriz. Assim, podemos fazer com que o programa, antes de ler a matriz, leia a informação de quantas linhas e quantas colunas ele deverá ler.

program matrizes2

implicit none

integer i,j,nlinhas,ncolunas

real nota

dimension nota(20,20)

open(unit=2,file=(notas_de_fortran2.txt(,status=(unknown()

read(2,*) nlinhas,ncolunas

if ((nlinhas .GT. 20) .OR. (ncolunas.GT.20)) then

print*,’A matriz de dados de entrada nao pode ser lida.’

else

do i=1,nlinhas

read(2,*) (nota(i,j), j=1,ncolunas)

enddo

do i=1,nlinhas

do j=1,ncolunas

write(*,*) ‘A nota ’,j,’ do aluno ’,i,’ eh: ’,nota(i,j)

enddo

enddo

endif

close(2)

stop

end

Pergunta: Por que adicionamos o IF () THEN ELSE?

Podemos com o programa acima calcular, por exemplo, a média de cada aluno (veja página a seguir):

program matrizes3

implicit none

integer i,j,nlinhas,ncolunas

real nota,media

dimension nota(20,20),media(20)

open(unit=2,file=(notas_de_fortran2.txt(,status=(unknown()

read(2,*) nlinhas,ncolunas

if ((nlinhas .GT. 20) .OR. (ncolunas.GT.20)) then

print*,’A matriz de dados de entrada nao pode ser lida.’

else

do i=1,nlinhas

read(2,*) (nota(i,j), j=1,ncolunas)

enddo

do i=1,nlinhas

media(i)=0.0

do j=1,ncolunas

media(i)=media(i)+nota(i,j)

enddo

media(i)=media(i)/3.0

enddo

do i=1,nlinhas

write(*,*) ‘A media do aluno ’,i,’ eh: ’,media(i)

enddo

endif

close(2)

stop

end

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 17

17. MAIS SOBRE VETORES E MATRIZES:

17.1. Uma forma conveniente de declarar as dimensões de um vetor ou matriz.

Nas aulas anteriores vimos duas maneiras alternativas de declarar vetores e matrizes no FORTRAN:

Maneira 1: usando o comando DIMENSION

program exemplo1

implicit none

real var1,var2

dimension var1(50),var2(40,40) ! var1 é um vetor de até 50 posições (elementos)

! var2 é uma matriz de até 40 x 40 elementos

Maneira 2: sem usar o comando DIMENSION

program exemplo2

implicit none

real var1(50),var2(40,40) ! var1 é um vetor de até 50 posições (elementos)

! var2 é uma matriz de até 40 x 40 elementos

As duas formas acima são inteiramente equivalentes.

Mas há uma forma considerada mais conveniente de indicar as dimensões de vetores ou matrizes, principalmente quando o número de variáveis que são vetores e/ou matrizes é grande. É a forma empregando o comando PARAMETER ( que aprendemos várias aulas atrás, para declarar valores constantes. Veja o exemplo abaixo (em que não usamos o comando DIMENSION):

program exemplo3

implicit none

real var1(50),var2(40),var3(50,40),var4(50,50),var5(30,40) ! 2 vetores e 3 matrizes

real var6(30,30),var7(50,30) ! 2 vetores

Vamos supor agora que você perceba que necessite aumentar 10 valores em todas as dimensões. Neste caso você terá que modificar as dimensões de todas as variáveis, uma a uma:

program exemplo3

implicit none

real var1(60),var2(50),var3(60,50),var4(60,60),var5(40,50) ! 2 vetores e 3 matrizes

real var6(40,40),var7(60,40) ! 2 vetores

Este procedimento é trabalhoso, principalmente em programas com muitos vetores e matrizes. Ao invés disto, podemos primeiro criar uma ou mais variáveis constantes que receberão os valores das dimensões dos vetores e matrizes. Assim:

program exemplo4

implicit none

integer D1,D2,D3 ! Variáveis inteiras que receberão as dimensões

parameter (D1=40, D2=50, D3=60) ! Declarando as dimensões na forma de constantes

real var1(D3),var2(D2),var3(D3,D2),var4(D3,D3),var5(D1,D2)

real var6(D1,D1),var7(D3,D1) ! As constantes D1, D2 e D3 indicam as dimensões

Observe agora que se precisarmos mudar as dimensões dos vetores e/ou matrizes (de uma maneira sistemática), basta fazer isto 1 única vez na linha do comando PARAMETER e não mais para cada vetor e/ou matriz. Os novos valores de D1, D2 e D3 serão imediatamente atribuídos às dimensões dos respectivos vetores e matrizes.

17.2. Observação: no momento da declaração das variáveis, não podemos fornecer a dimensão de um vetor (ou matriz) através de uma variável! Por exemplo, se tentarmos fazer:

program exemplo5

implicit none

integer nx ! Variável do tipo inteiro

real valor

dimension valor(nx) ! Tentativa de declarar a dimensão do vetor via uma variável

haverá erro já na compilação. Este tipo de declaração só funciona dentro de subrotinas (como veremos mais adiante).

17.3. Maneira alternativa de fornecer dados para um vetor ou matriz.

Vimos nos exemplos das aulas passadas as maneiras de atribuir valores a cada elemento de uma matriz ou vetor. Por exemplo, via teclado:

program exemplo6

implicit none

integer ordem

real valor

dimension valor(10)

print*,“Forneça 10 valores reais:”

do ordem=1,10 ! Laço de repetição EXPLÍCITO

read(*,*) valor(ordem)

enddo

.....

No exemplo acima, onde é utilizado um laço de repetição explícito para a leitura de dados, o usuário deverá fornecer (via teclado) 1 valor por linha (i.e., totalizando 10 linhas).

Ou:

program exemplo7

implicit none

integer ordem

real valor

dimension valor(10)

print*,“Forneça 10 valores reais:”

read(*,*) (valor(ordem),ordem=1,10) ! Laço de repetição IMPLÍCITO

.....

No exemplo acima, onde é utilizado um laço de repetição implícito para a leitura de dados, o usuário deverá fornecer (via teclado) os 10 valores em 1 linha.

Veja agora o exemplo alternativo abaixo:

program exemplo8

implicit none

integer ordem

real valor

dimension valor(10)

print*,“Forneça 10 valores reais:”

read(*,*) valor ! Desta vez não há um laço de repetição, e nem índice de contagem

Neste caso o usuário poderá fornecer os 10 dados, via teclado, da maneira que mais lhe convier: seja na forma de 10 valores numa linha, seja na forma de 10 linhas com 1 valor por linha, ou segundo uma combinação de valores em uma mesma linha e em linhas diferentes; por exemplo, 4 valores em 1 linha, depois 2 valores na linha seguinte, depois 3 valores na linha seguinte e depois 1 valor na próxima linha. Por exemplo:

12. 456. 13. -0.01 400.0 234.0 -35.679 10. 6789.34 0.1 ( 10 valores em 1 linha

ou:

12. 456. 13.

-0.01

400.0 234.0

-35.679 10. 6789.34 0.1

ou:

12. 456. 13.

-0.01 400.0 234.0 -35.679 10. 6789.34 0.1

etc...

É importante ressaltar que enquanto o usuário não fornecer exatamente 10 valores o programa não prosseguirá. Se o usuário fornecer mais que 10 valores, apenas os 10 primeiros serão atribuídos aos elementos do vetor.

( Vantagem desta forma de ler os dados: não há necessidade de se preocupar com a forma de se fornecer os valores de entrada (se na forma de linhas ou de colunas).

( Desvantagem desta forma de ler os dados: a dimensão declarada para o vetor (ou matriz) tem que ser inteiramente preenchida com dados. No exemplo acima, declaramos o vetor valor com 10 elementos, e ao se ler os dados de entrada para este vetor fomos obrigados a fornecer exatamente 10 valores; não tivemos opção de fornecer menos que 10 valores, como era o caso nas formas anteriores.

O que vale para vetores, também vale para matrizes. Por exemplo, podemos ler uma matriz 4 x 3 da seguinte forma:

program exemplo9

implicit none

real mat

dimension mat(4,3) ! Declarando a variável real mat como matriz

print*,“Forneça os 12 valores da matriz 4 x 3:”

read(*,*) mat ! Leitura sem laço de repetição, e nem índice de contagem

.....

O programa só prosseguirá após o comando read depois que o usuário fornecer os 12 valores que compõem a matriz 4 x 3. Mas, ao contrário do caso do vetor, agora deve haver grande atenção; o usuário deverá fornecer, via teclado, os 12 elementos levando-se em conta que o FORTRAN lerá esta matriz não na forma de linha por linha, mas sim na forma de coluna por coluna. Então suponha que o usuário forneça, via teclado, os 12 valores dispostos assim:

77.0 56.1 32.9 25.8 99.9 10.0 100.3 46.5 48.7 89.9 77.2 33.0

O FORTRAN atribuirá à variável mat a seguinte matriz:

mat(1,1)=77.0 mat(1,2)=99.9 mat(1,3)=48.7

mat(2,1)=56.1 mat(2,2)=10.0 mat(2,3)=89.9

mat(3,1)=32.9 mat(3,2)=100.3 mat(3,3)=77.2

mat(4,1)=25.8 mat(4,2)=46.5 mat(4,3)=33.0

Ou seja:

77.0 99.9 48.7

56.1 10.0 89.9

32.9 100.3 77.2

25.8 46.5 33.0

Agora suponha que o usuário forneça, via teclado, os mesmos 12 valores mas da seguinte forma:

77.0 56.1 32.9

25.8 99.9 10.0

100.3 46.5 48.7

89.9 77.2 33.0

De novo, como na ausência de um controle de leitura (via laço de repetição) o FORTRAN automaticamente opta por ler os valores da matriz na forma de coluna por coluna, a variável mat receberá, também neste caso, a seguinte matriz:

77.0 99.9 48.7

56.1 10.0 89.9

32.9 100.3 77.2

25.8 46.5 33.0

O que provavelmente é diferente daquilo que o usuário pretendia. Não importa a disposição dos dados no momento de fornecê-los, a primeira série de 4 valores formará a primeira coluna, a segunda série de 4 valores formará a segunda coluna, e assim por diante:

Forma como os dados são lidos Forma como os dados são atribuídos à mat(4,3)

77.0 56.1 32.9 77.0 99.9 48.7

25.8 99.9 10.0 56.1 10.0 89.9

100.3 46.5 48.7 32.9 100.3 77.2

89.9 77.2 33.0 25.8 46.5 33.0

Para evitar este tipo de dificuldade é melhor optar-se por controlar a leitura dos dados via laço de repetição, assim:

program exemplo10

implicit none

real mat

dimension mat(4,3)

print*,“Forneça os 12 valores da matriz na forma 4 x 3:”

do i=1,4 ! Laço de repetição EXPLÍCITO, para as linhas

read(*,*) (mat(i,j),j=1,3) ! Laço de repetição IMPLÍCITO, para as colunas

enddo

…..

Neste caso sim haverá a correspondência desejada:

Forma como os dados são lidos Forma como os dados são atribuídos à mat(4,3)

77.0 56.1 32.9 77.0 56.1 32.9

25.8 99.9 10.0 25.8 99.9 10.0

100.3 46.5 48.7 100.3 46.5 48.7

89.9 77.2 33.0 89.9 77.2 33.0

17.4. Matrizes multidimensionais.

Suponha que um professor dê aula para 3 turmas diferentes com cada turma tendo o mesmo número de alunos, e que para cada turma o professor dê 3 provas. Neste caso temos a situação (supondo 5 alunos por turma):

Turma 1 Turma 2 Turma 3

Aluno1: nota1 nota2 nota3 Aluno1: nota1 nota2 nota3 Aluno1: nota1 nota2 nota3

Aluno2: nota1 nota2 nota3 Aluno2: nota1 nota2 nota3 Aluno2: nota1 nota2 nota3

Aluno3: nota1 nota2 nota3 Aluno3: nota1 nota2 nota3 Aluno3: nota1 nota2 nota3

Aluno4: nota1 nota2 nota3 Aluno4: nota1 nota2 nota3 Aluno4: nota1 nota2 nota3

Aluno5: nota1 nota2 nota3 Aluno5: nota1 nota2 nota3 Aluno5: nota1 nota2 nota3

Por conveniência:

Vamos atribuir um índice i para cada turma: i=1 (turma 1), i=2 (turma 2), i=3 (turma 3)

Vamos atribuir um índice j para cada aluno: j=1 (aluno 1),j=2 (aluno 2), j=3 (aluno 3), j=4 (aluno 4), j=5 (aluno 5)

Vamos atribuir um índice k para cada nota: k=1 (nota 1), k=2 (nota 2), k=3 (nota 3)

Temos um total de 3 x 5 x 3 (45) notas. É possível armazenar estas 45 notas em uma única variável na forma de uma matriz “tridimensional”; isto é, além de linhas e colunas, ela possui um terceiro “eixo”, perpendicular às linhas e colunas, formando uma espécie de “caixa”:

Neste caso se quisermos armazenar na memória do computador a segunda nota (k=2) do terceiro aluno (j=3) da primeira turma (i=1) podemos atribuir esta nota à variável valor assim definida:

valor(1,3,2)

Generalizando, o primeiro índice de valor varia de 1 até 3 (número de turmas); o segundo índice varia de 1 até 5 (número de alunos por turma); o terceiro índice varia de 1 até 3 (número de notas por aluno). Neste caso a variável valor tem associada a ela 45 endereços de memória, cada uma podendo armazenar 1 nota específica.

No FORTRAN esta variável é declarada da mesma forma como qualquer outra matriz:

program exemplo11

implicit none

integer i,j,k

real valor

dimension valor(3,5,3) ! Declarando uma matriz multidimensional: 3 x 5 x 3

Como atribuiríamos os valores dos elementos desta matriz? O mais conveniente seria atribuir, para cada turma (isto é mantendo fixo o índice contador correspondente à turma), as notas de cada aluno (isto é, mantendo fixo o índice correspondente ao aluno e fornecendo a nota):

Turma 1: (i=1)

Aluno 1: (j=1)

Nota 1: (k=1) valor(1,1,1)

Nota 2: (k=2) valor(1,1,2)

Nota 3: (k=3) valor(1,1,3)

Aluno 2: (j=2)

Nota 1: (k=1) valor(1,2,1)

Nota 2: (k=2) valor(1,2,2)

Nota 3: (k=3) valor(1,2,3)

Aluno 3: (j=3)

Nota 1: (k=1) valor(1,3,1)

Nota 2: (k=2) valor(1,3,2)

Nota 3: (k=3) valor(1,3,3)

Aluno 4: (j=4)

Nota 1: (k=1) valor(1,4,1)

Nota 2: (k=2) valor(1,4,2)

Nota 3: (k=3) valor(1,4,3)

Aluno 5: (j=5)

Nota 1: (k=1) valor(1,5,1)

Nota 2: (k=2) valor(1,5,2)

Nota 3: (k=3) valor(1,5,3)

Turma 2: (i=2)

repete-se o algoritmo, com j variando de 1 a 5, e com k variando de 1 a 3 para cada j fixo.

Turma 3: (i=3)

repete-se o algoritmo, com j variando de 1 a 5, e com k variando de 1 a 3 para cada j fixo.

Temos claramente três laços de repetição (para i, para j e para k), sendo dois aninhados (o laço de j aninhado no laço de i, e o laço de k aninhado no laço de j). O seguinte trecho de programa realizaria tal leitura (onde o usuário deve fornecer três notas por linha: para cada turma, 1 linha por aluno):

do i=1,3 ! Laço explícito externo (laço das turmas)

do j=1,5 ! Laço explícito aninhado (laço dos alunos)

read(*,*) (valor(i,j,k),k=1,3) ! Laço implícito aninhado (laço das notas)

enddo

enddo

Obs: Nada impede que uma matriz tenha n-dimensões. Por exemplo, o professor pode todo ano dar aula para três turmas de cinco alunos, dando três notas por aluno. Neste caso, se ele quiser armazenar na memória a terceira nota, do quinto aluno, da primeira turma, do segundo ano em que deu aula ele poderá fazê-lo na variável: valor(2,1,5,3)

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 18

17.5. índices ZERO e NEGATIVOS para vetores e matrizes.

Nos exemplos vistos até agora os índices/dimensões dos vetores e matrizes sempre foram inteiros maiores que 1. Por exemplo:

real valor, kapa

dimension var(15), kapa(20,30) ! Um vetor de 15 elementos e uma matriz 20 x 30

Mas o que dizer então do “endereço” var(-2)? Ou var(0)?

Na verdade é permitido haver índices zero e negativos em vetores e matrizes, mas para isto ser aceito sem “acidentes” de execução, a declaração do vetor/matriz deve seguir uma sintaxe diferente, onde se estabelece a AMPLITUDE dos valores que podem ser assumidos pelos índices. Isto é feito da seguinte maneira:

real valor, kapa

dimension var(−7:7), kapa(-16:3,0:29) ! De novo, um vetor de 15 elementos e uma matriz 20 x 30

Neste exemplo acima o vetor var poderá receber até 15 valores, distribuídos pelos 15 endereços de memória assim definidos: valor(-7) , valor(-6) , valor(-5) , .... , valor(0) , valor(1) , ...., valor(6) , valor(7).

O mesmo vale para a matriz kapa:

kapa(-16,0) kapa(-16,1) kapa(-16,2) .... kapa(-16,28) kapa(-16,29)

kapa(-15,0) kapa(-15,1) kapa(-15,2) .... kapa(-15,28) kapa(-15,29)

....

kapa(0,0) kapa(0,1) kapa(0,2) .... kapa(0,28) kapa(0,29)

....

kapa(3,0) kapa(3,1) kapa(3,2) .... kapa(3,28) kapa(3,29)

Observe que a matriz kapa continua sendo uma matriz de dimensão máxima 20 x 30, exatamente como na sintaxe anterior. A diferença está apenas nos valores que podemos atribuir aos seus índices. Pela sintaxe anterior podíamos apenas atribuir valores maiores que zero a estes índices (avisos de erro surgiriam na execução do programa se tentássemos forçar o uso de 0 ou números negativos naquele caso). Atente para o seguinte: na grande maioria das vezes o programador FORTRAN utilizará aquela sintaxe original que vimos nas aulas anteriores.

17.6. Índices que resultam de uma expressão aritmética:

Os índices de um vetor ou de uma matriz também podem ser referenciados por expressões aritméticas simples. Para ilustrar isto considere, por exemplo, a série de 6 valores abaixo:

45.0 29.0 −15.8 34.7 −200.0 8.0

Suponha que estes 6 valores sejam fornecidos a um programa FORTRAN e atribuídos a um vetor do tipo real com 6 elementos.

real valor

dimension valor(6)

Então, após a atribuição (leitura) de valores teríamos:

valor(1)=45.0; valor(2)=29.0; valor(3)=−15.8; valor(4)=34.7; valor(5)= −200.0; valor(6)=8.0

Vamos supor agora que queiramos construir uma nova série de dados onde cada elemento consista da multiplicação de dois valores consecutivos da série original acima. Assim:

Nova série de dados: primeiro elemento = valor(1) × valor(2) = 45.0 × 29.0

segundo elemento = valor(2) × valor(3) = 29.0 × −15.8

terceiro elemento = valor(3) × valor(4) = −15.8 × 34.7

quarto elemento = valor(4) × valor(5) = 34.7 × −200.0

quinto elemento = valor(5) × valor(6) = −200.0 × 8.0

(Evidentemente, a nova série contém 1 elemento a menos que a série original).

Também podemos escrever o algoritmo acima em termos dos índices que associam-se aos elementos do vetor:

i=1, j=2: ( primeiro elemento = valor(i) × valor(j) = 45.0 × 29.0

i=2, j=3: ( segundo elemento = valor(i) × valor(j) = 29.0 × −15.8

i=3, j=4: ( terceiro elemento = valor(i) × valor(j) = −15.8 × 34.7

....

i=5, j=6: ( quinto elemento = valor(i) × valor(j) = −200.0 × 8.0

Fica claro na seqüência acima que j=i+1 sempre (ou, equivalentemente, i=j−1). Assim, uma maneira alternativa de escrever este mesmo algoritmo seria:

i=1 ( primeiro elemento = valor(i) × valor(i+1) = 45.0 × 29.0

i=2 ( segundo elemento = valor(i) × valor(i+1) = 29.0 × −15.8

i=3 ( terceiro elemento = valor(i) × valor(i+1) = −15.8 × 34.7

....

i=5 ( quinto elemento = valor(i) × valor(i+1) = −200.0 × 8.0

ou ainda:

j=2 ( primeiro elemento = valor(j−1) × valor(j) = 45.0 × 29.0

j=3 ( segundo elemento = valor(j−1) × valor(j) = 29.0 × −15.8

j=4 ( terceiro elemento = valor(j−1) × valor(j) = −15.8 × 34.7

....

j=6 ( quinto elemento = valor(j−1) × valor(j) = −200.0 × 8.0

Em linguagem FORTRAN isto poderia ser escrito como (supondo que os elementos da nova série sejam atribuídos a um vetor real de 5 elementos declarado com o nome multi):

do i=1,5

multi(i)=valor(i)*valor(i+1)

enddo

ou, equivalentemente:

do i=2,6

multi(i−1)=valor(i−1)*valor(i)

enddo

O exemplo acima mostra então que os índices de um vetor (e o mesmo vale para as matrizes) podem ser referenciados pelo resultado de uma expressão aritmética.

ALGUNS Exercícios Práticos:

(1) Utilizando a noção de vetor, escreva, compile e execute um programa que leia um arquivo contendo a tabela abaixo com algumas temperaturas medidas de hora em hora na estação meteorológica de Santa Maria. O programa deverá identificar e escrever na tela as temperaturas máxima e mínima medidas e seus respectivos horários. Além disto, o programa deverá informar também a temperatura média.

Hora Temperatura ((C)

0800 9.8

0900 11.2

1000 13.5

1100 15.1

1200 16.8

1300 18.3

1400 20.1

1500 20.9

1600 19.0

1700 17.3

1800 15.9

1900 13.2

2000 11.7

(2) Suponha agora que, partindo da tabela acima, você queira estimar a temperatura aos 30min de cada hora; isto é, às 8h30, 9h30, 10h30, etc.... Para isto você decide então fazer a média aritmética das medições consecutivas de temperatura ( isto é, temp. 8h30 = (temp. 8h00 + temp. 9h00)/2 e assim por diante. Utilizando o conceito de vetor (e o que foi aprendido no item 17.6), elabore e execute um programa que realize estas contas e forneça na tela as estimativas de temperaturas das 8h30 até as 19h30, em intervalos de 1 hora.

Matrizes:

(3) Elabore e execute um programa que leia uma matriz quadrada qualquer (isto é, uma matriz M x N onde M = N) e escreva na tela apenas os elementos que compõem a diagonal principal desta matriz.

AULA 18: Programas que resolvem os exercícios 1, 2 e 3:

(1)

program temperaturas

implicit none

integer i

character*4 hora,hora_min,hora_max

real temp,maxtemp,mintemp,media

dimension temp(15),hora(15)

C Arquivo de entrada

open (unit=3,file="temperaturas.txt",status="old")

media=0.0

C Lê a hora e a temperatura, e soma as temperaturas

do i=1,13

read(3,*) hora(i),temp(i)

media=media+temp(i)

enddo

C Calcula a temperatura média

media=media/13.

C "Chutes" iniciais para as temperaturas máxima e mínima

maxtemp=temp(1)

hora_max=hora(1)

mintemp=temp(1)

hora_min=hora(1)

C Identifica as temperaturas máxima e mínima e seus horários respectivos

do i=2,13

if (temp(i) .GT. maxtemp) then

maxtemp=temp(i)

hora_max=hora(i)

endif

if (temp(i) .LT. mintemp) then

mintemp=temp(i)

hora_min=hora(i)

endif

enddo

C Escreve os resultados

print*

print*,"RESULTADOS"

write(*,100) "A temperatura máxima foi de ",maxtemp,"C, registrada

&às ",hora_max," horas."

write(*,100) "A temperatura mínima foi de ",mintemp,"C, registrada

&às ",hora_min," horas."

write(*,101) "A temperatura m‚dia foi de ",media,"C."

print*

100 format(A,F6.1,2A)

101 format(A,F6.1,A)

stop

end

(2)

program temperaturas2

implicit none

integer i

character*4 hora

real temp,temp30

dimension temp(15),hora(15),temp30(15)

C Arquivo de entrada

open (unit=3,file="temperaturas.txt",status="old")

C Lê a hora e a temperatura

do i=1,13

read(3,*) hora(i),temp(i)

enddo

C Calcula as temperaturas nos 30min intermediários

do i=1,12

temp30(i)=(temp(i)+temp(i+1))/2.

enddo

C Escreve os resultados

print*

print*,"RESULTADOS"

do i=1,12

write(*,100) hora(i),temp(i)

write(*,101) temp30(i)

enddo

write(*,100) hora(13),temp(13)

print*

100 format(A,F6.1)

101 format(4X,F6.1)

stop

end

(3)

program diagonal

implicit none

integer i,j,nl,nc

real mat

dimension mat(30,30)

C Entrada de dados

print*,"ENTRADA DE DADOS:"

print*,"Forneça as dimensões (NxN) da matriz quadrada (até 30x30)"

read(*,*) nl,nc

if ((nl .GT. 30) .OR. (nc .GT. 30) .OR. (nl .NE. nc)) then

print*,"O usuário forneceu dimensões não permitidas."

print*,"Pressione qualquer tecla para sair."

print*

else

print*

print*,"Forneça a matriz, linha por linha:"

do i=1,nl

read(*,*) (mat(i,j),j=1,nc)

enddo

print*

print*,"Os elementos que compõem a diagonal da matriz são:"

do i=1,nl

write(*,*) mat(i,i)

enddo

endif

stop

end

Univsesidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 19

18.0. FUNÇÕES:

Na Aula 5 nós aprendemos que o FORTRAN possui “embutido” um conjunto de funções intrínsecas pré-definidas que executam determinados cálculos ou tarefas. Por exemplo, uma destas funções é aquela que calcula o seno de um determinado ângulo ang fornecido em radianos:

sin(ang) ( fornece o valor do seno de ang

Cada uma destas funções pode ser usada em uma expressão bastando-se fornecer seu nome com o(s) respectivo(s) argumento(s) em parênteses. No exemplo acima, o nome da função é sin e o argumento fornecido foi ang, onde ang é uma variável real qualquer que recebeu anteriormente o valor do ângulo em radianos; por exemplo:

ang=4.712

senoide=sin(ang)

Outra opção é simplesmente fornecer explicitamente o valor do argumento para a função:

senoide=sin(4.712)

É importante saber que, além das funções intrínsecas do FORTRAN, o programador pode definir funções adicionais que não constam na biblioteca de funções pré-definidas do FORTRAN. Uma vez esta nova função tendo sido definida pelo programador, ela poderá ser empregada quantas vezes forem necessárias. (De fato, o programador pode, se desejar, criar sua própria biblioteca de funções a serem empregadas em seus programas).

Estas funções funcionam como “subprogramas” porque são escritas separadamente do programa principal que executa estas funções. A sintaxe geral das funções é:

tipo function nome_da_função(lista de argumentos)

, onde:

( tipo é um identificador (opcional) do tipo do valor a ser fornecido pela função (integer, real, character, logical, etc...). Se o tipo não for informado no cabeçalho da função, ele deverá ser fornecido dentro da função, logo no início.

( nome_da_função é simplesmente o nome dado pelo programador a esta função (pode ser qualquer nome contanto que satisfaça os critérios de nomes estabelecidos no FORTRAN, como visto na Aula 2);

( lista de argumentos é a sequência de argumentos (ou, se for o caso, 1 único argumento) que são fornecidos para a função.

( A idéia geral do funcionamento de uma função é:

O programa principal fornece um(a) valor/informação para a função ( a função recebe este(a) valor/informação e realiza um cálculo ou tarefa ( a função retorna para o programa principal o resultado deste cálculo ou tarefa.

18.1. Funções de 1 argumento:

Vamos ver um exemplo: suponha que nós queiramos usar a seguinte expressão:

[pic]

que determina a voltagem v através de um certo capacitor onde t é o tempo (um número real).Uma função pode ser implementada que realize este cálculo. Vamos chamá-la de volt:

real function volt(t)

A função volt tem o aspecto de um programa FORTRAN. Sua forma geral será:

real function volt(t)

real t ! Declara-se a variável que foi recebida como argumento

volt=(t+0.1)*exp(sqrt(t)) ! Realiza-se o cálculo e atribui-se o resultado à variável volt

return ! Retorna o valor de volt para o programa principal

end ! Fim da função

Observe que o nome da variável que receberá o resultado final do cálculo realizado dentro da função tem que ter o mesmo nome da função (no exemplo acima, volt); o comando RETURN retornará ao programa principal o valor atribuído à variável volt dentro da função volt. Em outras palavras, o valor a ser retornado para o programa principal no momento do comando RETURN é aquele que estiver armazenado na variável que tenha exatamente o mesmo nome da função.

Repare que não precisamos declarar a variável volt dentro da função porque no cabeçalho da função já foi declarado o seu tipo. Entretanto a(s) variável(eis) que for(em) fornecida(s) como argumento(s) para a função tem(têm) que ser declarada(s) dentro da função.

Se não declararmos no cabeçalho da função o tipo do valor retornado ao programa principal, então precisaremos declarar a variável volt dentro da função:

function volt(t) ! Não foi especificado o tipo do valor a ser retornado.

real volt, t ! Declara-se não só o argumento, mas também a variável que retorna o resultado final.

volt=(t+0.1)*exp(sqrt(t))

return

end

Aonde devemos localizar o código fonte da função em relação ao código fonte do programa principal? Após o comando END do programa principal:

! Abertura do programa principal

program ...

.....

..... ....

.....

stop

end

! Final do programa principal; agora escreve a função:

function ....

.....

return

end

! Final da função.

E como o programa principal deve chamar (ou “acionar”) a função? Da mesma forma como fazemos com uma função intrínseca. Mas devemos ter alguns cuidados. Para ilustrar, veja no exemplo abaixo um programa FORTRAN completo (programa principal + função) que emprega a função volt criada pelo programador:

program capacitor ! Programa principal

implicit none

integer tempo,ini,fim,increm

real tempor,voltagem,volt

print*,“Forneça os tempos inicial e final (valores inteiros):”

read(*,*) ini,fim

print*,“Forneça o passo no tempo (valor inteiro):”

read(*,*) increm

do tempo=ini,fim,increm ! Laço de repetição no tempo.

tempor=float(tempo) ! Convertendo o índice do tempo para um valor real.

voltagem=volt(tempor) ! Acionando a função volt aplicada ao argumento tempor.

! O resultado será atribuído à variável real voltagem.

print*,“No tempo ”,tempo,“ a voltagem é: ”,voltagem

enddo

stop

end ! Final do programa principal

C

function volt(T) ! Cabeçalho da função volt, sem declarar o tipo do valor retornado.

real T,volt ! Declarando o argumento de entrada e a variável que receberá o resultado

! final a ser retornado pela função para o programa principal.

volt=(T + 0.1)*exp(sqrt(T))

return ! Retorna o valor de volt para o programa principal.

end ! Final da função volt

Detalhes importantes a serem observados:

( Da mesma forma como no exemplo anterior a variável senoide recebeu o valor retornado pela função sin aplicada ao argumento ang, a variável voltagem no programa acima recebe o valor fornecido pela função volt aplicada ao argumento tempor. Logo, a variável voltagem tem que ter o mesmo tipo declarado para o valor retornado pela função volt (neste caso, tipo real);

( Tivemos que declarar dentro do programa principal uma variável chamada volt e do tipo real; generalizando, o nome da função deve ser declarada como uma variável no programa principal, de tipo igual ao tipo do valor retornado pelo função.

( O nome da variável que é fornecida pelo programa principal como argumento para a função não precisa ser necessariamente igual ao nome da variável que recebe o valor do argumento na função. No exemplo acima o programa principal fornece a variável tempor com argumento para a função volt, enquanto que na função volt a variável que recebe este valor é a variável T (ou seja, nomes diferentes). A única restrição que se faz é que estas duas variáveis sejam do mesmo tipo. Como T foi declarada como real dentro da função volt, ao fornecermos o valor do argumento para volt precisamos, antes, converter o valor inteiro de tempo para um valor real (sendo atribuído a tempor) usando o comando FLOAT. Se fizéssemos: voltagem=volt(tempo)

, acarretaria possivelmente em um erro pois tempo é do tipo inteiro enquanto que T é do tipo real, causando um conflito;

( Ainda neste contexto é preciso reparar que a variável T não pertence ao programa principal, mas à função volt e por isto T não é declarada no programa principal, apenas na função;

( Uma função pode empregar outra(s) função(ões), seja(m) ela(s) intrínseca(s) ou não. A função volt acima utiliza as funções intrínsecas exp( ) e sqrt( ).

( Da mesma forma como exemplificado para a função intrínseca sin, podemos fornecer explicitamente o valor do argumento para a função criada pelo programador. Por exemplo:

voltagem=volt(0.0) ! Mas não poderíamos fornecer volt(0), pois 0 estaria no formato inteiro

( Uma maneira alternativa de executar a mesma tarefa no programa capacitor seria:

....

do tempo=ini,fim,increm

voltagem=volt(tempo) ! Acionando a função volt aplicada ao argumento tempo

print*,“No tempo ”,tempo,“ a voltagem é: ”,voltagem

enddo

....

function volt(T)

integer T ! Agora T tem que ser do tipo inteiro, pois o argumento fornecido foi inteiro

real volt

volt=(float(T) + 0.1)*exp(sqrt(float(T)))

….

18.2. Funções de mais de 1 argumento:

A função volt foi um exemplo de função com um único argumento de entrada. Mas uma função pode ter mais de 1 (um) argumento, e além disto os argumentos não precisam necessariamente ser do mesmo tipo. Vejamos um exemplo de função com múltiplos argumentos. Suponha que desejemos empregar a seguinte função matemática:

xn + yn , se x ≥ y

f(x,y,n) =

0 , caso contrário.

onde x e y são reais e n inteiro. Uma função no FORTRAN que executaria este cálculo seria:

function fff(x,y,n)

real fff,x,y ! fff, x e y do tipo real

integer n ! n do tipo inteiro

if (x .GE. y) then

fff=x**n + y**n

else

fff=0.0

endif

return ! Retorna ao programa principal o valor de fff

end

(Observe que uma função pode empregar normalmente as estruturas condicionais (IF THEN ELSE). Também pode empregar laços de repetição, acesso a arquivos, vetores, matrizes, etc...)

O programa principal poderia acionar esta função como:

....

var1=−0.1 ! Valor real para x

var2=4.5 ! Valor real para y

expoente=2 ! Valor inteiro, para n

result=fff(var1,var2,expoente) ! result é uma variável do tipo real, e recebe o valor

! calculado pela função fff.

Observe que deve haver uma correspondência perfeita entre as variáveis do programa principal e as variáveis da função no que diz respeito aos seus tipos. O valor de var1 do programa principal será atribuído à variável x da função fff, logo ambas são do tipo real. O valor de var2 do programa principal será atribuído à variável y da função fff, logo ambas também são do tipo real. O valor da variável expoente do programa principal será atribuído à variável n da função fff, logo ambas são do tipo inteiro.

18.3. Funções de tipo caractere:

As funções podem também retornar informações do tipo caractere. Veja o caso da função poluicao abaixo. Suponha que o programa principal forneça um argumento do tipo inteiro à função poluicao (que represente um índice numérico de poluição):

function poluicao(indice)

integer indice,limiar

character*8 poluicao ! O valor a ser retornado é do tipo caractere.

parameter (limiar=50) ! Definindo uma constante para o limiar de poluição.

if (indice .LT. limiar) then

poluicao=“SEGURO”

else

poluicao=“PERIGOSO”

endif

return ! Retorna ao programa principal a palavra atribuída à variável poluicao

end

Evidentemente, no programa principal a variável a receber o resultado da função poluicao também deverá ser do tipo caractere (pelo menos character*8).

(Observe também que podemos utilizar normalmente o comando PARAMETER dentro da função).

Universidade Federal de Santa Maria

Departamento de Física

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 20

IMPORTANTE: atenção para uma correção na aula passada:

Ao criarmos uma função precisamos declarar no programa principal uma variável que tenha o mesmo nome da função e cujo tipo seja igual ao tipo do valor retornado pela função. Assim, no programa capacitor que escrevemos aula passada deve constar:

program capacitor ! Programa principal

implicit none ! Faltava o “implicit none” no exemplo da aula passada...

integer tempo,ini,fim,increm

real tempor,voltagem,volt ! A variável volt tem o nome da função volt, e tem o mesmo

! tipo do valor retornado pela função volt: tipo real.

....< restante do programa principal >....

end

!

function volt(T)

real T,volt ! A função volt retorna um valor real ao programa principal

....< restante da função >....

return

end

18.3. Funções de tipo caractere (continuação):

Aula passada vimos o exemplo de uma função que retorna ao programa principal um valor (informação) do tipo caractere:

function poluicao(indice)

integer indice,limiar

character*8 poluicao

parameter (limiar=50)

if (indice .LT. limiar) then

poluicao=“SEGURO”

else

poluicao=“PERIGOSO”

endif

return

end

No exemplo acima, ao declararmos o tipo da função (através da declaração da variável poluicao) nós indicamos que o número máximo de caracteres que pode constar na variável que retorna a informação para o programa principal é oito. Outra forma de declarar isto seria:

character*8 function poluicao(indice)

(E neste caso não seria necessário declarar uma variável poluicao dentro da função).

Existe ainda uma outra maneira de se informar o comprimento (máximo) da variável caractere retornada pela função:

character*(*) function poluicao(indice)

ou, equivalentemente:

function poluicao(indice)

integer indice,limiar

character*(*) poluicao

Neste caso o comprimento máximo da variável caractere poluicao será exatamente igual ao comprimento máximo da variável caractere poluicao declarada no programa principal. Veja o exemplo:

program polui

implicit none

integer index

character*30 poluicao,var

print*

print*,“Forneça o índice de poluição medido (número inteiro).”

read(*,*) index

frase=poluicao(index)

print*

print*,var

stop

end

C

character*(*) function poluicao(indice)

integer indice,limiar

parameter (limiar=50)

if (indice .LE. limiar) then

poluicao=“As condições são seguras.”

else

poluicao=“As condições são perigosas”

endif

return

end

ou ainda

function poluicao(i)

integer i,limiar

character*(*) poluicao

parameter (limiar=50)

....< restante da função >....

18.4. Compartilhamento de variáveis entre o programa principal e as funções:

Uma função funciona como um pequeno programa FORTRAN e, portanto, pode ter suas próprias variáveis de uso interno, as quais pertencem apenas à função e não precisam ser declaradas no programa principal. Um exemplo disto é a variável (constante) limiar declarada no exemplo da função poluicao:

function poluicao(indice)

integer indice,limiar

character*8 poluicao

parameter (limiar=50)

Importante: uma variável de uso interno da função que por acaso tenha o mesmo nome de uma variável existente no programa principal será totalmente independente da variável do programa principal. Por exemplo:

program polui

implicit none

integer index

character*30 poluicao,var

print*,“Forneça o índice de poluição medido (número inteiro).”

read(*,*) index

frase=poluicao(index)

print*,var

stop

end

C

character*(*) function poluicao(indice)

integer indice,var

parameter (var=50)

if (indice .LE. var) then

poluicao=“As condições são seguras.”

else

poluicao=“As condições são perigosas”

endif

return

end

A variável var do programa principal é do tipo caractere. A variável var da função poluicao é do tipo inteiro. Não haverá conflito nenhum pois a variável var na função é de uso interno, sem haver sua comunicação com o programa principal; é como se o programa principal “nem soubesse” da existência de uma variável var dentro da função. Logo as duas variáveis são completamente distintas, apesar de terem o mesmo nome (entretanto, procure evitar este tipo de prática).

Por outro, extremo cuidado deve ser tomado com o(s) argumento(s) da função caso ele(s) venha(m) a ser modificado(s) dentro da função. Neste caso não haverá independência entre as duas variáveis correspondentes e a modificação sofrida pelo argumento dentro da função será transmitida para a variável correspondente dentro do programa principal. Considere o programa abaixo, que calcula, com o auxílio de uma função, o fatorial de um número fornecido via teclado pelo usuário:

program fatorial

implicit none

integer i,numero

real fator,fatore

print*, "Forneça um número INTEIRO para o calculo do fatorial:"

read(*,*) numero

if (numero .LT. 0) then

print*, "O fatorial não é definido para um número negativo."

else

if (numero .EQ. 0) then

print*, "O fatorial de 0 é igual a 1."

else

fator=fatore(numero)

print*

print*,"RESULTADO:"

print*,"O fatorial de ",numero," é igual a:",fator

print*

end if

end if

stop

end

!

function fatore(numero) ! Esta função calcula o fatorial de numero

integer numero

real fatore

fatore=1.

do while (numero .GT. 0) ! Só pára quando numero for igual a zero

fatore=fatore*float(numero)

print*,numero,fatore

numero=numero−1

end do

return

end

No programa principal na hora de executar o comando:

print*,"O fatorial de ",numero," é igual a:",fator

ele escreverá: “O fatorial de 0 é igual a...” ( ERRADO! Este erro acontece porque a variável numero (que é um argumento fornecido para função fatore) foi modifica dentro da função fatore e, portanto, esta modificação foi transmitida para a variável numero do programa principal.

Para resolver este conflito seria adequado fazer:

1) Declarar no programa principal mais uma variável inteira (por exemplo, num):

integer i,numero,num

2) Antes de acionar a função fatore, atribuir à nova variável num o valor da variável numero e então fornecer para a função fatore o argumento num e não o argumento numero:

......

else

num=numero

fator=fatore(num)

......

Com isto “protegemos” a variável numero (do programa principal) de quaisquer modificações que o argumento possa sofrer dentro da função, mesmo que na função o argumento tenha o mesmo nome da variável numero (como é o caso neste exemplo).

Atenção: se ao invés disto tivéssemos optado apenas por mudar o nome da variável-argumento na função, o problema persistiria. Por exemplo, se na função fatore mudássemos o nome da variável-argumento para, por exemplo, teste então todas as modificações sofridas por teste dentro da função seriam transferidas para a variável numero no programa principal e o erro aconteceria de novo:

( programa principal aciona a função fatore fornecendo a variável numero como argumento:

fator=fatore(numero)

( A função fatore recebe o valor de numero através da sua variável-argumento teste.

function fatore(teste)

integer teste

real fatore

fatore=1.

do while (teste .GT. 0)

fatore=fatore*float(teste)

print*,teste,fatore

teste=teste−1

end do

return

end

Logo, a melhor opção é fornecer, no programa principal, uma outra variável como argumento para a função fatore, como fizemos ao adicionar uma nova variável (num) no exemplo anterior.

Evidentemente, este tipo de problema só ocorrerá CASO a(s) variável(eis)-argumento da função seja(m) modificada(s) dentro da função. Caso contrário não ocorrerá problemas de mudança involuntária do valor da variável do programa principal.

Univsersidade Federal de Santa Maria

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 21

19.0 SUBROTINAS:

Assim como funções, as subrotinas também funcionam como “programas dentro de um programa”. A diferença está no fato das subrotinas geralmente executarem um maior número de tarefas que as funções. Isto acontece porque, ao contrário das funções, as subrotinas podem retornar mais de um valor ou informação para o programa que as aciona. Na verdade, as subrotinas podem ser concebidas pelo programador para assumir o total controle da execução das tarefas do programa, deixando o programa principal como um mero “distribuidor” destas tarefas.

Outra diferença importante é que enquanto as funções retornam valores/informações através de uma variável que tem o mesmo nome da função, as subrotinas retornam os valores/informações através de seus argumentos. Além disto, é possível desenvolver subrotinas que não retornam valor/informação algum(a) para o programa que as aciona, executando apenas tarefas cujos resultados não necessitam ser retornados ao programa.

A terceira diferença entre funções e subrotinas está na forma com que a subrotina é acionada. As funções são acionadas diretamente pelo seu nome associado ao(s) respectivo(s) argumento(s), enquanto que as subrotinas são acionadas por um comando do FORTRAN chamado CALL. Veja a comparação abaixo entre a forma de acionar uma função volt e uma subrotina volt:

FUNÇÃO VOLT

var=volt(...argumentos...) ( acionando a função volt aplicada ao(s) argumento(s). Seu resultado (único) será atribuído à variável var.

SUBROTINA VOLT

call volt(...argumentos...) ( acionando a subrotina volt aplicada ao(s)

argumento(s). Seus resultados serão retornados através

dos seus próprios argumentos.

Na função volt todos os argumentos têm que ter um valor definido no momento em que a função é acionada. Na subrotina volt não é obrigatório que todos os seus argumentos tenham seus valores definidos no momento em que a subrotina é chamada. Tipicamente, aqueles argumentos que são fornecidos para a subrotina sem possuir um valor definido são os argumentos que receberão de volta o(s) resultado(s) da(s) tarefa(s) executada(s) pela subrotina.

A sintaxe geral para o programa acionar a subrotina é:

call nome_da_subrotina (lista de argumentos)

A sintaxe geral do cabeçalho da subrotina é:

subroutine nome_da_subrotina (lista de argumentos)

Geralmente (mas não obrigatoriamente) a lista de argumentos fornecida para a subrotina contém argumentos que fornecem valores/informações para a subrotina e argumentos que recebem de volta da subrotina o(s) resultado(s) da tarefa(s) executada(s) por ela.

Toda subrotina é terminada com um comando end.

subroutine nome_da_subrotina (lista de argumentos)

...< corpo da subrotina>...

end

Abaixo temos um exemplo simples de um programa que converte ângulos de graus para radianos utilizando uma subrotina chamada converte.

program conv ! Programa principal

implicit none

real graus,radianos

print *,“Forneca o ângulo em graus:”

read(*,*) graus

call converte(graus,radianos) ! O programa principal chama a subrotina

write(*,*) “O valor do ângulo em radianos é:”, radianos

stop

end ! Final do programa principal

C

subroutine converte(entrada,saida) ! Cabeçalho da subrotina

real entrada,saida,pi

parameter (pi=3.1416)

saida=entrada*pi/180.

end ! Final da subrotina

No exemplo acima o programa principal lê o valor do ângulo em graus fornecido pelo usuário e depois aciona a subrotina converte através do comando CALL. A conversão de graus para radianos é realizada dentro da subrotina.

Observações importantes:

( Não precisamos “declarar” a subrotina dentro do programa principal; basta acioná-la com o comando CALL. Assim como as funções, o código fonte da subrotina deve seguir abaixo do programa principal. Nenhuma subrotina pode ter o mesmo nome do programa principal;

( Repare que ao acionar a subrotina converte duas variáveis reais foram indicadas como argumentos (graus e radianos). Uma das variáveis (graus) refere-se ao ângulo fornecido pelo usuário via teclado. A outra variável (radianos) não tem nenhum valor atribuído a ela no momento em que a subrotina é chamada.

call converte(graus,radianos)

( No cabeçalho da subrotina converte os dois argumentos consistem das variáveis entrada e saida, as quais são declaradas como sendo do tipo real logo no início da subrotina.

subroutine converte(entrada,saida)

real entrada,saida,pi ! Declarando as variáveis entrada e saída como sendo do tipo real

Na execução do programa principal, o valor atribuído à variável graus é passado para a variável entrada da subrotina converte. Além disto, a variável radianos no programa principal é associada à variável saida da subrotina. Ou seja, assim como nas funções, uma associação é realizada entre os argumentos fornecidos à subrotina e os argumentos correspondentes presentes no cabeçalho da subrotina. Esta associação é feita seguindo a ordem em que as variáveis são listadas, mesmo que possuem nomes diferentes:

call nome_da_subrotina (argumento1, argumento2, argumento3, argumento4, etc...)

subroutine nome_da_subrotina(argumentoA, argumentoB, argumentoC, argumentoD, etc...)

A variável argumento1 no programa principal é associada à variável argumentoA da subrotina; a variável argumento2 no programa principal é associada à variável argumentoB da subrotina; e assim por diante. É por este motivo que as variáveis da subrotina têm que ser do mesmo tipo da variável com que estão sendo associadas no programa principal.

No nosso exemplo temos:

Programa principal Subrotina converte

graus (tipo real) entrada (tipo real)

radianos (tipo real) saida (tipo real)

Assim, a variável real entrada na subrotina recebe o valor do ângulo em graus. Em seguida, dentro da subrotina, o valor do ângulo em graus é convertido para radianos:

saida=entrada*pi/180.

Agora a variável real saida na subrotina corresponde ao valor do ângulo em radianos. Como a variável saida foi associada à variável radianos no programa principal, após a execução da subrotina converte o valor de radianos no programa principal foi atualizado, e então o resultado pode ser escrito na tela.

( Repare que, além dos argumentos ( isto é, da associação entre as variáveis do programa principal e as variáveis da subrotina ( a subrotina pode ter suas próprias variáveis internas, necessárias para a execução da subrotina, mas que não se “comunicam” como programa principal. No caso da subrotina converte há uma variável interna do tipo real: pi (declarada como constante).

É importante mencionar que as variáveis internas da subrotina podem ter o mesmo nome de variáveis do programa principal sem que haja conflito entre elas. Isto é possível por que o programa principal só se comunica com a subrotina através das variáveis que são fornecidas como argumentos, e não através das variáveis internas da subrotina. Por exemplo:

program aula

implicit none

integer var1

real valor,teste

....

call exemplo(valor,teste)

....

end ! Fim do programa principal

subroutine exemplo(a,b)

real a,b

character*7 var1

...

end ! Fim da subrotina

No programa principal a variável var1 é do tipo real. Na subrotina a variável var1, que é interna à subrotina, é do tipo caractere. Não há conflito entre elas porque o programa principal “desconhece” a existência da variável var1 da subrotina. A única troca de informação entre a subrotina e o programa principal é através das variáveis argumentos: valor ( a ; teste ( b.

De volta ao exemplo do programa que faz a conversão do ângulo de graus para radianos, como fica o fluxo de informação no programa? Vamos imaginar a execução do programa:

(1) Forneça o ângulo em graus:

60. => valor fornecido pelo usuário

Então a variável graus recebe o valor 60.0

(2) call converte(graus,radianos)

O programa principal chama a subrotina converte. Nesta altura da execução apenas a variável graus possui um valor conhecido (=60.0). O valor da variável radianos ainda está indefinido.

(3) A execução temporariamente deixa o programa principal e segue para a subrotina converte. Como a variável entrada da subrotina é associada à variável graus do programa principal então o valor de entrada é 60.0

A variável saída da subrotina é associada à variável radianos do programa principal, então o valor de saida ainda está indefinido.

entrada = 60.0

saida = ???

(4) Dentro da subrotina converte a seguinte operação é realizada:

saida = entrada*pi/180.

, onde pi foi declarada como uma constante real no início da subrotina (pi=3.1416).

Então agora a variável saída recebe o valor:

saida = 60.0 * 3.1416 / 180.

isto é:

saida = 1.0472

Como a variável saida foi associada à variável radianos no programa principal, então a variável radianos também recebe o valor igual a 1.0472. Isto é:

radianos = saida = 1.0472

(5) Após realizar a conta de conversão a execução da subrotina encontra o comando end dentro da subrotina. Isto significa que é hora de retornar ao programa principal.

(6) A linha seguinte no programa principal é:

write(*,*) “O valor do ângulo em radianos é:”, radianos

A esta altura o valor da variável radianos é 1.0472, porque este foi o valor repassado pela execução da subrotina converte. Logo o resultado será, na tela:

O valor do ângulo em radianos é: 1.0472

Como exercício, poderíamos escrever o mesmo programa da seguinte forma:

program conv

implicit none

real graus, radianos

call leitura(graus) ! Programa principal chama a subrotina que lê o ângulo em graus

call converte(graus,radianos) ! Programa principal chama a subrotina de conversão

call escreve(radianos) ! Programa principal chama subrotina que escreve o resultado na tela

stop

end ! Final do programa principal

! Subrotinas

subroutine leitura(pindamonhagaba) ! Subrotina que lê o ângulo em graus

real pindamonhagaba

print *, “Forneca o angulo em graus:”

read(*,*) pindamonhagaba

end

!

subroutine converte(entrada,saida) ! Subrotina que realiza a conversão

real entrada,saida,pi

parameter (pi=3.1416)

saida=entrada*pi/180.

end

!

subroutine escreve(birobiro) ! Subrotina que escreve o resultado na tela

real birobiro

write(*,*) “O valor do ângulo em radianos é:”, birobiro

end

Desta vez utilizamos 3 subrotinas: uma para leitura do ângulo em graus, outra para conversão de graus para radianos e outra para escrever o resultado na tela. Deste modo o programa principal se transformou simplesmente num “gerenciador de tarefas”, que são delegadas às subrotinas.

Universidade Federal de Santa Maria

Disciplina: Computação Básica para Física – FORTRAN (FSC1004)

Prof. Ernani L. Nascimento

AULA 22

19.1. Alguns exercícios envolvendo subrotinas:

(1) Conversão de coordenadas polares para coordenadas cartesianas (2D):

A posição P de um ponto no espaço bidimensional pode ser determinada, em relação a uma origem O, por uma representação em coordenadas polares:

| [pic] |

, onde r é a distância à origem e ( é o ângulo entre o segmento de comprimento r e o eixo horizontal positiva; x e y são os eixos horizontal e vertical das coordenadas cartesianas. As expressões que relacionam as coordenadas polares com as coordenadas cartesianas são: x = r cos (; y = r sen ( .

Escreva, compile e execute um programa FORTRAN que receba do usuário a posição P em termos dos valores r e ( e a converta, através de uma subrotina, para coordenadas cartesianas.

program polares

implicit none

real rpol,theta,xis,ipsilon

character*1 opcao

opcao=‘S’

do while ((opcao .EQ. ‘S’) .OR. (opcao .EQ. ‘s’))

print*

print*,‘Forneça a posição em coordenadas polares r e theta (em gr

&aus)’

read(*,*) rpol,theta

call converte(rpol,theta,xis,ipsilon)

print*

print*,‘Em coordenadas cartesianas esta posição é:’

print*,‘X =’,xis,‘ Y =’,ipsilon

print*

print*,‘Deseja realizar outra conversão polar => cartesiana?’

print*,‘S(sim) ou N(Não)?’

read(*,*) opcao

end do

stop

end

C

subroutine converte(a,b,c,d)

real a,b,c,d,pi

parameter (pi=3.14159)

b=b*pi/180. ! Converte de graus para radianos

c=a*cos(b)

d=a*sin(b)

end

(2) Área e volume da esfera:

Escreva, compile e execute um programa que calcule a área (A) e o volume (V) de uma esfera dado o seu raio (R). O cálculo da área e do volume deve ser feito dentro de uma subrotina: A= 4(R2 , V= 4(R3/3

(3) Integração numérica:

É possível programar um computador para calcular derivadas e integrais. A solução analítica de derivadas e integrais fornece resultados exatos, enquanto que a solução de derivadas e integrais em um computador fornece resultados aproximados; esta é a chamada solução NUMÉRICA. Ou seja, o CÁLCULO NUMÉRICO trata da solução aproximada de derivadas e integrais utilizando o computador. Uma das importâncias de se utilizar computadores para esta tarefa é que existem equações na Matemática, Física e ciências afins que não possuem solução analítica conhecida. Para estas equações resta a solução aproximada com um computador via MÉTODOS NUMÉRICOS. Abaixo fazemos um estudo simples de INTEGRAÇÃO NUMÉRICA da função f(x)=x2 +1, que possui solução analítica:

[pic]

Se a=0 e b=1 temos a solução igual a 1,3333...

Vamos agora resolver esta integral de maneira numérica (isto é, utilizando um computador).

De uma maneira geral, o problema trata então de calcular de maneira aproximada uma integral:

[pic]

Se f(x) for não-negativa no intervalo entre [a,b], isto corresponde a dizer que queremos calcular a área da região sob o gráfico de y=f(x) entre x=a e x=b:

|[pic] |

As soluções analíticas (quando existem) fornecem o valor exato da área sombreada. As soluções numéricas fornecem um valor aproximado desta área.

Existe mais de um método de integração numérica; vamos considerar o mais simples deles, chamado de MÉTODO DO RETÂNGULO. Para isto vamos dividir a área sob a função não-negativa y=f(x) entre x=a e x=b por n intervalos iguais.

|[pic] |

Cada intervalo tem largura (x = (b − a)/n. Repare que cada intervalo horizontal (x é a base de um retângulo, cuja altura (y é a distância entre o eixo horizontal dos x e a função y=f(x) válida em um ponto localizado na metade de cada distância (x (x1, x2, x3,....,xn). Se somarmos as áreas de todos os retângulos localizados dentro do intervalo [a,b] obtemos um valor aproximado da área da região sob o gráfico de y=f(x) entre x=a e x=b:

soma das áreas dos retângulos ( f(x1) (x + f(x2) (x + f(x3) (x + .... + f(xn) (x

Se os valores de a e b no eixo x forem fornecidos, assim como o número de n intervalos em que queremos dividir a distância [a,b], podemos então calcular numericamente a integral da função entre a e b. No nosso caso será a função f(x)=x2+1.

Escreveremos um programa que resolve o algoritmo abaixo:

( a, b e n são fornecidos pelo usuário (a e b reais, e n inteiro);

( estes valores são fornecidos para uma subrotina que será responsável por realizar a integração numérica da função f(x)=x2+1 entre a e b;

( na subrotina:

* calculamos (x = (b − a)/n

* calculamos x1=a+(x/2; x2= x1+(x; x3= x2+(x; x4= x3+(x; .....; xn= x(n-1)+(x

* calculamos f(x1), f(x2), f(x3),f(x4),....,f(xn), onde f(x)=x2+1

* calculamos as áreas A1=f(x1)(x; A2= f(x2)(x; A3=f(x3)(x; A4=f(x4)(x;....; An=f(xn)(x

* somamos as áreas Ai [com i=1,n]:

Área total = [pic], que será o resultado da integração numérica.

( de volta ao programa principal escrevemos o resultado na tela. Abaixo segue o programa:

program integracao

implicit none

integer n

real arg,area

dimension arg(2)

print*

print*,‘Forneça os limites da integração (a e b) no eixo x:’

read(*,*) arg(1),arg(2) ! arg(1) = a, arg(2)=b

print*,‘Forneça o número de intervalos (retângulos):’

read(*,*) n

call integra(arg,n,area)

print*

write(*,*)‘A integração numérica de f(x)=x**2+1 entre x=',arg(1),'

& e x=',arg(2),‘utilizando o método do retângulo com ',n,' retângul

&os é ',area

print*

stop

end

C

subroutine integra(lim,int,soma) ! lim(1) recebe arg(1); lim(2) recebe arg(2)

integer int,i

real lim,soma,deltax,mei,y,calc

dimension lim(2)

deltax=(lim(2)−lim(1))/float(int) ! (b – a)/n

mei=lim(1)+deltax/2. ! x1

soma=0.0

do i=1,int ! de i=1 a i=n

y=calc(mei) ! Chama a função CALC, que retorna o valor f(x)=x**2+1

soma=soma+y ! Soma o valor da f(x) válida para mei

meio=meio+deltax ! Avança para o próximo valor de x

enddo

soma=soma*deltax ! Multiplica o somatório por delta x, dando o resultado final

end

C

real function calc(valor)

real valor

calc=valor**2+1. ! f(x)=x**2+1

end

Execute para a=0.0 e b=1.0. E repare que quando maior é o número de intervalos (i.e., retângulos) usados, mais o resultado numérico se aproxima do resultado analítico calculado na página 2. Isto faz sentido; pela segunda figura da página 2 nós podemos inferir que quanto maior o número de retângulos utilizados, menor é o erro cometido ao aproximarmos a área real pela soma das áreas dos retângulos.

-----------------------

(1) O USUÁRIO FORNECE OS DADOS DE ENTRADA PARA UM ARQUIVO EXECUTÁVEL (UM PROGRAMA EXECUTÁVEL)

(2) PROGRAMA EXECUTÁVEL (“CAIXA PRETA”) REALIZA AS OPERAÇÕES

(3) O PROGRAMA EXECUTÁVEL FORNECE O RESULTADO

(1) O USUÁRIO ESCREVE UM CÓDIGO FONTE

(2) O USUÁRIO CRIA UM ARQUIVO EXECUTÁVEL

(3) O USUÁRIO FORNECE OS DADOS DE ENTRADA PARA O ARQUIVO EXECUTÁVEL

(4) PROGRAMA EXECUTÁVEL REALIZA AS OPERAÇÕES

(5) O PROGRAMA EXECUTÁVEL FORNECE O RESULTADO

Multiplica o resultado da raiz cúbica por -1.

Multiplica a variável (de valor negativo!) por -1.

Entrada de dados para o programa , via atribuição direta no código fonte.

Entrada de dados para o programa, via teclado.

Explica para o usuário o objetivo do programa.

Solicita ao usuário o dado de entrada.

O programa vai aguardar o usuário fornecer dois valores.

Entrada de dados.

Execução de cálculos.

Saída dos resultados, com o comando WRITE.

Uma linha em branco será incluída entre as duas linhas com texto.

rótulo

rótulo

i5

6 espaços

Só será executado se int2 ( 0

Só será executado se int2 = 0

Sequência_1 de comandos

Sequência_2 de comandos

Sequência_3 de comandos

Sequência_1 de comandos

Sequência_2 de comandos

Sequência_3 de comandos

notas

alunos

10 valores fornecidos em linhas diferentes

10 valores fornecidos em linhas diferentes

O terceiro conjunto de 4 valores fornecido pelo usuário forma a terceira coluna.

O segundo conjunto de 4 valores fornecido pelo usuário forma a segunda coluna.

O primeiro conjunto de 4 valores fornecido pelo usuário forma a primeira coluna.

Nota 3

Nota 1

Nota 2

Aluno1

Aluno2

Turma 3

Aluno4

Aluno3

Turma 2

Turma 1

Aluno5

aluno

nota

turma

nota

aluno

turma

ano

Argumento fornecido

Nome da função

Tipo do valor retornado pela função volt para o programa principal.

Nome da função.

Argumento fornecido para a função volt.

Argumento do tipo inteiro

Utilizando a função float dentro da função volt.

inteiro

real

real

inteiro

real

real

Declaramos uma variável tipo caractere com comprimento máximo de 30 caracteres. Repare que esta variável tem o mesmo nome da função que acionamos no programa principal.

Acionamos a função, fornecendo o argumento index.

A função retorna um valor tipo caractere, cujo comprimento máximo é 30 (como declarado para a variável poluicao no programa principal)

A variável limiar é usada internamente na função e não tem ligação nenhuma com o programa principal.

A variável indice também pertence apenas à função, mas possui uma ligação com o programa principal uma vez que recebe o valor fornecido via argumento da função. Apesar disto, indice não precisa ser declarada no programa principal.

Aciona a função fatore.

Fornece numero como argumento para fatore.

Na função fatore o argumento também é chamado de numero.

A variável numero (que é um argumento da função) é modificada dentro da função. Esta modificação será “sentida” pela variável |1 |1 |1 |

1 |1 |1 |1 |1 |-1 | 1 |!1 |+1 |,1 |/1 |01 |21 |31 |41 |51 |G1 |H1 |K1 |L1 |U1 |V1 |€1 |?1 |²1 |³1 |´1 |µ1 |ø1 |ù1 |numero no programa principal, pois elas se comunicam.

A variável teste (que é um argumento da função) é modificada dentro da função. Esta modificação será “sentida” pela variável numero no programa principal, pois elas se comunicam.

é associada à variável

é associada à variável

y

Solução analítica

f(x4)

(

(y

(x

................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download