Moduly
Moduly jsou programy které nemohou existovat samostatně. Moduly jsou nesmírně užitečné pro zapouzdření proměnných a procedur a umožňují nám kontrolovat, které procedury jsou mimo modul viditelné atd. Jsou důležité pro rozdělení kódu podle pravidla: Každá část kódu se stará jen o jednu věc. To vede k lepší přehlednosti, znovupoužitelnosti atd.
Mnoho modulů lze získat na internetu, např. https://github.com/search?q=fortran či jinde.
Příkaz module
Příkaz použiváme místo příkazu program
. Deklarujeme v něm proměnné, vkládáme implicit none
a procedury píšeme za contains
. Modul píšem mimo program
. Máme dvě možnosti buď modul pišeme do stejného souboru nebo do jiného souboru. V případě, že píšeme modul do jiného souboru musíme nejdříve zkompilovat soubor s modulem a potom při kompilaci hlavního programu vložit adresu ke zkompilovanému modulu. Kompilace pro kompilátory gfortran a ifort může mít dvě podoby:
gfortran hlavniProgram.f95 modul1.f95
./a.out
popř.
ifort hlavniProgram.f95 modul1.f95
./a.out
nebo
gfortran -c modul1.f95
gfortran hlavniProgram.f95 modul1.o
./a.out
popř.
ifort -c modul1.f95
ifort hlavniProgram.f95 modul1.o
./a.out
V prvním případě hlavní program “vidí” modul, protože se kompilují zároveň. V druhém případě získáme nejdříve zkompilovaný modul (modul1.o), který spojíme s hlavním programem až při jeho kompilaci. Příkazem ./a.out spouštíme programy.
Modul používáme v programu tak, že okamžitě za příkaz program _jmenoProgramu_
vkládáme use _nazevModulu_
. Modul můžeme samozřejmě vkládat také do jiného modulu.
module module_1
implicit none
real, parameter :: pi = 4.*atan(1.) ! Ludolfovo číslo
contains
!------------------------------
! prevede stupne na radiany
real function stupne_na_radiany(stupne)
real :: stupne
stupne_na_radiany = stupne * pi / 180.0
end function
!------------------------------
! prevede radiany na stupne
real function radiany_na_stupne(radiany)
real :: radiany
radiany_na_stupne = radiany * 180.0 / pi
end function
end module
!==================================================
program priklad_40
use module_1
implicit none
write(*,*) pi
write(*,*)
write(*,*) stupne_na_radiany(45.)
write(*,*) radiany_na_stupne(pi * 0.25)
write(*,*)
write(*,*) stupne_na_radiany(radiany_na_stupne(pi))
end program
Specifikace public
a private
Uvnitř modulu můžeme proměnným přidělit specifikace ,public ::
a ,private ::
. Těmi můžeme určit, které proměnné budou veřejně (public
) a tedy přístupné z hlavního programu a které nepůjdou číst ani přepisovat (private
) z hlavního programu. Specifikace můžeme použít dvěma ekvivalentními způsoby.
real, public :: a, b
real, private :: x, y
nebo
real :: a, b, x, y
public :: a, b
private :: x, y
Jako privátní nebo veřejné můžeme mít i procedury.
Výchozí nastavení je pro všechny proměnné a procedury public
. Pokud ovšem napíšeme v modulu samostatný příkaz private
stane se výchozím stavem. To znamená, že pokud neřekneme, jinak nebude proměnná či procedura viditelná v hlavním programu.
Skrýt některé proměnné nebo procedury je výhodné, když chceme zabespečit některou proměnnou či proceduru, která je důležitá pro funkce modulu, ale pro hlavní program neužitečné apod.
module module_2
implicit none
private
public :: kombinacni_cislo
contains
!------------------------------
integer function kombinacni_cislo(n,k) result(kc) !spocita n nad k
integer :: n,k
if(n >= k .and. k >= 0) then
kc = faktorial(n) / (faktorial(k) * faktorial(n-k))
else
kc = 0
end if
end function
!------------------------------
! tato funkce je jen pomocna neni nutne aby o ni hlavni program vedel
recursive function faktorial(x) result(y)
integer :: x
integer :: y
if(x == 1) then
y = 1
else
y = x * faktorial(x - 1)
end if
end function
end module
!==================================================
program priklad_41
use module_2
implicit none
write(*,*) kombinacni_cislo(5,2)
!write(*,*) faktorial(5) ! nelze pouzit
end program
module module_3
implicit none
private
integer :: nm1 = 0.0 ! tyto promenne jsou dulezite pro vypocet bylo by nezadouci
integer :: nm2 = 1.0 ! aby je bylo mozne prepsat z hlavniho programu
public fibonacci
contains
!------------------------------
integer function fibonacci()
fibonacci = nm2
nm2 = nm2 + nm1
nm1 = fibonacci
end function
end module
!==================================================
program priklad_42
use module_3
implicit none
write(*,*) fibonacci() ! 1
write(*,*) fibonacci() ! 1
write(*,*) fibonacci() ! 2
write(*,*) fibonacci() ! 3
write(*,*) fibonacci() ! 5
write(*,*) fibonacci() ! 8
write(*,*) fibonacci() ! 13
write(*,*) fibonacci() ! 21
end program
příkaz use
blíže
Někdy se může hodit používat proceduru v hlavním programu pod jiným názvem než jak ji definujeme v modulu. Například kvůli kolizi názvů apod. Pro takový případ můžeme použít operátor =>
.
use mujModul, noveJmenoProcedury => jmenoProceduryVModulu
Přetížení procedur v modulu Expertní - nepovinné
Díky specifikacím private
a public
můžeme přetížit procedury mnohem lepším způsobem než doposud. Zkrátka, z procedur které budou vystupovat pod názvem přetížené procedury uděláme privátní procedury a z přetížené veřejnou.
module module_5
implicit none
private
public :: kvadrat
interface kvadrat
procedure :: kvadrat_integer, kvadrat_real
end interface
contains
!------------------------------------------
function kvadrat_integer(x)
implicit none
integer :: x
real :: kvadrat_integer
kvadrat_integer = real(x)**2
end function
!------------------------------------------
function kvadrat_real(x)
implicit none
real :: x, kvadrat_real
kvadrat_real = x**2
end function
end module
!==================================================
program priklad_44
use module_5
implicit none
write(*,*) kvadrat(1.)
end program