FORTRAN
A linguagem de programação Fortran foi desenvolvida na década de 1950 e continua a ser usada hoje em dia. O nome tem como origens a expressão "Formula Translator" (ou "Translation"). A linguagem Fortran é principalmente usada em ciências da computação e análise numérica.
O primeiro compilador de FORTRAN foi desenvolvido para o IBM 704 em 1954-57. O compilador era optimizado, pois os autores acreditavam que ninguém iria usar essa linguagem se a sua prestação não fosse comparável com a da linguagem assembly A linguagem Fortran foi largamente adoptada por cientistas para a escrita de programas numericamente intensivos, o que encorajou os produtores de compiladores a escrever compiladores que gerassem código mais rápido. A inclusão de um tipo de dados de número complexo na linguagem tornou a linguagem Fortran particularmente apta para a computação científica. Ao longo dos tempos foram-se dando algumas revisões da linguagem. Entre elas encontram-se:
- FORTRAN IV (também conhecida como FORTRAN 66)
- FORTRAN 77, 90, 95
--Origem: Wikipédia, a enciclopédia livre.
Olá Mundo
Exemplos de código típico e mínimo para testar se o Fortran90 está instalado (ha um equivalente para cada linguagem)
print*,"olá Mundo" end
Editar
Essas duas linhas devem estar dentro de um arquivo (ex: ola.f90), isto pode ser feito com cat linha por linha ou com um editor de texto (jed ou emacs)
Compilar
ola.f90 deve ser compilado, isto é traduzido de linguagem de Fortran (código fonte) para Assembler (código objeto ou de maquina) com a seguinte instrução:
> f90 ola.f90 -o ola
f90 invoca o compilador que faz a dita conversão
-o nome é uma opção para nomear o código objeto (o programa executável) que no exemplo terá o nome ola
sem essa opção o executável criado terá o nome a.out
Rodar
ola.f90 não é executável, o computador não sabe o que fazer com ele, para isso o compilador traduz para una série de instruções que o computador sim sabe executar)
Para rodar fazemos: > ./ola
./ na frente é necessário para o interprete de comandos (shell) saber que o programa está no diretório de trabalho (veremos depois como configurar a sessão para não ter que digitar esses caracteres)
> olá Mundo ! será a saída na tela
Desta forma completamos o pequeno ciclo de teste de existência de compilador Fortran 90 no computador que estamos usando e também de ter criado nosso primeiro código Fortran, compilado e executado o mesmo.
Olá Mundo (versão com estilo padrão: program ... end program)
program ola print*,"olá Mundo" end program ola
Esta versão está mais no estilo que usaremos daqui para frente, mesmo que opcional a declaração program nome (terminada com end program) é útil quando temos códigos longos com sub-rotinas (estes são programas chamados pelo programa principal
Variáveis
Em linguagem de programação "Variáveis" são nomes definidos pelo programador onde podem ser armazenados números ou texto para uso posterior, sobre os quais podem ser feitas operações matemáticas, lógicas ou de manipulação de caracteres, e que também podem ser alteradas ou substituídas por novos conteúdos dependendo das instruções do programa.
Podemos dizer que um programa é feito de constantes, variáveis e instruções de operações entre elas que definem uma tarefa a ser desenvolvida automaticamente pelo computador.
Em FORTRAN existem cinco tipos de variáveis:
INTEGER -> enteira, exemplo: 0, 1, 100 -34 REAL -> real o de ponto flutuante, exemplo: 3.14, -0.003, 3.2E-10, -5.02E100 (notação científica) COMPLEX -> complexa, exemplo: (2.3, 0), (0, -1.0), (1.2E-5, -0.001) LOGICAL -> logica, exemplo: .TRUE. .FALSE. (só essas) CHARACTER -> caracter, exemplo: "ola", "Entre seu nome!"
No programa a definição de variáveis é feita no início assim
Program test Integer I, J, K Real a, x, velocidade, tempo_0, Temp Logical prova Character*10 Titulo, nome ...
São as chamadas declarações de variáveis, depois seguem as instruções de execução
Bytes
Em computação byte é uma unidade de medida de armazenagem de informação, tipicamente de oito bits. O bit, pela sua vez, é a mínima quantidade de informação possível, ou seja a menor unidade de medida de armazenagem de informação. É onde podemos guardar apenas dois estados: 0 ou 1, sim ou não, etc. Menos do que isso não é informação nenhuma, pois de fato, menos do que isso é um estado único que só pode ser sempre 0 ou 1 ou 2, mais é sempre igual, ele só pode tomar esse único valor e não mudar. Para ter informação então, no mínimo precisamos de dois estados: ora é um, ora é zero. Por isso alguém chamou o bit de ... a mínima diferença que faz a diferença.
A origem do bit é anterior ao computador, provavelmente de 1936, e o nome vem da contração de dígito binário em inglês. Os dígitos binários eram usados anteriormente e são apenas uma representação dos números como é a decimal, porem com base nas potências de 2. assim um número binário só pode estar composto de 0 e 1 (como um decimal esta só composto dos dígitos de 0 a 9). Como exemplo o numero binário 1001100 representa o número decimal 76. (texto em preparação--Sebas 12:42, 11 Setembro 2007 (BRT))
Entrada e Saída
São as intruções READ e WRITE (ou PRINT) O READ permite entrar dados antes ou durante a execução do programa.
Com o WRITE podemos ver os resultado final da execução do código ou acompanhar o desenvolvimento do mesmo.
Exemplos:
READ (*,*) I, Velocidade ... Write (*,*) Titulo, Temp
Esta última é equivalente a
PRINT*, Titulo, Temp
Todas essa representam entrada/saída pelo terminal Entrada pelo Teclado. Saída na Tela. São as chamadas entrada/saida standar
Se quisermos ler ou gravar num arquivo:
OPEN (1, FILE="entrada.dat") READ(1,*) I, Velocidade OPEN (2, FILE="entrada.dat") WRITE (2,*) Titulo, Temp CLOSE(1) CLOSE(2)
Operadores matemáticos
Operador | Função |
---|---|
. | ponto decimal |
+ | soma |
- | resta |
* | multiplicação |
/ | divisão |
** | potência |
( ) | parênteses |
Exemplo usando todas
z = 3.14*x**(-1.4)/2 - 4.3E-10
Funções intrínsecas
Estas são as funções pré-definidas no compilador, entre as quais encontramos a mais comummente utilizadas como raiz quadrada, trigonométricas, exponencial, etc: A sintaxe de uso é o nome da função (geralmente três letras) e o argumento entre parêntesis:
raiz quadrada: sqrt trigonométricas: sin, cos, tan, asin exponencial: exp logaritmo natural: log módulo: abs
Exemplos:
a = sqrt(2.) b = sin(x) Pi = 2.*asin(1.) uma forma pratica de ter Pi como constante dentro de um programa y = (x - exp(-lam*x**2))/sqrt(x) z = x**(1./4.) Cuidado! Teste com 1/4 em lugar de 1./4. e verá a grande diferença
Ciclos (loop)
O grande lance dos programas (e do computador claro) é poder repetir operações sem ter que fazer uma de cada vez. Ou seja, utilizando a lógica para repetir tarefas que podem ter variações especificadas pelo programador dentro de um ciclo. Vejamos um exemplo usando a instrução Do I=... End Do:
... Do I = 1, 100 x = I*0.1; y=x**2 Print*, x,y End Do ...
Nota a diferencia do shell onde maiúsculas e minúsculas são diferentes (A é diferente de a) no Fortran elas *SÃO* interpretadas da mesma forma (print = PRINT = PrInT=...). Porem, é recomendado, por uma questão de estilo, usar preferentemente minúsculas, reservando maiúsculas para aquilo que se quer chamar a atenção.
o Ponto e vírgula permite separar instruções diferentes em uma mesma linha
a interpretação do do é a seguinte:
* comece com I=1 * faca o que esta entre do ... end do * incremente I em 1 e veja se ultrapassou o valor máximo de I (no exemplo 100) * se a resposta e não faca de novo com o novo valor de I * o ciclo se repete até o valor máximo de I (= 100 no exemplo) * quando I ultrapassa esse valor o laço é interrompido e o programa continua com a seguinte instrução depois de end do
Pergunta:
Qual será no exemplo acima o valor da variável I finalizado o laço?
Exemplo: MRUA
Neste exemplo criamos um programa que gera a trajetória x(t) (uma dimensão) de um objeto com aceleração constante:
x(t) = x(0) + v(0)*t + 0.5*a*t²
program mrua implicit none ! isto nos obriga a declarar todas as variáveis que usaremos (recomendável) real :: x0, x, v0, a, t, dt ! variáveis reais (ponto flutuante) integer :: I, N print*, 'entre x0, v0, a, t, N' read*, x0, v0, a, t, N dt = t/N ! passo de tempo: definido pelo tempo máximo e o numero de pontos da trajetória t = 0 do i = 1, N x = x0 + v*t + 0.5*a*t**2 print*, t, x t = t + dt end do end program mrua
Nota: este programa tem um erro que você deve descobrir
Controle de Fluxo (IF e CASE)
Possibilitam a escolha de rumos diferentes no programa dependendo de valores de variáveis ou condições entre elas.
IF ... THEN ...
A sintaxe é:
if (condição) then instruções executadas quando condição verdadeira else instruções executadas quando condição falsa end if
Para apreciar o poder dela primeiro vejamos:
Operadores relacionais e lógicos
Operador | Função |
---|---|
== | igual |
/= | diferente |
> | maior |
>= | maior ou igual |
< | menor |
<= | menor ou igual |
.AND. | E lógico |
.OR. | OU lógico |
.NOR. | NÃO lógico |
Eles são usados junto com as instrucões de controlo como o IF (se), exemplo:
! exemplo de divisão a x b: ... read*, a, b if (b /= 0) then c = a/b else stop 'b=0' end if print*, 'a/b=', c ...
CASE
Este serve para quando temos muitas opçõs ou escolhas para tomar rumos diferentes no programa.
Vejamos a sintaxe diretamente no exemplo:
Select Case (J) Case(1) print*, "caso 1" Case(2) print*, "caso 2" Case (4:10) print*, "caso 4-10" .... Case Default print*, "não foi nenhum dos casos contemplados" End Select
Ciclos (Avançado)
Ciclo infinito (Do ... end Do)
Se não especificamos com um índice o numero de vezes que o laço deve ser executado este será executado para sempre. Exemplo:
Do print*, "All work and no play makes Jack a dull boy" End Do
vai fazer que a tela do computador pareça ter sido controlado por um espírito maligno saído do filme O Iluminado. Só vamos poder cortar a loucura dela com CTRL C.
Para que seja de utilidade usamos o Exit, como no exemplo abaixo:
Do Print*, "Digite o número 1 ou 2" Read*, num Select Case (num) Case (1) Print*, "Você digitou 1" Exit Case (2) Print*, "Você digitou 2" Exit Case Default Print*, "Opção inválida" End Select End Do
Se queremos um programa a prova de fogo (ie que não de erro por entrada de dados) podemos fazer uma pequena modificação:
Do Print*, "Digite o número 1 ou 2" Read(*,*,ERR=100) num Select Case (num) Case (1) Print*, "Você digitou 1"; Exit Case (2) Print*, "Você digitou 2"; Exit Case Default 100 Print*, "Opção inválida" End Select End Do End
Na qual usamos ERR=100 para o código se recuperar de dado inesperado, transferindo o controle do programa para a linha com esse número em caso de erro (texto em lugar de número por exemplo).
Ciclo condicional (Do While)
O Do While é executado enquanto uma condição lógica é satisfeita. Exemplo:
I = 1 Do While ( I <= 100 ) I = I + 1; print*. I End do
Resulta equivalente a:
Do I + 1, 100 print*. I End do
Porem é de utilidade quando a condição não é trivial. Exemplo:
fac = 1. + 1./3.; Imax = 1.E6 I = 1; print*, I Do While ( I < Imax ) I = fac*I; print*, I End do
Arranjos (Arrays)
Tecnicamente, são tipos de dados ou variáveis estruturadas. De outra forma, um arranjo é um conjunto de dados escalares, todos do mesmo tipo (REAL ou INTEGER, etc), organizados de forma regular de maneira que é fácil atribuir ou extrair valores deles.
Assim como um escalar real é definido como
Real A
um array real pode ser definido assim:
Real A(10)
No primeiro exemplo A pode conter apenas um valor por vez, enquanto no segundo, 10 diferentes valores podem ser armazenados em A, cada um dos quais pode ser referido via o índice assim
A(1) = 0; A(2:7) = 4; A(8) = -1; A(9:10) = 2
Do i =2, 10, 2 print*, A(i) !imprimindo só as posições pares End do
Rodando esse programa teremos na tela:
4.000000 4.000000 4.000000 -1.000000 2.000000
Arranjos Estáticos
Arranjo estático e aquele cuja dimensão (números de elementos do arranjo) é definido nas declarações (instruções no início do programa e que não são executadas durante o tempo de rodada), é um número fixo que não pode ser mais alterado durante a execução. Exemplos:
Real A(10), B(30) Integer GG(10,10), ax(5,20), FG(6,10,5)
Também pode ser assim:
Character*10, Dimension (10,10) :: A, B, C, D
A dimensão é definida com Dimension(10,10) para todos os arrays (A,B,C,D), todos eles da mesma forma (shape).
NOTA: quando mais de um atributo é aplicado a uma ou mais variáveis (arrays ou escalares) os dois pares de pontos (::)
entre atributos e variáveis é mandatório
Arranjos Dinâmicos
A diferença com os anteriores é que a dimensão destes é definida durante durante a execução do programa, pudendo até ser modificada durante o mesmo. Isto se consegue com o atributo ALLOCATABLE. Vejamos o exemplo:
Real, Allocatable :: A(:), B(:,:) Integer, Allocatable :: K(:), AJ(:,:,:)
Nesses exemplos definimos A e K como arrays vetoriais, B matricial, e AJ tensorial.
O número de elementos deles é definido durante o tempo de execução com ALLOCATE.
A seguir um exemplo que ilustra a vantagem de usar arranjos dinâmicos
Real, Allocatable :: A(:), B(:,:) Integer I, N, M Read*, N Allocate (A(N), B(N,N)) Do I = 1, N A(I) = 2*I End Do Do i =1, N B(i,:) = A + i End do ... if (j > 0) then Deallocate (B) else Deallocate (A) end if ... Select Case (J) Case(-1) Allocate (A(N/2) Case(2) Allocate (B(N,N/2)) End Select case
Funções e Subrotinas
São módulos independentes para fazer tarefas especificas definidas pelo programador.
Com a declaração FUNCTION é possível definir funções matemáticas diferentes ou além do conjunto de funções intrínsecas do
compilador. Elas podem ser de uma ou mais variáveis, porem devolvem um valor só.
ATENÇÂO a sintaxe: na declaração de função se escreve g(x) (primeira linha nos exemplos
onde se declara o nome da função e das variáveis). Na definição da função se escreve:
g = ...
não se colocam os argumentos ou variáveis a esquerda, elas devem aparecer só a direita da instrução.
Quanto a subrotina ela e um procedimento mais geral que pode operar em um conjunto ou todas as
variáveis que estão no programa principal, e no retorno ao programa não há limite nas variáveis
que pode devolver. Vejamos a sintaxe de cada uma:
Function
A sintaxe é:
REAL FUNCTION NOME(VARIAVEL) ... NOME = operações com VARIAVEL END FUNCTION NOME
Vamos para o exemplo:
Real Function g(x) Implicit None Real x g = x**2 * sin(x) End Function g
Exemplo de duas variáveis:
Real Function paraboloide(z,w) Implicit None Real z,w paraboloide = z**2 + w**2 End Function paraboloide
É possível também definir funções não analíticas, como por exemplo:
... if (x <= 0) then g = 0. else g = 1. end if ...
Logo na execução, dentro do programa principal, se chama como qualquer função intrínseca do FORTRAN. Vejamos um exemplo completo de programa com definição de função.
! este e o program principal que usa a funcao h(x) Program exemplo_uso_funcao Implicit None Real, external :: h(x) Real x, dx, y Integer i,N Print*, "programa para construir tabela de h(x)" Print*, "entre o primeiro e ultimo x e o numero de pontos a graficar" Read*, x0, xf, N dx = (xf - x0)/N Do i = 0, N x = x0 + i*dx print*, x, h(x) End Do End Program exemplo_uso_funca ! aqui a definicao de funcao h(x) Real Function h(x) Real x h = exp(-x**2)/2.0 End Function h
Subroutine
A sintaxe de subrotina e:
SUBROUTINE EXEMPLO (Argumentos) ... END SUBROUTINE
No meio todas as instruções FORTRAN são validas, pois a subrotina é um programa. A idéia é que se um conjunto de operações se repete muito, então resulta conveniente colocá-las num módulo e chamá-lo cada vez que for necessário, assim:
PROGRAM Principal ... CALL EXEMPLO(Argumentos) ... DO ... CALL EXEMPLO(Argumentos) ... END DO ... END PROGRAM Principal
Exemplo:
Program Main implicit None Real A(3,3) Read*, B Call Matriz(A,B) End Program Main Subroutine Matriz(A,B) Real A(3,3) A = B End Subroutine Matriz
Module
Esta estrutura permite definir variáveis de uso comum entre o programa principal e as subrotinas sem se preocupar de passar elas como argumentos das mesmas. Vejamos um exemplo:
Module VARIAVEIS Real a, b Integer N End Module
Depois no programa e subrotina
Program Principal Use VARIAVEIS !o main sabe agora de a,b,N Implicit None ... Read (*,*) a, b, N !estes valores de a,b,N serão passados para sub Call Sub ... End Program Subroutine Sub Use VARIAVEIS !a Subrutina sabe de a,b,N Implicit None ... h = (a-b)/N !e pode usa-las com os valores que tinham quando foi chamada ... End Subroutine