Kurs FORTRANU | ||
---|---|---|
Předcházející | Další |
Pamět je z hlediska procesoru jen řada bytů a na to aby se stala pamět srozumitelná pro programy musí její obsah interpretovat. Pokud jde o data programu na ty se program dívá prostřednictvím datových typů.
Základní typy dat jsou: integer, real, character, logical, complex.
Celá čísla jsou reprezentována na intelech 32bitovým číslem s rozsahem -2**31..2*31, všechny ostatní procesory už dnes používají 64bitovou representaci celočísleným s rozsahem -2**63..2**63. Často jde překladačí sdělit jestli chceme používat 32 nebo 64 bitovou přesnost jako základní.
Logická data jsou reprezetována stejným typem jako celá čísla. Je věcí překladače jak zakoduje logickou hodnotu .true. a .false.
V numerické praxi je často potřeba specifikovat numerickou přesnost s jakou mají vystupovat čísla ve vyhodnocovaných výrazech. Tu lze zadat jak na základě znalosti vnitřního zobrazení dat na daném počítači tak na základě skutečně udané přesnosti pomocí počtu desetiných míst nebo čísel v exponentu. Obyčejně je délka reálného čísla stejná jako u celého čísla, tj 32bit na intelech. U reálných čísel je ovšem možné definováním typu double precision specifikovat číslo s 2x větším rozsahem. Přehled je vidět v tabulce.
Tabulka 9. Datové typy na Intelech
typ | rozsah | přesnost |
---|---|---|
32bit integer | -2147483648..2147483648 | |
32bit reál | -1e38..1e38 | 6 desetiných míst |
64bit reál | -1e308..1e308 | 16 desetiných míst |
Jak je vidět je při použití různých čísel programů a dat značný zmatek v délkách reprezentujících to či ono. Proto došlo k zavedení tzv. numerických typů (kind) pomocí kterých můžeme udat kind daného čísla. Tyto kindy jsou ovšem implementačně závyslé a je tedy třeba nějak zajistit jejich systémovou nezávyslost. Proto byly zavedeny standarní funkce umožňující přesně specifikovat co chce. Jejich přehled je uveden v tabulce.
Tabulka 10. Funkce typů dat
funkce | popis |
---|---|
selected_int_kind(exp) | vybere takový kind který umožní používat celá čísla v rozsahu -10**exp..10**exp |
selected_real_kind(digit,exp) | vybere takový kind který umožní používat reálná čísla v rozsahu -10**exp..10**exp s přesností na digit míst, exp je nepovinné |
Je ovšem třeba zdůraznit, že si nelze vybírat jakoukoli kombinaci parametrů. Pro daný typ je třeba mít HW podporu.
Pomocí parametrů je možné specifikovat typ a ten používat dále v proramu. To bude vidět v ukázce. Snadno se tak dají programy modifikovat při přenosu na jiný počítač případně z jednoduché do dvojnásobné přesnosti a podobně.
program kindy ! specifikujeme presnost realnych cisel integer, parameter :: Q = selected_real_kind(16,100) real(Q) :: x x = 2.0_Q*atan2(1.0_Q,0.0_Q) ! = 2*atan(1/0) = pi write(*,*) "real kind = ",Q," pi = ",x end program kindy
Ovšem někdy je třeba vědět další informace o datových typech v průběhu výpočtu. Například u numerické derivace je nejpřesnejší volit krok jako druhou odmocninu z počtu platných desetiných míst. Pak se nám mohou hodit fuknce z následující tabulky. Argumenty funkce může být jak konstanta tak proměnná.
Tabulka 11. Specifikcé funkce typů
funkce | popis |
---|---|
digits(x) | počet platných míst |
epsilon(x) | strojové epsilon |
huge(x) | strojové nekonečno |
[min,max]-exponent(x) | exponent |
precision(x) | přesnost |
radix(x) | báze x |
range(x) | rozsah exponentů |
tiny(x) | nejmenší kladné číslo |
Tabulka 12. Manipulace s čísly
funkce | popis |
---|---|
exponent(x) | vraci exponent čísla x |
fraction(x) | desetinná část x |
nearest(x) | nejbližší zobrazitelné číslo u čísla x |
set_exponent(x) | nastaví exponent u čísla x |
spacing(x) | rozdíl mezi nejbližšími čísly |
Příkladem použití těchto funkcí může být například test na rovnost dvou reálných čísel.
program test real :: a,b a = 1.0 b = 2.0**0.0 if( abs(a - b) < epsilon(a) )then write(*,*) "cisla jsou stejna: ",a,b else write(*,*) "cisla nejsou stejna: ",a,b endif end program
Pomocí základních typů umožňuje fortran též definovat odvozené typy. To umožňuje konstrukci vlastních programových knihoven, použití pointerů a podobně.
Vlastní typy se definují pomocí popisu typedef. Slouží k definování strukturovaných dat. Takto nově definovaný typ pak použijeme příkazem type. Na složky typu se dostaneme prostřednictvím operátoru % Celé si to ukážeme v praxi, kdy se pokusíme nadefinovat operace s quaterniony což jsou čtveřice čísel analogických komplexním číslům. Dnes jsou ve fyzice nahrazeny spinory. Napíšeme modul, který definuje jak typ tak základní operace s nimi. Přitom provedeme takzvané přetížení operátorů. Pomocí definice typu můžeme též rozšířit množinu základních operací běžných operátorů. Zároveň můžeme vytvořit vlastní operátor. Překladač pak na základě proměnných typů, které do daného výrazu vstupují určí jaký je skutečný význam daného operátoru.
module quater ! modul umoznujici pouziti kvaternionu v programech ! definice typu type quaternion real :: x1, x2, x3, x4 end type quaternion ! scitani interface operator(+) module procedure addq end interface ! odcitani interface operator(-) module procedure subq end interface ! nasobeni interface operator(*) module procedure mulq end interface contains function addq ( a,b ) ! addq = a + b type (quaternion) :: addq type (quaternion) :: a,b addq = quaternion( a%x1 + b%x1, a%x2 + b%x2, a%x3 + b%x3, a%x4 + b%x4) end function addq function subq ( a,b ) ! subq = a - b type (quaternion) :: subq type (quaternion) :: a,b subq = quaternion( a%x1 - b%x1, a%x2 - b%x2, a%x3 - b%x3, a%x4 - b%x4) end function subq function mulq ( a,b ) ! mulq = a * b type (quaternion) :: mulq type (quaternion) :: a,b mulq = quaternion( a%x1 * b%x4 + a%x4 * b%x1 + a%x2 * b%x3 - a%x3 * b%x2, & a%x2 * b%x4 + a%x4 * b%x2 + a%x3 * b%x1 - a%x1 * b%x3, & a%x3 * b%x4 + a%x4 * b%x3 + a%x1 * b%x2 - a%x2 * b%x1, & -a%x1 * b%x1 - a%x2 * b%x2 - a%x3 * b%x2 + a%x4 * b%x4 ) end function mulq end module program qua use quater type(quaternion) :: a,b,c a = quaternion( 1.0, 1.0, 1.0, 1.0) b = quaternion( 2.0, 3.0, 4.0, 5.0) c = a + b write(*,*) c c = a - b write(*,*) c c = a * b write(*,*) c end
Jinou zajímavou možností je definovat generické funkce. Například potřebujeme mít v knihovně funkci fungující poněkud jinak v závislosti od typu vstupních parametrů.
Module kvadry interface qudra subroutine qudrar(a,b,c,x1,x2) real :: a,b,c,x1,x2 end subroutine subroutine qudrac(a,b,c,x1,x2) complex :: a,b,c,x1,x2 end subroutine end interface quadra contains subroutine qudrar(a,b,c,x1,x2) real :: a,b,c,x1,x2,d d = b**2 - 4.0*a*b if( d > 0 ) then x1 = (-b + sqrt(d))/2.0/a x2 = (-b - sqrt(d))/2.0/a else stop 'nelze resit v oboru realnych cisel' endif end subroutine subroutine qudrac(a,b,c,x1,x2) complex :: a,b,c,x1,x2,d d = b**2 - 4.0*a*b x1 = (-b + sqrt(d))/2.0/a x2 = (-b - sqrt(d))/2.0/a end subroutine end module
Konstrukce odvozených typů umožňuje rovněž použití dynamickách datových stuktur profilujících současné programovací jazyky. pomocí atributů pointer vytvoříme proměnnou která může ukazovat na nějaké místo v paměti a toto místo interpretuje jako specifiovaný datový typ. Na začátku programu ovšem není definováno a tak je jeho hodnota zcela deurčitá. Lze ji definovat pomocí proměnné s atributem target což je uplně normální proměnná která ovšem může sloužit jako cíl pro pointer. Přiřazení se dělá prostřednictvím operátoru =>. Ukážeme si to v praxi. Následující program vytvoří linkovaný seznam. (tohle chce asi trochu víc popsat).
program LinkedList type(node) real :: data type(node), pointer :: next end type node type(node), pointer :: list, current nullify(list) ! initializace listu na nullu allocate(list) ! vytvori pamet pro promenou list%data = 0.0 allocate(list%next) ! alokuje dalsi prvek seznamu list%next%data = list%data + 1.0 nuliffy( list%next%next) current => list do while( associated(current) ) write(*,*) current%data current => current%next enddo end program
Předcházející | Domů | Další |
Čtení tabulek a obrázků | Rozsáhlé projekty: CVS,make,knihovny |