Nahajate se tukaj

Osnove Fortrana

Programski jezik FORmulaTRANslation je bil prvotno razvit 1950 in nato standardiziran 1977. Kasnejše posodobitve vsebujejo Fortran 90.

Glavne prednosti so:

  • Pisanje formul
  • Zelo soroden pisanju matematičnih operaci
  • vgrajena kompleksna števila
  • Upravljanje s polji je naravno. Fortran 90 ima zmogljivo sintakso
  • Zelo optimiziran jezik. Uporaba kazalcev je omejena.
  • Naravni jezik za HPC aplikacije

Slabosti:

  • Slabša povezljivost z drugimi jeziji
  • Izdelava grafičnih vmesnikov (GUI) je težka
  • Uporaba znakovnih nizov
  • Zaradi velike količine znanstvenih kod se ohranja kompatibilnost za nazaj, kar povzroča nekoliko obsežnejži jeik
  • Če pa se uporablja v pravem kontekstu je FORTRAN zmogljiv jezik

Programiranje s Fortran 90

Fortran 90 je vpelljal naslednje novosti:

  • struktuirano programiranje
  • varno programiranje s kontrolo tipov
  • moduli
    • prinašajo zmožnosti vsebovanja kode
    • prinašajo "interface" v podprograme (kontrola tipov argumentov)
    • strukture
  • prenosljivost
    • koncept  podatkovnih objekotv "type"
    • prinaša zmožnosti prenosljivega obnašanja, še posebej za artimetiko plavajoče vejice.

Prvi program

program hello
! Display a message to standard output
implicit none
write (unit = *, fmt= *) ”Hello World!”
end program hello
  • Osnovna sintaksa je v vrsticah.
  • Neobčutljivost na velikosti črk
  • Komentarji se pričnejo s klicajem !

Glavni progam in sintaksa

Formalno se sestoji glavni program iz

 [program program-name]
[specification-statements]
[executable-statements]
end [program [program-name]]

Kjer pomeni besedilo v oglatih oklepajih [] opcijsko uporabo. Več stavkov v eni vrstici ločimi s podpičjem;. Če pa želimo daljše stavke zlimiti v vstice dodamo na kondu znak &, ki pomeni nadaljevanje vrstice v naslednji

 write (unit = *, fmt= *) &
”Nekoliko daljši pozdrav v FORTRANU.!”

Spremenljivke in vgrajeni tipi

implicit none  ! Prisili strogo preverjanje tipov
integer :: i! 10
real :: a! 3.14159
character :: letter! a
character (len= 12) :: month ! Januar
logical :: switch! .false.
complex :: z0, z1! (1.0, 1.0)

Spremeljivke

  • Morajo biti deklarirano pred izvršnimi stavki
  • Morajo imeti sprejemljiva imena iz znakov od katerih mora biti prvi črka.
  • Posebni znaki razen podčrtaja niso dovoljeni

S stavkom implicit none prisilimo strogo preverjanje tipov in ne veljajo privzeti tipi, ki so rezervirani za cela števila. Pravilo je

  • Če je prva črka i,j,k,l,m,n je spremenljivka tipa integer
  • V ostalih primerih je tip real

Implicitna raba imen spremenljivk e nevarna in se jo moramo izogibati.

Polja

Polja vsebujejo skupine vrednosti. Elementi polj so dostopna z indeksi. V Fortranu so polja shranjena v spominu kot kolone in ne kot vrstice, kot v jeziku C - column major.

Polja podajamo z atributom dimension

 integer, dimension(4) :: n4

Kar rezervira 4 elemente: n4(1), n4(2), n4(3), n4(4), Prvi element je privzeto z indeksom 1. Lahko pa določimo tudi spodnje in zgornje meje:

 real, dimension(-5:4) :: r

Večdimenzijska polja določimo z dodatkom dimenzij. Npr.

 complex, dimension(1:10, 1:20) :: z

Dovoljeno je do 7 dimenzij:

real, dimension(2, 3, 4, 5, 6, 1) :: veliko

Znakovna polja

 

So deklarirana podobno kot numerični tipi. Znakovne  spremenljivke lahko

  • Vsebijejo en sam znak
  • Kažejo na niz znakov

Naslednja so pravilne deklaracije

 character :: sex
character (len= 20) :: name
character (len= 10), dimension(10,10) :: carray

Za prirejanje konstantnih nizov lahko uporabimo enojne ali dvojne narekovaje.

Parametri

Se imenjejo konstante in so lahko vseh tipov. Njihova vrednost se ne more spremeniti.

 integer, parameter :: n = 100
real, dimension(2*n) :: r
real, parameter :: pi = 3.14

Prirejanje spremenljivk

Spremenljivke se kahko inicializira na poljubnem mestu v programu,

 program initial_declare
implicit none
integer:: i = 10
real :: pi = 3.14159
character (len= 12) :: month = ”Januar”
end program initial_declare

ali v glavnem programu

 complex :: ci
logical:: iostatus
ci= (0.0, 1.0)
iostatus= .true.

Koncept tipa

S tipom lahko izpeljemo lastne tipe iz obstoječih. Primer take rabe je primeren npr za spremenljivke tipa real, ki so običajno 4 byte, vendar to ni nikjer določeno. Z mehanizmom tipa pa lahko določimo izbrani tip. Npr. s specificiranjem danga decimalne vejice, kar naredimo s parametrom kind.

 integer, parameter :: sp= kind(1.0)
real (kind = sp), dimension(10) :: variable

Razširimo ločljivost na double

 integer, parameter :: dp= kind(1.0d0)
real (kind = dp) :: variable

Fortran 90 omogoča tudi izpeljane tipe s katerimi združujemo osnovne tipe. P

 type person
character (len=10):: name
real:: age
integer:: id
end type person


type(person) :: you, me
you = person(”Janez Kranjec”, 21, 1234)

Elemente izpeljanih tipov lahko naslavljamo z znakom %. Npr za popreje deklarirani tip person

 you%name! vsebuje ime
you%age! starost
you%id! oznaka

Numerični izrazi

  • ** - eksponent
  • * - množenje
  • / - deljenje
  • + - seštevanje
  • - - odštevanje

Pri izračunavanju izrazov z različnimi tipo spremenljivk velja pravilo, da je izračunan izraz vedno tipa, ki je višjega reda. Možno pa je tudi ročno prirejanje tipov z vgrajenimi funkcijami int(), real(), cmplx().

Vgrajene funkcije

Fortran ima zgodovinsko gledano, množico funkcij, ki si vgrajene v sam jezik. Teh je preko 100 in operirajo s polji, biti, znaki,..., kot tudi funkcije za

  • Pretvorbo: int() real() cmplx()abs() nint() aint() aimag()ceiling() floor()
  • Matematiko: sqrt(x)exp(x) log(x) log10(x)sin(x) cos(x) tan(x)asin(x) acos(x) atan(x) sinh(x)cosh(x) tanh(x)
  • Druge: min(x1, x2, ...) max(x1, x2, ...)mod(a, p) conjg() tiny(x) huge(x)

Relacijski operatorji

V 90/95 so poleg že zastarelih opisnih relacijski operatorjev uvedeni še "normalni" izrazi za operatorje, kot jih poznamo v ostalih "modernih" jezikij. Ti so:

 < ! less than
<= ! less than or equal
> ! greater than
>= ! greater than or equal
== ! equal
/= ! not equal

in logični operatorji

 .true.
.false.
.not. ! unary not
.and. ! logical and
.or. ! logical or
.eqv. ! equivalent
.neqv. ! not equivalent

Nadzor poteka programa

Pogojni stavek

 if (logical-expression) then
   block
[else if (logical-expression) then
   block]...
[else
   block]
end if

Primer:

 if (t < 0) then
  ! Mraz je
  led = .true.
else if (t > 100) then
  ! Toplo je
   para = .true.
else
   voda = .true.
   mokro = .true.
end if

Poleg tega so možne še druge oblike pogojnih stavkov, kot je npr elseif ali izbirni if z case. Na primer:

 seasons: select case (mesec)! mesec je tipa integer
   case (1:2,12)! Zima, Dec, Jan, Feb
     write(*,*)”Zima”
   case(3:5)! Pomlad, Mar, Apr, May
     write(*,*)”Pomlad je
   case(6:8)! Poletje, Jun, Jul, Aug
     write(*,*)”Poletje”
   case(9:11) ! Jesen, Sep, Oct, Nov
     write(*,*)”Jesen”
   case default! če je mesec izven 1-12
     write(*,*)"Vnesti je potrebno 1-12"
   end select seasons

Ponavljanje v mejah

 do n = 1, 100
  ! računaj
end do

Formalno je oblika stavka zanke:

 do [variable= expr1, expr2[, expr3]]
   blok
end do

kjer je expr3 izraz za korak. Možen je tudi negativni korak:

 do n = 10, 1, -1
  ! računaj
end do

Enostaven vhod/ihod

Uporabljamo ukaz print v osnovni obliki.

 print*,”Hello World”

Lahko pa uporabljamo tudi write(), ki je bolj uporaben.

Uporabniške funkcije

 result = dist(a, b, c)
...
real function dist(x, y, z)
  real, intent(in) :: x, y, z ! zaščiteni argumenti
  dist = sqrt(x*x + y*y + z*z)! Priredba rezultata
end function dist

  • Funkcije nimajo stavka return
  • So lahko rekurzivni
  • Vrednosti a, b, c se posredujejo z referenco
  • Običajno ne vsebujejo I/O
  • Vrednosti vhodnih argumentov se ne sme spreminjati sicer lahko imamo stranske učinke
  • Uporabimo intent(in), da zagotovimo zaščito argumentov

Podprogrami (subroutine)

call sort(nmax, a, ipass)
...
subroutine sort(nmax, a, ipass)
  integer, intent(in):: nmax
  real, dimension(nmax), intent(inout) :: a
  integer, intent(out) :: ipass
  ! ... tukaj računamo ...
  return
end subroutine sort
 

Podprogrami nikoli ne vračajo vrednosti. Če želimo izhod iz podprograma prej uporabimo ukaz return. Argumenti so lahko:

  • intent(in)
  • intent(inout)
  • intent(out)

Neupoštevanje predpisanega obnašanja se javi pri prevajanju, kar je dobra programerska praksa.

Moduli

Modul je skupek ali zbirka spremenljivk in procedur z naslednjo zgradbo:

 module sort
implicit none
  ! specifikacija spremenljivk
  ...
contains
  ! specifikacija procedur
  subroutine sort_sub1()
  ...
  end subroutine sort_sub1
  ...
end modulesort

Z moduli dosežemo modularno programiranje. Module v drugih delih kode uporabimo s stavkom use:

 program main
  use sort
  implicit none
  ...
  call sort_sub1()
end program main

Primer uporabe modula:

 program scope_main
  use scope_mod
  implicit none

  real :: a = 10.0, b=20.0
  write(*,*)”Pred klicanjem  sub1 a = ”,a,”b = ”,b
  call sub1(a)
  write(*,*)”Po klicanju sub1 a = ”,a,”b = ”,b

end program scope_main

 

 module scope_mod
  implicit none ! Velja za vse kar sledi
  contains
  subroutine sub1(x)
    real, intent(in) :: x
    real :: b = 5.0
    b = b + 1
    write(*,*)”Znotraj sub1 x = ”,x,”b = ”,b
    return
  end subroutine sub1
end module scope_mod

Prevajanje kode z moduli

V primeru imamo celoten porogram iz dveh delov. Glavni (main.f90), ki uporablja sortiranje (sort.f90) sta ločeni datoteki.

 f95 sort.f90 main.f90 –o progsort

Ker main uporablja sort, je pri večini prevajalnikov potrebno napisati sort.f90 pred main.f90

Vidnost spremenljivk v modulih

 module another_module
  implicit none
  private ! nastavi privzeto obravnavo
  public :: nlimit! javno dostopna spramenljivka modula
  integer, parameter :: nlimit= 20! public
  integer :: nlocal= 0! privatna
  real, public :: tmp! javna spremenljivka
contains
...
end module another_module

Privzeta vidnost spremenljivk je public.

 

Zunanji podprogrami

V naslednjem primeru

 program main
...
call sub1()
end program main
subroutine sub1()
...
end subroutine sub1

sta ta dva programa povsem ločeni prevajalni enoti, ki si ne delita vidnosti. Vsa skupna informacija se prenaša z argumenti, katere se na da kontrolirati na pravilnost tipa. Tak način modularnega programiranja je bil nekoč edino možen in zazo se imanuje tudi zunanji podprogram. Primer takega programa je:

 program scope_external
  implicit none
  real :: a = 10.0, b=20.0
  write(*,*)”Pred klicanjem sub1 a = ”,a,”b = ”,b
  call sub1(a)
  write(*,*)”Po klicanju sub1 a = ”,a,”b = ”,b
end program scope_external

subroutine sub1(x)
  implicit none
  real, intent(in) :: x
  real :: b= 5.0
  b = b + 1
  write(*, *)”Znotraj sub1 x = ”,x,”b = ”,b
return
end subroutine sub1

V primeru je razvidno, da prevajalnik ne testira tipov. Če želimo to doseči (kar je dobra praksa), to dosežemo z ekplicitno navedbo funkcije ali podprograma.

Interni podprogrami

V glavnem programu lahko pišemo tudi interne podprograme, ki jih označimo z "internal" Primer:

 program main
  ...
  call sub1()
  contains
   subroutine sub1()
   ...
   end subroutine sub1
end program main

Rekurzivni podprogrami

Zarani privzetega prenašanja argumentov z referenco morajo rekurzivni podprogrami

  • vsebovati označbo recursive.
  • Rezultati morajo biti označeni z result

Primer rekurzivne funkcije:

 res = factorial(m)
...
recursive function factorial(n) result(nfact)
  implicit none
  integer, intent(in) :: n
  integer :: nfact
  if (n > 0) then
    nfact= n * factorial(n-1)
  else
    nfact= 1
  end if 
end function factorial

Primer rekurzivnega podprograma:

 call factorial(m,res)
...
recursive subroutine factorial(n,result)
integer, intent(in) :: n
integer, intent(inout) :: result
if (n > 0) then
call factorial(n-1,result)
result = result * n! Need to update result
else
result = 1
end if
return
end subroutine factorial

Povzetek

Fortran v vsebuje različne programske enote:

  • Glavni program
  • Procedure: funkcije in podprogrami
  • Moduli

Ob pravilni rabi lahko dobimo dobro struktuirano kodo, ki je zanesljiva, razumljiva in se jo da vzdrževati.