Otevíráte osmý díl seriálu o jazyku Object Pascal pro začátečníky. I zde si odpočineme od nových pojmů z OOP a podruhé se budeme věnovat cyklům, neboli iteracím. Po cyklu for přijde na řadu cyklus while. Časem se ještě můžeme vrátit k třetímu cyklu Pascalu: repeat. Přeji vám pohodu při čtení!
Úvod
Osmý díl seriálu o jazyku Object Pascal rozdělím na tři kapitoly:
- Řešení úloh z minulého dílu.
- Povídání o cyklu while.
- Úkoly k tomuto cyklu.
ad 1) Řešení úloh z minulého dílu
Úkol č. 1
Zadání: Napište program, který spočte součet čísel od 1 do 100. (Úloha zadaná kdysi malému Gaussovi ve škole. Ten si s ní ovšem poradil rychle a bez počítače.)
Řešení: Jde o jednoduché použití cyklu for.
program soucet1az100; {$APPTYPE CONSOLE} uses SysUtils; var soucet, cislo: integer; begin soucet := 0; // pocatecni hodnota promenne for cislo := 1 to 100 do // zde neni strednik, prikaz zde nekonci! soucet := soucet + cislo; writeLn('Soucet cisel od 1 do 100 je ', soucet); writeLn; // prazdny radek writeLn('Pro ukonceni programu stisknete klavesu Enter.'); readLn; // prikaz pro pozastaveni programu end.
Úkol č. 2
Zadání: Napište program, který spočte součet čísel od zadané dolní meze do zadané horní meze. Vstupními hodnotami tedy budou dvě celá čísla, výstupní hodnotou jedno číslo - součet.
Řešení: Jako minule, jen přidáme vstup krajních hodnot.
program soucetNazM; {$APPTYPE CONSOLE} uses SysUtils; var soucet, cislo, dolniMez, horniMez: integer; // deklarace promennych begin soucet := 0; // pocatecni hodnota promenne write('Zadejte dolni mez cisel pro soucet: '); readLn(dolniMez); write('Zadejte holni mez cisel pro soucet: '); readLn(horniMez); for cislo := dolniMez to horniMez do soucet := soucet + cislo; write('Soucet cisel od ', dolniMez, ' do ', horniMez); writeLn(' je: ', soucet); writeLn; // prazdny radek writeLn('Pro ukonceni programu stisknete klavesu Enter.'); readLn; // prikaz pro pozastaveni programu end.
Další úkoly jistě dořešíte sami. Pokud by někdo řešení poslal, rád ho zveřejním.
ad 2) Povídání o cyklu while
Úvod
Připomeňme si, že:
- cykly umožňují opakování jisté části programu - jednoduchého (jednoho) příkazu nebo složeného příkazu (bloku více příkazů),
- v Pascalu jsou pro cyklus tři příkazy: cyklus for, cyklus while a cyklus repeat,
- cyklus for využijeme, pokud předem známe počet opakování (průchodů cyklem). Zbylé dva cykly použijeme, když předem počet opakování cyklu neznáme.
Cyklus while
Cyklus while začíná podmínkou. Příkazy cyklu se provedou jen tehdy, pokud je podmínka splněna (pokud má logický výraz podmínky hodnotu true, ve vývojovém diagramu značíme znaménkem "+"). Nemusíme zadávat žádnou počáteční a konečnou hodnotu (pravděpodobně je ani neznáme). Při každém průchodu cyklem se také nezvyšuje automaticky hodnota nějaké řídicí proměnné (jak se to děje v cyklu for), o to se musíme postarat sami. V podmínce se tedy musí vyskytovat alespoň jedna proměnná a nesmíme zapomenout v příkazech cyklu její hodnotu měnit, jinak by opakování cyklu nikdy neskončilo!
Syntaxe (způsob zápisu) cyklu while
Konkrétní příklady:
1. příklad:
i := 1; while i<=10 do // V podmínce je proměnná, begin // která řídí opakování cyklu. writeLn(i); // Co cyklus provede? // Co v něm chybí? end;
2. příklad:
soucet:=0; while i<=10 do // V podmínce je proměnná, begin // která řídí opakování cyklu. soucet := soucet + i; // Co v cyklu chybí? end; // Co cyklus provede? write(‘ Součet od 1 do ‘); writeLn(i, ‘ je: ‘‚ soucet);
Otázka 1: Promyslete, co každý z těchto cyklů provede a co v nich k požadovanému fungování ještě chybí. (Odpověď je na konci dílu.)
Obecný zápis cyklu while
Cyklus s jednoduchým (jediným) příkazem:
while logická_podmínka do jednoduchy_prikaz;
Cyklus se složeným příkazem (skupinou více příkazů):
while logická_podmínka do begin prikaz_1; prikaz_2; ... prikaz_n; // za posledním příkazem nemusí být středník end;
Znázornění cyklu while vývojovým diagramem
(Jako v minulém dílu jsem možné znázornění cyklu nakreslil v programu Draw z OpenOffice.)
Úkoly k cyklu while
Úkol 1: napište program, který spočte součet čísel od 1 do 100 pomocí cyklu while. Podobný úkol je jistě určen spíš pro cyklus for, ale zkuste to i takto, můžete pak program porovnat s obdobným úkolem z minulého dílu.
Úkol 2: napište program, který rozhodne, jestli zadané číslo je prvočíslo. Nejdřív nakreslete vývojový diagram.
Nápověda: podmínka cyklu while bude zřejmě složena ze dvou podmínek, např. v tomto smyslu: ((zkoumané číslo není dělitelem zadaného čísla) AND (zkoumané číslo nedosáhlo horní meze)). Doporučuji ve složených podmínkách používat raději víc závorek než méně, ať je zaručena správnost fungování podmínky (např. logická spojka AND má v Pascalu značně velkou prioritu).
Připomeňme si, že program, který zjistí, zda zadané číslo je prvočíslem, jsme viděli už ve 2. a 3. dílu (tam bylo řešení), ovšem tam jsme ještě použili jednodušší cyklus for. Program byl ale velmi nevýhodný, jak jsem připsal v poznámce za ním. Řešení pomocí cyklu while už by mělo být efektivnější.
Otázka 2: Doporučuji vrátit se do třetího dílu a promyslet, v čem je nevýhodnost tam uvedeného řešení. Může to být užitečné i pro řešení nové. Odpověď umísťuji opět na konec článku.
Úkol 3: napište program, který najde nejmenší společný násobek dvou zadaných celých čísel. Zkuste sami najít nějaký algoritmus, možností je víc.
Úkol 4: napište program, který najde největší společný dělitel dvou zadaných celých čísel. Opět zkuste sami objevit nějaký algoritmus, nejšikovnější je tzv. Eukleidův, popř. ho zkuste někde vyhledat.
Závěr
Odpovědi na otázky z tohoto dílu
Otázka 1: Promyslete, co každý z těchto cyklů provede a co v nich k požadovanému fungování ještě chybí.
Odpověď: První cyklus vypíše čísla od 1 do 10, druhý tato čísla sečte. Pozor: v obou cyklech chybí příkaz pro zvyšování hodnoty řídící proměnné i, čili příkaz inc(i). Navíc u druhého příkladu chybí nastavení počáteční hodnoty proměnné i před cyklem (i := 1;).
Otázka 2: Program, který zjistí, zda zadané číslo je prvočíslem, jsme viděli už ve 2. a 3. dílu (tam bylo řešení), ovšem tam jsme ještě použili jednodušší cyklus for. Program byl ale velmi nevýhodný, jak jsem připsal v poznámce za ním. Řešení pomocí cyklu while už by mělo být efektivnější. Doporučuji vrátit se do třetího dílu a promyslet, v čem je nevýhodnost tam uvedeného řešení. Může to být užitečné i pro řešení nové.
Odpověď: Nevýhod řešení ve 3. díle bylo víc:
- Především použití cyklu for je zde nevhodné. Např. když je zadané číslo sudé, už první zkoumaný dělitel (číslo 2) je dělitelem čísla a cyklus pokračuje úplně zbytečně. Tuto nevýhodu opraví právě použití cyklu while.
- Dál je nevhodné, že jako horní mez jsme zvolili polovinu ze zadaného čísla. Vždyť pokud by číslo mělo být dělitelné svou polovinou, muselo by být dělitelné i dvěma, což se vyzkouší hned na začátku. Stejně nemá cenu hledat dělitele ani do třetiny ze zadaného čísla (pak by číslo bylo dělitelné i třemi). Pokud věc trochu promyslíte, přijdete na to, že stačí hledat dělitele do odmocniny ze zadaného čísla, v Pascalu je to funkce sqrt(x), pro naši potřebu ještě odřízneme desetinná místa třeba funkcí trunc(sqrt(x)).
- Algoritmus by šel vylepšovat i jinak, zkuste ještě něco vymyslet.
Tento díl dopisuji na začátku ledna. Taky vám je v tento čas trochu smutno z toho, jak rychle utekly Vánoce, že stromeček už je asi v kotelně nebo dávno odvezený od popelnic a že na krásnou vánoční hudbu a na koledy si budeme muset zase rok počkat? Potěšit nás může to, že ve snaze být na sebe hodní a milí, ke které nás Vánoce přirozeně vedou, můžeme pokračovat celý rok. A jestli si chcete vánoční atmosféru připomenout, poslechněte si krásné pořady o Janu Jakubu Rybovi z Toulek českou minulostí Českého rozhlasu. Jsou to díly přímo o České mši vánoční a o Rybově životě. Ryba byl jistě výjimečný a zanechal nám mnoho krásné hudby. Neměl to právě proto v životě hodně těžké? Mějte se pěkně a buďte hodní na výjimečné lidi: i když jsou chytřejší nebo šikovnější než my, potřebují naši pomoc a ne závist a házení klacků pod nohy.