|
5. While cyklus |
|
|
|
- Motto: Každý algoritmus lze popsat pomocí
posloupnosti příkazů, větvení a cyklu s testováním před
tělem cyklu. Dijkstra 1958.
- Bez cyklu – každý příkaz se provede nejvýše jednou
S cyklem – každý příkaz uvnitř cyklu se provede nejvýše N-krát
- Důsledek pro programátora: Nechápu-li možnosti cyklu, pak doba
potřebná k vytvoření programu je nejen vyšší než doba výpočtu, ale
i vyšší než užitek z něj.
- Cyklus má svůj začátek – while logická_podmínka
Cyklus má svůj konec – end
Cyklus má své tělo – libovolné příkazy mezi while a end
Příkazem return – v těle větvení můžeme realizovat předčasný únik
z funkce
Existují i jiné příkazy pro předčasné ukončení cyklu, ale
kazí programátorský styl
- Obecná syntaxe:
|
|
|
while logická_podmínka
% tělo_cyklu
end
|
|
|
- Dijkstrův systém:
V posloupnosti příkazů mohou být větvení (několik) nebo cykly.
Uvnitř větvení může být posloupnost příkazů, cyklus nebo jiné větvení.
Uvnitř cyklu může být posloupnost příkazů, větvení (jedno) nebo jiný cyklus.
- Příklad cyklu ze života:
|
|
|
zalez_do_postele;
while unaven
zdrimni_si;
end
vylez_z_postele;
|
|
|
- Příklad cyklu uvnitř větvení:
|
|
|
if unaven
zalez_do_postele;
while unaven
zdrimni_si;
end
vylez_z_postele;
end
|
|
|
- Příklad větvení uvnitř cyklu:
|
|
|
jdi_do_prace;
while cas<16.00
if nekdo_jde_kolem
predstirej_praci;
else
zdrimni_si;
end
end
jdi_domu;
|
|
|
- Příklad cyklu uvnitř jiného cyklu:
|
|
|
while zijes
while unaven
zdrimni_si;
end
servi_nekoho;
end
|
|
|
- Příklad cyklu s počítadlem nesežraných sušenek:
|
|
|
jdi_na_navstevu;
pocet_susenek=29;
while pocet_susenek>0
snez_susenku;
pocet_susenek=pocet_susenek-1;
end
jdi_domu;
|
|
|
- Zvolání: Kdo nepochopil algoritmus s cyklem, ten ho také nekrokoval.
Poznámka 1: Cyklus umožňuje elegantně zobecnit řešení problému.
Poznámka 2: Cyklus umožňuje realizovat hromadné zpracování dat.
Poznámka 3: Elegance znamená co nejmenší počet příkazů, co nejmenší
spotřebu paměti počítače nebo co nejkratší dobu výpočtu – vyberte si.
|
|
|
|
Příklad 5A.1: |
|
|
Sestavte funkci na výpočet největšího společného dělitele dvou přirozených čísel.
Instrukce: Starý řecký matematik Euklides vymyslel elegantní algoritmus,
který pochopíte nejlépe jeho krokováním při různých hodnotách parametrů.
Proč je algoritmus naivní? |
|
|
Řešení: |
|
|
function [nsd]=NaivniNSD(a,b) |
% Naivni realizace nejvetsiho spolecneho delitele dle Euklida |
% [nsd]=NaivniNSD(a,b); |
% nsd ... nejvetsi spolecny delitel |
% a ... prvni prirozene cislo |
% b ... druhe prirozene cislo |
while a~=b |
% pokud se jeste nerovnaji |
if a>b |
% mozna, ze a je vetsi nez b |
a=a-b; |
% zmensi a |
else |
b=b-a; |
% zmensi b |
end |
end |
nsd=a; |
% ted jsou hodnoty a, b stejne a rovne deliteli |
|
|
|
|
Příklad 5A.2: |
|
|
Nastudujte funkce floor, abs a mod pomocí příkazu help a pak si uvědomte,
proč následující funkce není naivní.
|
|
|
Řešení: |
|
|
function [nsd]=NSD(a,b) |
% Efektivni realizace nejvetsiho spolecneho delitele dle Euklida |
% [nsd]=NSD(a,b); |
% nsd ... nejvetsi spolecny delitel |
% a ... prvni prirozene cislo |
% b ... druhe prirozene cislo |
a=floor(abs(a)); |
% proc? |
b=floor(abs(b)); |
% ze stejneho duvodu |
while a>0 & b>0 |
% pokud jsou obe kladna |
if a>b |
% mozna, ze a je vetsi nez b |
a=mod(a,b); |
% rychle zmensi a nahrazenim zbytkem po deleni |
else |
b=mod(b,a); |
% rychle zmensi b nahrazenim zbytkem po deleni |
end |
end |
if a+b==0 |
% co kdyby byly obe hodnoty nulove |
nsd=1; |
% proc? |
else |
nsd=a+b; |
% prave jedno z cisel ma hodnotu nula |
end |
|
|
|
|
Příklad 5A.3: |
|
|
Sestavte funkci pro řešení rovnice x = F(x) metodou prosté iterace, a pak ji
použijte na řešení rovnice x = sin x + x v intervalu od 3 do 4.
Instrukce: Nejprve v klidu a bez cyklu vytvoříme konkrétní funkci
F(x) = sin x + x. Pak se budeme zabývat metodou prosté iterace jako obecným
nástrojem pro řešení rovnice x = F(x). |
|
|
Řešení: |
|
|
function [y]=F(x) |
% pokusna funkce pro prostou iteracni metodu |
% x ... realne cislo |
% y ... x+sin(x) |
y=x+sin(x); |
|
function [x]=ProstaIterace(a,b,x0,nmax,epsilon) |
% Bezpecne reseni rovnice x=F(x) metodou proste iterace |
% [x]=ProstaIterace(a,b,x0,nmax,epsilon); |
% x ... nalezene reseni rovnice |
% a ... dolni mez definicniho oboru F(x) |
% b ... horni mez definicniho oboru F(x) |
% x0 ... pocatecni odhad reseni a<=x<=b |
% nmax ... maximalni pocet vycisleni funkce F(x) |
% epsilon ... tolerance rozdilu mezi levou a pravou stranou rovnice |
% dokud neni duvod k pochybam o metode |
while nmax>0 & x0>=a & x0<=b |
% jeden krok proste iterace a jedno vycisleni funkce F |
x=F(x0); |
nmax=nmax-1; |
% mame o jeden zivot mene |
if abs(x-x0)<epsilon |
% budeme koncit? |
return; |
% hodnota x uz je dobra |
end |
x0=x; |
% "Co bylo, uz neni..." Byron |
end |
x=inf; |
% nenalezeno reseni |
|
|
|
|
Příklad 5A.4: |
|
|
Nastudujte v helpu možnosti funkcí feval a eval. Potom sestavte funkci
pro řešení libovolné rovnice x = F(x) metodou prosté iterace.
Instrukce: Funkci VyresCokoli se zadává jméno funkce jako řetězec v apostrofech.
Pokuste se vyřešit rovnice x = sin x + x nebo x = cos x ve vhodných intervalech.
Krokujte do hloubky s důrazem na provádění funkce feval.
|
|
|
Řešení: |
|
|
function [x]=VyresCokoli(jmenoF,a,b,x0,nmax,epsilon) |
% Obecne reseni rovnice x=F(x) metodou proste iterace |
% [x]=VyresCokoli(jmenoF,a,b,x0,nmax,epsilon); |
% x ... nalezene reseni rovnice |
% jmenoF ... nazev funkce F(x) jako retezec znaku |
% a ... dolni mez definicniho oboru F(x) |
% b ... horni mez definicniho oboru F(x) |
% x0 ... pocatecni odhad reseni a<=x<=b |
% nmax ... maximalni pocet vycisleni funkce F(x) |
% epsilon ... tolerance rozdilu mezi levou a pravou stranou rovnice |
while nmax>0 & x0>=a & x0<=b |
% stejne |
% ukazka neprimeho volani funkce jmenem v bode x0 |
x=feval(jmenoF,x0); |
nmax=nmax-1; |
% stejne |
if abs(x-x0)<epsilon |
% stejne |
return |
% stejne |
end |
x0=x; |
% stejne |
end |
x=inf; |
% stejne |
|
|
|
|
Příklad 5A.5: |
|
|
Jistě znáte omšelou hitorku z 19. století, jak neposlušný žák Gauss dostal
za trest spočítat součet všech čísel od 1 do 100 a on to měl hned hotové.
Sestavte funkci pro výpočet součtu prvních n přirozených čísel.
Instrukce: Krokujte a místo proměnné k si představte počet čárek na tácku. |
|
|
Řešení: |
|
|
function [s]=ZaTrest(n) |
% Soucet prvnich n prirozenych cisel |
% [s]=ZaTrest(n); |
% s ... hodnota souctu |
% n ... pocet cisel |
k=1; |
% prvni clen souctu |
s=0; |
% soucet zacina od nuly |
while k<=n |
% mame jeste pricitat? |
s=s+k; |
% pricteme 1,2,3,... |
k=k+1; |
% zvetsime na dalsi clen 2,3,4,... |
end |
|
|
|
|
Příklady pro samostatné vypracování |
|
|
Příklad 5B.1: |
|
|
Pomocí funkce NSD sestavte funkci pro výpočet
nejmenšího společného násobku dvou čísel.
|
|
|
|
Příklad 5B.2: |
|
|
Pomocí funkce NSD sestavte funkci pro výpočet nejmenšího
společného dělitele čísel uložených ve vektoru. Použijte funkci size.
|
|
|
|
Příklad 5B.3: |
|
|
Pyramida je stavěna z kostek a bez dutin. Výška pyramidy je H.
Základna pyramidy je čtverec o straně H. Sestavte funkci pro spotřebu kostek
na její stavbu. Definujte pojem vytunelovaná pyramida alespoň třemi různými
obecnými způsoby. Pro každou definici sestavte funkci pro spotřebu
kostek na její stavbu.
|
|
|
|
Příklad 5B.4: |
|
|
Blouznivý poutník ušel první den A kilometrů. Další dny
ušel vždy polovinu trasy předchozího dne a ještě k tomu opačným směrem.
Bez použití mocnin sestavte funkci, která z počtu dnů N a vzdálenosti A určí
délku pochodu, vzdálenost mezi začátkem a cílem pochodu a účinnost poutníka v procentech.
|
|
|
|
Seznam použitých příkazů |
|
|
while, return, floor, abs, mod, help, feval, eval
|
|
|