Datové typy

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.

Specifikace přesnosti reálných a komplexních dat

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

typrozsahpřesnost
32bit integer-2147483648..2147483648
32bit reál-1e38..1e386 desetiných míst
64bit reál-1e308..1e30816 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

funkcepopis
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ů

funkcepopis
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

funkcepopis
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

Odvozené typy

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

Dynamické datové typy

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