Pravidla programování PMD




Programovací jazyk

Všechny podprogramy, sestavené pro soubor PMD, musí být rozepsány ve standardním FORTRANu 77. Žádné odchylky, nebo rozšíření se nepřipouštějí.
Výjimky byly přijaty jen ve standardních podprogramech pro čtení vstupních údajů, kde se pracuje s integer-ekvivalenty alfanumerických znaků. Tyto ekvivalenty se pro některé počítače liší, potřebné modifikace nejsou rozsáhlé. Modifikace pro různé operační a výpočtové systémy lze nalézt ve zdrojích podle znaku '#' . Ve všech podprogramech PMD se dále používá následující programátorský obrat, který není ve standardu FORTRANu uveden, ale jehož přípustnost je ověřena praxí na všech dostupných počítačích:
předpokládá se, že jsou-li v C0MMON-bloku proměnné zapsány v určitém pořadí, jsou tak uloženy i v paměti. Napíšeme-li tedy:
      DIMENSION ABC(21)
EQUIVALENCE (ABC(1),A(1))
COMMON // A(5), B(7), C(9)
můžeme očekávat, že bude např. B(5) = ABC(10)

Práce s pamětí

Používá se "kvazidynamická" deklarace paměti. Operace ve vnitřní paměti se provádějíve vzájemně ekvivalentních pracovních polích INT (typu integer) a R (typu real), do kterých se potřebná pole proměnných vnořují. Číselné hodnoty dimensí LI a LR polí INT a R, se určí mimo program podle rozsahu řešené úlohy. V programu se uvedou jen v řídícím segmentu (MAIN) ve výroku DIMENSION a dvěma přiřazovacími výroky se zavedou jako proměnné, používané v parametrech dále vyvolávaných podprogramů. Ke změně nároku celého programu na paměť stačí změnit hodnoty LI, LR pouze v těchto místech. Polím proměnných v podprogramech vyvolávaných ze segmentů MAIN se paměť přiděluje dynamicky pomocí parametrů subrutin.
Při stanovení LI, LR je třeba respektovat relaci délky čísla typu real a čísla typu integer na daném stroji, která je vyjádřena číslem ICL, zavedeným na začátku řídícího segmentu. Postup je zřejmý z následujících příkladů. Prakticky se velikost paměti nastavuje pomocí příkazu PARAMETR např. PARAMETER (LI = 3000000) a dále platí LR = LI/2 . Nárok programu na paměť je 4*LI [B].
Tento přístup má však nevýhodu, že uživatel musí po ruce kompilátor pro případné zvětšení paměťového nároku úlohy, či pro případ počítače s měnší velikostí operační paměti. Proto bylo použito dynamické alokace funkcí MALLOC podle nároků provozovaného programu. Protože funkce MALLOC není standardní pro všechny kompilátory, byly vytvořeny nové hlavní programy s názvem zakončeným písmenem 'A' (např. RMD3 -> RMD3A). Program nejprve přečte COMMON a spočte požadovanou délku LI, kterou pak alokuje funkcí MALLOC.
Vyjímku tvoří programy zpracování sítě a okrajových podmínek, kde načátku nelze maximální požadovanou délku LI určit. Tyto programy jsou zkompilovány s vhodnou délkou LI. Pokud program skončí s chybou o nedostatečné velikosti LI, musí se program spustit s parametrem před jménem úlohy -MLI 10000000 nebo -M 40, kde v prvním případě se jedná o po6adovanou velikost LI  a v druhém případě přímo o velikost paměti v [MB].


Příklad 1
Na počítači nechť real zabírá dvojnásobek paměti pro integer, čili ICL = 2. Máme deklarovat paměť pro úlohu, která potřebuje LI = 10000 integerů. Do pole INT má adresy LBINE máme vnořit pole INE délky LINE a do pole R od LBRPD pole RPD délky LRPD. Bude:
      DIMESION INT (10000), R (5000), ...
COMMON /CPMD/ .....ICL, ...LINE, ..LRPD, ....
EQUIVALENCE (INT(1),R(1)0,. . .
.
.
ICL = 2
.
.
LI = 10000
.
.
LR = LI/ICL
.
.
CALL PROBD (INT,LI,R,LR)
·
.
(PROBD m.j., určí délky LINE,LRPD a uloží je do /CPMD/
.
CALL SCMD (INT,LI,R,LR,.....LBINE,...LBRPD,...)
(SCMD m.j. určí indexy LBINE a LBRPD)
.
.
CALL SUBRl(INT,LI,R,IR,INT(LBINE),LINE,R(LBRPD),LRPD,..)
.
.
END
.
.
SUBROUTINE SUBRl (INT,'LT,R,LR,INE,LI1~E,RPD,IR,PD,.....)
.
.
DIMENSION INT(LI),R(LR),INE(LINE),RPD,LRPD),...
.
.
END

Příklad 2Na místě pole INE z příkladu 1. chceme umístit real- pole T. Adresa začátku pole T, vnořeného do R bude:
      LBT = (LBINE - 1) / ICL + 1
M-tý prvek pole T má v R adresu LBT - I + M .

Příklad 3
Na místě real-pole RPD z příkladu l umístit integer-pole ICD.
Adresa začátku pole ICD bude:
      LBICD = (LBRPD - l) * ICL + 1

N-tý prvek pole ICD má v INT adresu LBICD - 1 + N a vyjádří se jako INT(LBICD - 1 + N) .

Přenos informace mezi subroutinami a programy

Ve FORTRANu lze informaci mezi subroutinami a podprogramy přenášet jen pomocí jejich parametrů, nebo prostřednictvím COMMON-bloku. Přenos pomocí parametrů je poněkud pomalejší. Velký počet parametrů u rozsáhlých subroutin bývá zdrojem chyb, které nejsou některými kompilátory testovány. Přenos prostřednictvím COMMONu má závažnou nevýhodu v tom, že při použití převzatého podprogramu není z jeho výpisu jasné, zda jednotlivé v bloku uvedené položky v něm skutečně svými hodnotami již jsou, nebo zde je třeba je tam zavést apod. Pojmenované COMMON-bloky musí podle standardu mít ve všech podprogramech programu stejnou délku, což je také nepohodlné. Různou délku smí mít jen nepojmenovaný COMMON //. Proto se v poslední době na některých pracovištích dává přednost přenosu informace výhradně pomocí parametrů subroutin. Při jejich vhodné organizaci je tím zaručena dokonalá kompatibilita subroutin při zachování jejich nezávislosti. Je jasné, co do subroutiny vstupuje a co z ní vystupuje.
Úplné opuštění COMMONU se nám nicméně nezdá správné. Pro PMD navrhujeme přenos informace mezi subroutinami uspořádat tak, aby bylý plně využity výhody obou možností přenosu při potlačení jejich nedostatků.

Přenos informace pomocí COMMON-bloku /CPMD/

V celém PMD se bude používat jediný pojmenovaný COMMON-blok /CPMD/ , který může být zařazen do každé subroutiny. Má tyto vlastnosti:

Přenos informace pomocí parametrů subroutin

Parametry subroutin se předně používají ke sdílení paměti, viz zde a dále k přenosu hodnot proměnných. Protože v PMD dáváme přednost krátkým subroutinám, je možné udržet počet jejich parametrů v rozumných mezích. Pro složité úkony se konstruují podprogramy-bloky, které jen vyvolávají podprogramy nižší úrovně pro dílčí úkony. Blok si obyčejně provádí rozvrh paměti sám nebo používá standardní rozvrh, jehož parametry bere z /CPMD/, takže má zpravidla jen parametry INT,LI,R,LR.
Aby bylo zřejmé, které parametry jsou vstupní a které výstupní, zavádí se tato úprava parametrů:

Příklad 4
      SUBROUTINE SUBRR(INI,LI,R,LR,INE,LLIINE,AS,BS,LAB,H,LH)
DIMENSION INT(LI),R(LR),INE(LLINE),AB(LAB),BS(LAB),H(LH)
COMMON /CPMD/ . . . . LINE . . . . .


Přenos informace mezi programy

Základní parametry úlohy se přenášejí pomocí COMMONu /CPMD/ - viz zde , který se dumpuje na periferii č. IDCOM. Pro přenos rozsáhlých souborů údajů mezi programy se používají sekvenční soubory ve vnější paměti, tj. na disku nebo dříve na magnetické pásce. Jejich čísla se povinně zavádějí v řídících segmentech programů a ukládají se do /CPMD/, s nímž se í dumpují. Jde o položky IDGMI až IDA2. O práci se soubory - viz zde

Detaily programování


Dále uvedené směrnice mají smysl doporučení. Nezbytně nutné je dodržet pouze pravidla přenosu informace mezi podprogramy, zatímco odchylky od pravidel grafické úpravy a značení lze v případech přejatých podprogramů tolerovat.
Podprogramy psané pro PMD musí všem požadavkům směrnic vyhovovat. Docílí se tím čitelnost a srozumitelnost programů, která by měla být jednou z hlavních předností PMD,

Výběr instrukcí

C0MM0N se smí v PMD používat jen s omezením podle odstavce .
EQUIVALENCE - použití se omezuje jen na deklaraci ekvivalence polí INT a R v řídícím segmentu programu a k přidělování významu položkám polí v /CPMD/. Zásadně se nesmí používat k "překřtívání" proměnných v průběhu subroutiny.
ARITMETICKÝ IF, tj. např. IF(A-B)100,200,300 se nedoporučuje. Odporuje přehlednému strukturovaní programu, vede k zvětšení počtu návěští a GO TO. Nahrazuje se logickým IF.
LOGICKÝ IF se používá vždy ve stejné úpravě jako "struktura"; záleží přitom na počtu testovaných okolností, počtu následků a na tom, chceme-li zařadit vysvětlivky. Mohou nastat případy:
POČÍTANÝ GO TO se pro přehlednost upravuje jednotně takto:
     GO TO (10,20,30,40, . . . ),ITYP
C
C ITYP=1 ~ JEDNOROZMERNY PRVEK
10 vztahy
GO TO 90
C
C ITYP=2 - CTYRUHELNIK PR0 ROVINNE ULOHY
20 vztahy
GO TO 90
C ITYP=3 - KOMPAKTNI PRVEK PRO 3D - ULOHY
30 vztahy
GO TO 90
.
.
.
GO TO 90
C END CTGO
.
.
DO - CYKL - dříve se doporučovalo rozepisování cyklů. Při použití dnes již běžných optimalizujících kompilátorů to však nepřináší podstatné zrychlení výpočtu a naopak to prodlužuje program a znesnadňuje ladění. Rozepisování cyklů je výhodné jen pokud:
Ve většině případů je tedy lépe použít nerozepsaný DO-cykl. Úprava pro oba případy je zřejmá z následujícího příkladu

Příklad 5
Máme ve stylu PMD přepsat rozepsaně i nerozepsaně cyklus,který by " postaru " byl zapsán takto:
      DO 5,I=1,N
DO 5,J=1,3
5 A(J)=A(J)+ X(I)*B(J)
Nerozepsaný přepis ve stylu PMD je:
      DO 1000 I=1,N
XI = X(I)
DO 2000 J=1,3
A(J) = A(J) + XI * B(J)
2000 OONTINUE
1000 CONTINUE

Rozepsaný přepis:
      EQUIVALENCE (A(1),A1),(B(1),B1),(A(2),A2),(B(2),B2),
1 (A(3),A3),(B(3),B3)
.
.
DO l000 I=1,N
XI = X(I)
A1 = A1 + XI*B1
A2 = A2 + XI*B2
A3 = A3 + XI*B3
1000 CONTINUE
.
.

Zacházení s maticeni a poli proměnných

Ze čtvercové souměrné matice se pracuje jen s její horní trojúhelníkovou částí (včetně hlavní diagonály), linearizovanou po sloupcích. Matice řádu N je tedy uložena jako vektor o délce N*(N+1)/2 :

A11 Al2 A13
A21 A22 A23 ---> A11 A12 A22 A13 A 23 A33
A31 A32 A33

Člen A(I,J) matice má v tomto vektoru pořadí J*(J-1)/2+I .
Obdélníkové matice se interpretují obvyklým způsobem jako dvourozměrné pole A(I,J). Jejich linearizace doporučená v l. versi pravidel programování, program komplikuje a nepřináší očekávané urychlení výpočtu.
Jiná situace je u vícerozměrných polí, která nejsou zcela zaplněna. Jako příklad uveďme standardní pole INET, ve kterém jsou postupně pro všechny prvky zařazena čísla jejich uzlů. Kdyby bylo zavedeno jako pole dvojrozměrné INET(IE,JH), mělo by dimenze NELEM, NNEX(tj. max. počet uzlů prvku v dané síti). To by mohlo v síti s prvky s rozdílnými počty uzlů na prvek vést k plýtvání vnitřní paměti. Proto se pole INE bere jako jednorozměrné pole, ve kterém je pro každý prvek uloženo jen tolik čísel uzlů, kolik jich prvek má. To ovšem na druhé straně znesnadňuje výběr z tohoto pole a proto se sestavuje další pomocné pole NNET(IE) dimense LNNET, ve kterém je pro každý prvek uložen počet jeho uzlů. Pole INE se vždy probírá s pomocí pole NNET od začátku.

Volba jmen

Jména proměnných se volí mnemotechnicky, přičemž se vychází z anglického názvu nebo z obecně užívaného symbolu (napětí SIG apod.). Jméno proměnné smí mít max. 6 znaků a musí začínat písmenem. Následně se užívá implicitní deklarace typu. Názvy proměnných typu integer musí začínat na I, J, K, L, M, N, přičemž začínají písmenem:
Jména podprogramů smí mít max. 5 znaků.
Jména programů smí mít jen 4 znaky. obvykle se volí zkratka anglického názvu řešeného problému.

Volba návěští

Návěstí se volí jednotně. Rozlišují se podle druhu instrukcí,každému druhu je přiděleno určité rozmezí návěstí. V každé subroutině se návěští číslují od začátku příslušného rozmezí. Návěstí se doráží na 5. sloupec, aby uvnitř subroutiny v 1. sloupci byla jen písmena C od poznámek, které tím lépe opticky vyniknou. Návěští instrukcí téhož typu musí uvnitř subroutiny vzrůstat monotónně. Proto je vhodné,při psaní podprogramu postupovat v návěstí např. po desítkách, aby se pravidlo o růstu návěští neporušilo při pozdějším vsouvání dalších návěstí při opravách.
Návěstí se volí:

Grafická úprava

Vysvětlivky (comments) mají usnadnit orientaci v programu a jeho pochopení v místech, kde nestačí k porozumění znalost pravidel a zvyklosti PMD a řešené problematiky.
Na začátku programu i podprogramu se v rámečku končícím v 70. sloupci uvede jednotně uspořádaná informace, která má obsahovat:
Řádků s vysvětlivkami nesmí být bezprostředně za sebou víc, než 30. Proto se do zarámované informace neuvádí vysvětlení významu vnitřních proměnných podprogramu, které se provede pomocí vysvětlivek uvnitř podprogramu.
Srozumitelnosti a čitelnosti programů velice prospívá členění výpisu na odstavce, oddělované prázdnými řádky a uvedené nadpisem.

Práce s vnější pamětí

Vnější pamětí rozumíme pevné disky (dříve se používali magnetické pásky nebo bubny). Pro ukládání informace se ve vnější paměti zřizují různé diskové soubory , označované v programu předponou ID a příponou souboru na disku - např. IDSOL znamená práci s diskovým souborem uloha.SOL . Symbolická čísla souborů vystupují v /CPMD/. Hodnoty se jim přisuzují v řídících segmentech programů přičemž se v určitém programu přidělují jen čísla souborům v tomto programu nově zavedeným. Čísla souborů jimiž se informace přenáší z programů předcházejících, se přenášejí prostřednictvím /CPMD/. Zápis i čtení se provádí většinou sekvenčně. Z toho vyplývají tyto zásady práce s vnější pamětí:
Vyjímku tvoří přímopřístupové soubory IDEQ1,  IDEQ2,  IDEQN (frontální řešič), IDPLA(napětí v Gaussových bodech), kde se čtení nemusí provádět sekvenčně a záznamy lze přepisovat (prvotní zápis se samozřejmě vytváří sekvenčně). Délka všech záznamů však musí  být stejná. Pro práci s přímopřístupovými soubory se používají tyto podprogramy:
 

Příklad 6
Do periferie č. IDIS bylo pěti výroky zapsáno postupně 5 polí IPOL1 až IPOL5. Chceme-li nyní přečíst 3. záznam tj. pole IPOL3, musíme psát:
      BACKSPACE IDIS
BACKSPACE IDIS
BACKSPACE IDIS
READ(IDIS) IPOL3
nebo
REWIND IDIS
READ(IDIS)
READ(IDIS)
READ(IDIS) IPOL3
-zapisovat lze jen v pokračujícím směru vpřed. Jestliže bychom v předešlém příkladě 6 po zapsání všech pěti polí provedli:
      REWIND IDIS
WRITE(IDIS) IPOLE
bude vše, co bylo na periferii IDIS zapsáno za záznamem IPOLE , ztraceno, i když by pole IPOL bylo stejně dlouhé jako IPOL1.