Urychlovací úpravy BASICových programů

Radek Štěrba, RASTER

V dnešní části bych se rád věnoval drobné skutečnosti, která může velice ovlivnit rychlost vašeho BASIC programu.

Možná jste si už někdy všimli, že čím je BASICový program delší, tím pomaleji běží. Rychlost ale nezávisí přímo na délce programu, ale na tom, jak daleko od začátku je místo, které právě používáme. Přesnější vysvětlení ukážu na příkladu:

100 PRINT "AHOJ"
110 GOTO 100

Tento prográmek poběží celkem rychle...

Zkuste ho ale takto zmodifikovat:

1 REM
2 REM
3 REM
4 REM
5 REM
...
99 REM
100 PRINT "AHOJ"
110 GOTO 100

Zdánlivě úplně stejný program, ale v druhém případě poběží pomaleji. Proč?

Programovací jazyk BASIC je interpret - ale to jste již jistě mnohokrát slyšeli. Proto vlastní program není přímo ve strojových instrukcích, ale skládá se z čísel, která určují funkce které mají být prováděny. Součástí BASICu je i to, že před každým příkazem (nebo skupinou příkazů) je číslo řádku, abychom mohli stanovit pořadí, v jakém budou prováděny. A teď tedy zpět k problému s rychlostí a její závislosti...

V prvním případě je nalezen jako první řádek číslo 100, je "přeložen" a proveden. Pak jde program na další řádek. Ten "přeloží" a provede... a právě teď jsme u jádra věci, přesněji řečeno u příkazu GOTO 100. V tomto okamžiku BASIC hledá od začátku BASICového programu řádek s číslem 100. Protože je to hned první řádek v programu, nalezne ho celkem rychle.

V druhém případě je situace obdobná. Nejprve jsou postupně nalezeny řádky 1 až 99, každý z nich je vždy "přeložen" a proveden (příkaz REM označuje poznámku, takže navenek se nic neděje). Vznikne tím sice jisté zdržení, ale tyto řádky jsou mimo náš nekonečný cyklus. Přesto se však jejich existence na rychlosti projeví. Řádek 100 je přeložen a proveden také stejně jako v prvním případě. Na řádku 110 je GOTO 100. Nyní BASIC začne od začátku prohledávat program dokud nenalezne řádek s číslem 100. Najde řádek 1 (a to není 100), pak najde řádek 2 (to taky není 100), 3, 4, .. , 99 (taky ne) a až nyní našel řádek 100. I když jednotlivé řádky nebudou vůbec překládány, na rychlosti se to projeví...

Obdobné je chování u příkazů FOR .. NEXT, RESTORE .. READ, GOSUB .. RETURN, .. prostě vždycky, když se pracuje s číslem nějakého řádku.

(Upřesnění: Možná Vás překvapilo, že mezi těmito příkazy je i FOR .. NEXT a RETURN, ale uvědomte si, že narazí-li program na NEXT, vrací se na FOR podle zapamatovaného čísla řádku, na kterém příslušející FOR byl. Takže i FOR a NEXT nepřímo pracuje s čísly řádků. Obdobné je to i u příkazu RETURN a u dalších.)

A co s tím?...

Asi vás moc nepotěším... Žádná snadná pomoc neexistuje.

Jediným, čím můžete aspoň trochu zrychlit svůj program je umisťováním náročných částí co nejblíže k začátku programu. Nemyslím tím použít co nejnižší čísla řádků - s tím to vůbec nesouvisí!! Blízkostí zde myslím to, aby před touto částí bylo co nejméně řádků (bez ohledu na jejich čísla).

Př.
Máte program, který má 500 řádků (čísla 10 až 5000 s krokem 10).

10 ...
20 ...
...

Od řádku 5010 je často používaná rutina (kterou voláte z několika míst povelem GOSUB 5010), která například sčítá čísla v nějakém poli:

5010 SOUCET=0
5020 FOR X=1 TO 20
5030 SOUCET=SOUCET+POLE(X)
5040 NEXT X
5050 RETURN

Pak následující změnou běh této rutiny (a tím i celého programu) podstatně urychlíte:

1 GOTO 10
5 SOUCET=0:FOR X=1 TO 20: SOUCET=SOUCET+POLE(X):NEXT X:RETURN
10 ... 
20 ...
...

Nezapomeňte, že nyní je ještě třeba změnit všechna volání GOSUB 5010 na GOSUB 5.

Shrnutí:
Čím méně řádků váš BASICový program má, tím rychleji jsou prováděny příkazy pracující s čísly řádků (GOTO, GOSUB, FOR .. NEXT, ...), protože každý programový řádek je hledán od začátku celého BASIC programu. Pokud vám tedy jde o rychlost víc než o přehlednost, umisťujte na každý řádek co nejvíce příkazů. Tím snížíte celkový počet řádků a urychlíte práci BASICu při hledání řádku s daným číslem. Často používané části programu umisťujte co nejblíže k "začátku" programu a málo používané části (nebo ty, ve kterých Vám nejde o rychlost) až za ně. Nejlepší je tyto "totálně" znepřehledňující úpravy provádět až v hotovém programu a nechat si schovanou i původní verzi.

Abyste si mohli udělat představu, o jakých časových úsporách zde hovořím, zkuste si spustit (pod čistým BASICem!!! - viz. dále) přiložené testovací prográmky:

TEST1A.BAS ..ukazuje dobu běhu části programu pracujícího "na konci LISTingu".

TEST1B.BAS ..ukazuje stejnou část umístěnou hned "na začátku".

TEST2A.BAS ..ukazuje čas nutný pro provedení programu, který mnohokrát volá podprogram umístěný "na koci LISTingu".

TEST2B.BAS ..ukazuje čas stejného programu, když je podprogram přemístěn na jeden řádek a co nejvíce "na začátek".

Důležitá poznámka na závěr:
Doufám, že jste si všimli, že se celý článek věnuje "čistému" BASICu. Co se týče TURBOBASICu, tam je situace trochu jiná, protože TBASIC má některé vnitřní rutiny oproti BASICu vylepšeny. Rutina pro hledání řádku s daným číslem je mnohem rychlejší, takže skutečnosti, o kterých se v tomto článku zmiňuji, se v TBASICu téměř neprojeví.