Kurs FORTRANU | ||
---|---|---|
Předcházející | Další |
Řešení komplikovaného problému lze často zjednodužšit jeho rozdělením na několik podproblémů, které lze vyřešit snáze. V programovacích jazycích tomu odpovídá dělení celého programu na podprogramy které jsou víceméně nezávislé na sobě navzájem. Složením několika podprogramů z určité oblasti pak můžeme konstruovat celé programové knihovny.
Ve fortranu existují tři typy programových jednotek:
Je nejvyšší v hierarchii, začíná slovem program, v programu může být jen jedinný, všechny proměnné které program obsahuje jsou lokální, tj. nejsou známy žádné jiné programové jednotce
Podprogram je volán hlavním programem nebo jinou funkcí či podprogramem, případně sebou samým. Proměné jsou lokální. Podprogram nevrací žádnou návratovou hodnotu a se svým okolím může komunikovat výhradne prostřednictvím parametrů.
Funkce je volána hlavním programem, jinou funkci nebo prodprogramem nebo sebou sama. Proměnné jsou lokální. Funkce musí vracet návratovou hodnotu ale může měnit i svoje parametry.
Obecně je vhodné psát samostatné programové jednotky do samostatných souborů na disku a případě i samostatně překládat. Proto je nevhodné používat něco jako globální proměnné, které navíc komplikují práci ve složitých programech.
Struktura podprogramu nebo funkce je podobná jako u hlavního programu, začíná deklaracemi lokalních proměnných po kterých následuje vlastní kód.
Podprogram začíná slovem subroutine za nímž následuje jeho název a seznam parametrů. Končí slovem end subroutine. Parametry slouží na učení typu proměnných a na jejich případné přejmenování. Extrémě důležité je přesně dodržovat pořadí a typy parametrů jinak dostaneme zcela nesmyslné výsledky. Podprogram se z jiné programové jednotky volá příkazem call Typický příklad zápisu podprogramu je zde:
subroutine podprogram(a,b,x,i) real :: a,b,x integer :: i if( i == 666 ) return write(*,*) "Predane parametry:",a,b,x,i x = x + 1 end subroutine
Funkce je uvozena slovem function před kterým ovšem může stát definice typu. Pokud ne, mělo by být někde v definicích funkce řečeno jakého typu je návratová hodnota funkce. Dále následují parametry podobně jako v prípadě podprogramu. Někde ve těle funkce by měla být do funce přiřazena návratová hodnota. Příklad:
function funkce(i,x) ! result(y) real :: x,funkce integer :: i ! real :: y if( i == 666 ) then funkce = 0.0 ! y = x + 1.0 return endif write(*,*) "Predane parametry:",x,i funkce = x + 1.0 ! y = x + 1.0 end function
V příkladu je v komentářích uvedena alternativní metoda návratové hodnoty. Je zapoznámkována nová lokální proměnná jejích přiřazená hodnota se předa volajícímu programu uvedením slova result. V takovém případě ovšem nesmí být název funkce natypován.
Jako příklad užití spolupráce funkcí a programu zde máme
Program Main real :: x,funkce integer :: i ! volani podprogramu call podprogram(2.0,3.0,x,0) write(*,*) "x po navratu z podprogramu = ",x ! volani funkce write(*,*) "vysledek funkce = ",funkce(1,x) end
Rekurse, tj, volání podprogramu samo sebou se musí překladači explicitně sdělit uvedením slova recursive před názvem (recursive subroutine, recursive function). K použití rekurse se (možná) dostaneme později.
Jak již bylo řečeno programové jednotky jsou samostatné, takže se dají například samostaně překládat f90 -c podprogram.f90 s parametrem -c značícím pouze překlad. Tento příkaz vytvoří soubor podprogram.o. S ten pak můžeme dak se spustitelnému souboru a vytvořit program např. f90 podprogram.o program.f90nebo knihovnu (viz dále).
Protože je předávání parametrů mezi programovými jednotkami dost obtížná tak i poměrně omezená věc, byly zavedny tzv. moduly. To jsou programové jednotky vyššího řádu sloužící k větší intergraci samostatných jednotek. Mají následující strukturu:
Module modul ! definice typu, promennych contains ! funkce, podprogramy, bud uvedene jejich kody nebo inkludnute end module
V první části, která je veřejná, můžeme definovat vlastní typy, nastavit konstatny, proměnné pro celý program a pod. Vše co nemá atribut private je veřejné.
V druhé části jsou pak uvedeny zdrojové kódy procedur a programů. Příkazem include 'funkce.f90' můžeme vložit zdrojový text z jiného souboru.
Tato konstrukce slouží jednak ke sdílení společných veřejných proměnných různým jednotkam a jednak ke kontrole předávaných parametrů procedur již překladačem. Sdílení proměnných se budeme věnovat příšte.
Použití modulů je jednoduché, hned na začátku jednotky která jej bude používat se dá příkaz use 'nejakymodul' a program se přeloží následujícím způsobem: f90 modul.f90 program.f90
Teď se zaměříme na zcela funkční a elegantní přepsání procedur na hledání kořenů rovnic, kterým jsme se už věnovali. Předním jsme totiž museli hledat kořen pouze určité funkce a ne takové, kterou by jsme si definovali sami. Použití funcí ovšem tento problém zcela elegantně řeší. Uvedeme dvě řešení, obě mají své výhody a nevýhody (jaké?).
Na ukázku si vezmeme newtonovu metodu (je kratší). Napíšeme funkci do samostaného souboru. V tomto případě musíme vytvořit podprogram který ma jako parametry počáteční odhad, funkci a konvergenční parametry. Zde je.
subroutine newton(f,df,x,fx,maxn,tol) ! poprogram resi rovnici f(x) = 0 newtonovou metodou, ! ! na vstupu ma funkci f(x), funci df(x) pocitajici jeji derivace, ! pocatecni odhad, povoleny pocet vycisleni funce a prenost ! ! na vystupu je v promenne x ulozen hledany koren integer :: i,maxn real :: x,f1,tol,x0 ! vnejsi funkce musi byt oznaceny specifikatorem external aby prekladac ! poznal, ze jde o funkci real, external :: f,df x0 = x + 2.0*tol do i = 1, maxn ! vypocet funkce fx = f(x) ! vypocet derivace f1 = df(x) ! vypocet noveho odhadu korene if( f1 /= 0.0 ) then x = x - f/f1 else stop 'Nulova derivace' endif ! vypis aktualniho korene write(*,*) "iterace = ",i," funkce = ",fx," derivace = ", f1, & " odhad korene = ",x, ! testy na ukonceni if( abs(x-x0) < tol ) exit ! uchovani korene x0 = x enddo end subroutine
Zde je příklad v modulu. Předávané funkce jsou zde navíc přesněji specifikovány, jak procedura předpokládá, že budou volané.
Module Rovnice contains subroutine newton(f,df,x,fx,maxn,tol) ! poprogram resi rovnici f(x) = 0 newtonovou metodou, ! ! na vstupu ma funkci f(x), funci df(x) pocitajici jeji derivace, ! pocatecni odhad, povoleny pocet vycisleni funce a prenost ! ! na vystupu je v promenne x ulozen hledany koren interface function f(x) real :: f,x end function f function df(x) real :: df,x end function df end interface integer :: i,maxn real :: x,f1,tol,x0 x0 = x + 2.0*tol do i = 1, maxn ! vypocet funkce fx = f(x) ! vypocet derivace f1 = df(x) ! vypocet noveho odhadu korene if( f1 /= 0.0 ) then x = x - f/f1 else stop 'Nulova derivace' endif ! vypis aktualniho korene write(*,*) "iterace = ",i," funkce = ",fx," derivace = ", f1, & " odhad korene = ",x, ! testy na ukonceni if( abs(x-x0) < tol ) exit ! uchovani korene x0 = x enddo end subroutine end module
Tento modul pak z hlavního programu použijeme následovně.
program Newton ! program resi rovnici cos(x) = 0 newtonovou metodou use Rovnice integer :: i,maxn real :: x,fx,f1,tol ! zadani pocatecniho odhadu minima, napr. z pulek x = 1.5 ! maximalni pocet opakovani maxn = 100 ! hledana presnost vypoctu tol = 1e-5 call newton(f,df,x,fx,maxn,tol) ! vypis vysledku write(*,*) "pocet iteraci = ",i write(*,*) "hledany koren = ",x write(*,*) "hodnota funkce = ",fx end function f(x) real :: f,x f = cos(x) end function function df(x) real :: df,x df = -sin(x) end function
Předcházející | Domů | Další |
Řízení toku programu | Vstup/Vystup |