Přeskočit na obsah

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