Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Lekce 04

V této lekci se budeme věnovat cyklům for a while. Bez znalosti těchto dvou cyklů v podstatě není možné se věnovat programování.

Cyklus for

Cyklus for využijeme, pokud chceme nějaký příkaz vykonat opakovaně, ale pro různé hodnoty nějaké proměnné. Ukážeme si to na jednoduchém příkladě:

for i=1:1:5
    i
end
i = 1
i = 2
i = 3
i = 4
i = 5

Tento jednoduchý program nám postupně vypsal hodnoty od 1 do 5. Jak ale cyklus funguje?

  • Na prvním řádku za příkazem for se volí, jaké hodnoty proměnné i budeme uvažovat. Zápisem i=1:1:5 říkáme, že v proměnné i budou postupně hodnoty od 1 (první parametr) do 5 (třetí parametr) s krokem 1 (druhý parametr). Pokud bychom tedy použili i=2:3:8, do proměnné i budeme postupně dosazovat hodnoty 2, 5 a 8.

  • Následně dochází ke spuštění samotného těla cyklu (mezi rádkem začínájícím for a řádkem obsahujícím for). V našem případě se jedná o řádek, který obsahuje pouze i.

  • Tělo cyklu bude postupně spuštěno a vyhodnoceno pro jednotlivé hodnoty proměnné i

    • na žačátku je i=1, takže po zavolání i se vypíše 1. Program dojel na konec těly cyklu (k end) a proto se načte následující hodnota i, což je 2

    • nyní je tedy i=2 a po zavolání i se tedy vypíše 2. Program opět dojel na konec těla cyklu a proto se opět načte následující hodnota i, což je 3

    • nyní je tedy i=3 a po zavolání i se tedy vypíše 3. Program opět dojel na konec těla cyklu a proto se opět načte následující hodnota i, což je 4

    • nyní je tedy i=4 a po zavolání i se tedy vypíše 4. Program opět dojel na konec těla cyklu a proto se opět načte následující hodnota i, což je 5

    • nyní je tedy i=5 a po zavolání i se tedy vypíše 5. Program opět dojel na konec těla cyklu, ale protože 5 je poslední možná hodnota, cyklus se již nebude spouštet

Pro lepší názornost provedeme úpravu na druhém řádku, a napíšeme zde i^2.

for i=1:1:5
    i^2
end
ans = 1
ans = 4
ans = 9
ans = 16
ans = 25

Jak tento program funguje?

  • Na prvním řádku za příkazem for se volí, jaké hodnoty proměnné i budeme uvažovat. Zápisem i=1:1:5 opět říkáme, že v proměnné i budou postupně hodnoty od 1 (první parametr) do 5 (třetí parametr) s krokem 1 (druhý parametr).

  • Tělo cyklu bude postupně spuštěno a vyhodnoceno pro jednotlivé hodnoty proměnné i

    • na žačátku je i=1, takže po zavolání i^2 se vypíše druhá mocnina 1, což je 1. Program dojel na konec těly cyklu (k end) a proto se načte následující hodnota i, což je 2

    • nyní je tedy i=2 a po zavolání i^2 se vypíše druhá mocnina 2, což je 2. Program opět dojel na konec těla cyklu a proto se opět načte následující hodnota i, což je 3

    • nyní je tedy i=3 a po zavolání i^2 se vypíše druhá mocnina 3, což je 9. Program opět dojel na konec těla cyklu a proto se opět načte následující hodnota i, což je 4

    • nyní je tedy i=4 a po zavolání i^2 se vypíše druhá mocnina 4, což je 16. Program opět dojel na konec těla cyklu a proto se opět načte následující hodnota i, což je 5

    • nyní je tedy i=5 a po zavolání i^2 se vypíše druhá mocnina 5, což je 25. Program opět dojel na konec těla cyklu, ale protože 5 je poslední možná hodnota, cyklus se již nebude spouštet

Pokud bychom chtěli vypsat druhé mocniny čísel od 1 do 10, je třeba na prvním řádku upravit rozsah hodnot, které bude cyklus for uvažovat

for i=1:1:10
    i^2
end
ans = 1
ans = 4
ans = 9
ans = 16
ans = 25
ans = 36
ans = 49
ans = 64
ans = 81
ans = 100

Následující úprava zajistí, že se nám vypíší pouze druhé mocniny sudých čísel od 2 do 20.

for i=2:2:20
    i^2
end
ans = 4
ans = 16
ans = 36
ans = 64
ans = 100
ans = 144
ans = 196
ans = 256
ans = 324
ans = 400

Zatím jsem si hodnoty pouze vypisovali, což nám ale neumožňuje s výslednými hodnotami dále pracovat. Proto si nyní ukážeme, jak lze výsledky uložit do vektoru. Budeme chtít vypsat druhé mocniny čísel od 1 do 10 a uložit je do proměnné vektor:

%vytvorime desetiprvkový vektor (pojmenovany vektor), ktery bude obsahovat nuly 
%zeros(a,b) vytvori nulovou matici, ktera ma "a" radku a "b" sloupcu
vektor=zeros(1,10);

for i=1:1:10

%hodnoty i^2 ukladame do `vektoru` na i-tou pozici
%vektor(i)=  ... do vektoru 'vektor' uloz hodnotu na i-tou pozici
%na konci prikazu je strednik, aby se nevypisovaly jednotlive kroky cyklu for
vektor(i) = i^2;

end

%vypis vysledny vektor
vektor
vektor =

     1     4     9    16    25    36    49    64    81   100

Nyní máme všechny výsledky uložené v jednom vektoru a můžeme s nimi dále pracovat.

Program jde upravit tak, aby se do vektoru uložily druhé mocniny čísel od 1 do n:

%zde je zadana pozadovana hodnota n - horni mez
n=50

%velikost vektoru je urcena primo pomoci promenne n
vektor=zeros(1,n);

%obdobna uprava je i u cyklu `for`
for i=1:1:n

vektor(i) = i^2;

end

vektor
n = 50
vektor =

 Columns 1 through 11:

      1      4      9     16     25     36     49     64     81    100    121

 Columns 12 through 22:

    144    169    196    225    256    289    324    361    400    441    484

 Columns 23 through 33:

    529    576    625    676    729    784    841    900    961   1024   1089

 Columns 34 through 44:

   1156   1225   1296   1369   1444   1521   1600   1681   1764   1849   1936

 Columns 45 through 50:

   2025   2116   2209   2304   2401   2500

Situace bude složitější, pokud bychom si chtěli ukládat pouze druhé mocniny sudých čísel od 2 do n.

Pokud použijeme stejný kód jako minule, výsledek nebude optimální

n=6

vektor=zeros(1,n)

for i=2:2:n
    vektor(i)=i^2;
end

vektor
n = 6
vektor =

  0  0  0  0  0  0

vektor =

    0    4    0   16    0   36

Do vektoru se nám sice uložily druhé mocniny, ale pouze na sudé pozice, liché obsahují nulu. To je dáno tím, že cyklus for je nastavený pouze pro sudá čísla, takže v příkazu vektor(i)=i^2 jsou hodnoty ukládány pouze na sudé pozice vektoru.

Řešení spočívá v následující úpravě:

n=8

%pri tvorbe nuloveho vektoru rikame, ze chceme pouze n/2 sloupcu. 
%Prikaz floor zaokrouhli vyslednou hodnotu dolu (to je pro pripad, ze by nekdo jako n zadal liche cislo
vektor=zeros(1,floor(n/2));

for i=2:2:n
    %obdobna uprava - i/2 zajisti, ze se bude ukladat i na licha cisla a bude se vse cislovat od 1
    %pro i=2 dostane 1
    %pro i=4 dostaneme 2
    %pro i=6 dostaneme 3
    %.......
    vektor(i/2)=i^2;
end

vektor
n = 8
vektor =

    4   16   36   64

Alternativní způsob řešení problému.

Pomocí if zkontrolujeme, jestli není n liché (s využitím zbytku po celočíselném děleni (modulo)). Pokud je n liché, snížíme jeho hodnotu o jedna a pak již nemusíme zaokrouhlovat při tvorbě nulového vektoru.

n=7

%Kontrola zda je `n` liche - pokud ano, je hodnota `n` snížena o jedno (a dostavame sude cislo)
%povsimnete si, ze de vubec neni vetev `else;, protoze ji nepotrebujeme
if mod(n,2)==1
    n=n-1
end

vektor=zeros(1,n/2)



for i=2:2:n
    vektor(i/2)=i^2
end

vektor
n = 7
n = 6
vektor =

  0  0  0

vektor =

   4   0   0

vektor =

    4   16    0

vektor =

    4   16   36

vektor =

    4   16   36

Ukázka pokročilejšího kódu, který dle nastavených limitu počítá různé mocniny o různých základech:

  • pomocí proměnných m a n se určí, jaké mocniny se budou počítat. Např. m=3 a n=6 znamená, že budou vypsány třetí až šesté mocniny

  • pomocí proměnných i a j se určí, pro jaké základy budou mocniny počítány. Např. i=2 a j=4 znamená, že budou počítány mocniny o základech dva až čtyři

%jake mocniny budeme pocitat

%nejmensi pocitana mocnina
m=3
%nejvetsi pocitana mocniny
n=6

%pro jake zaklady budeme mocniny pocitat

%nejmensi zaklad
i=2

%nejvetsi zaklad
j=4


%pripravime si nulovou matici, do ktere budeme ukladat vysledky
%na radcich budou jednotlive mocniny pro jeden zaklad
%tj. pokud budeme pocitat treti az seste mocniny, potrebujeme 4 sloupce

%na sloupcich budou mocniny jednotlivych zakladu
%tj. pokud  budeme pocitat se zaklady 2,3 a 4, potrebujeme 4 radky

vektor=zeros(j-i+1,n-m+1);

%pouzivame dva cykly for
%prvni bude menit, jakou mocninu pocitame
for mocnina=m:1:n
    %druhy cyklus meni zaklady
    for zaklad=i:1:j
    vektor(zaklad-(i-1),mocnina-(m-1))=zaklad^mocnina;
    end
end

vektor
m = 3
n = 6
i = 2
j = 4
vektor =

      8     16     32     64
     27     81    243    729
     64    256   1024   4096

Výpočet faktoriálu s pomocí cyklu for

GNO/OCtave samozřejmě umí vypočítat faktoriál přímo, pomocí funkce factorial():

format long

factorial(70)
ans = 1.197857166996989e+100

Příkaz format long byl přidán, protože jsme očekávali, že výsledná hodnota bude velká.

Nicméně my si ukážeme, jak počítat faktoriál s pomocí cyklu for na výpočtu faktoriálu 5. Výsledný kód není nikterak komplikovaný:

vysledek=1

for i=1:1:5
vysledek=vysledek*i
end
vysledek = 1
vysledek = 1
vysledek = 2
vysledek = 6
vysledek = 24
vysledek = 120

Jak kód funguje?

  • Protože počítáme faktoriál pěti, využijeme cyklus for, aby nám nageneroval všechny hodnoty i od 1 do pěty.

  • Tyto hodnoty ale nepotřebujeme vypsat, potřebujeme je vynásobit mezi sebou.

  • Využijeme jednoduchý trik - na začátku jsme si vytvořili proměnnou vysledek a uložili do něj 1.

  • V těle cyklu for pak v každém kroku proměnnou vysledek vynásobíme hodnotou v proměnné i a tuto nově vzniklou hdonotu uložíme do výsledku (jak je vidět ve výpisu kódů, hodnota výsledku se podstupně zvětšuje)

Protože je takovýto program užitečný, uděláme z něj funkci. Vytvoříme nový skript pojmenovaný faktorial.m a do něj uložíme následujíci kód:

!POZOR - v názvu funkce použijte faktorial s k, funkce factorial s c již v GNU/Octave existuje, tak si ji nechceme přepsat

function out=faktorial(n)

vysledek=1;

for i=1:1:n
vysledek=vysledek*i;
end
out=vysledek;
end

Nyní když zadáme faktorial(n), obdržíme faktoriál čísla n.

faktorial(5)
ans = 120

Takovouto funkci můžeme využít například v situaci, že si chceme udělat tabulku faktoriálů od 1 do n

n= 10
vektor=zeros(1,n);


for p=1:1:n
vektor(p)=faktorial(p);
end

vektor
n = 10
vektor =

 Columns 1 through 8:

         1         2         6        24       120       720      5040     40320

 Columns 9 and 10:

    362880   3628800

Takový kód ale není moc optimální, protože pro každý faktoriál počítáme vše znovu (například pokud bychom počítaly prvních 100 faktoriálů, tak pro faktoriál 99 i faktoriál 100 bychom v obou případech nasobili čísla od 1 do 99).

Výrazné zjednodušení je představeno níže (zkuste si porovnat dobu výpočtu u obou kódů v případě větších n)

n=10

vysledek=zeros(1,n);

vysledek(1)=1;

for i=2:1:n
vysledek(i)=vysledek(i-1)*i;
end

vysledek
n = 10
vysledek =

 Columns 1 through 8:

         1         2         6        24       120       720      5040     40320

 Columns 9 and 10:

    362880   3628800

Cyklus while

Jak je vidět, cyklus for je nesmírně užitečný. Někdy se ale můžeme dostat do situace, kdy nevíme kolikrát má být cyklus for vykonán (kolikrát a pro jaké hodnoty). V takové situaci můžeme využít cyklus while, který se spouští tak dlouho, dokud je splněná nějaká podmínka.

Jenoduchý příklad vidíme zde

i=1

%pokud je i mensi nez 10, telo cyklu se spusti
while i<10
    %vypis na oprazovku "cyklus while se spustil"
    display('cyklus while se spustil')
    %zvedni hodnotu i o jedna
    i=i+1
end
i = 1
cyklus while se spustil
i = 2
cyklus while se spustil
i = 3
cyklus while se spustil
i = 4
cyklus while se spustil
i = 5
cyklus while se spustil
i = 6
cyklus while se spustil
i = 7
cyklus while se spustil
i = 8
cyklus while se spustil
i = 9
cyklus while se spustil
i = 10

Jak program funguje?

  • Na začátku programu jsme i nastavili na jedna

  • Pokud je i menší než 10, cyklus se spustí (začne se opakovaně vykonávat tělo cyklu), dokud nebude i větší nebo rovno deseti

  • Cyklus vždy vypíše informaci o tom že se spustil a následně zvýší hodnotu i o jedna

  • Vidíme, že se cyklus spustil celkem 9x

  • V posledním (devátém) průběhu cyklu byla hodnota i zvětšena na 10, takže k dalšímu spuštění už nedošlo

Nyní si ukážeme další možnost použití cyklu while

Cheme najít první číslo větší než 100, které získáme tak že budeme k číslu jedna přičítat opakovaně číslo 7.

%pomocna promenna, kterou nastavujeme na 0
%jamile objevime hledane cislo, hodnota promenne zmenine na 1 (k tomu vyuzijeme `if`)
stop=0

%hodnota i je na zacatku 1
i=1

%cyklus while se bude spoustet tak dlouho, dokud bude proměnna "stop" rovna 0
while stop==0
    %hodnotu i zvetsime o 7
    i=i+7
    
    %provedeme kontrolu, zda jiz hodnota i po poslednim pricteni neni vetsi nez 100
    if i>100
        %pokud i je vetsi nez 100, zmenime hodnotu stop na 1 (a while se jiz nespusti)
        stop=1
    end
end
stop = 0
i = 1
i = 8
i = 15
i = 22
i = 29
i = 36
i = 43
i = 50
i = 57
i = 64
i = 71
i = 78
i = 85
i = 92
i = 99
i = 106
stop = 1

Nyní si ukážeme, jak pomocí while zjistit, kolik musíme sečíst po sobě jdoucích přirozených čísel od 1, aby byl součet větší než 10 000.

%do promenne `i` si budeme postupne ukladat jednotliva po sobe jdouci prirozena cisla, zacneme tedy s i=1
i=1;
%zde budeme ukaldat vysledny soucet, na zacatku je to tedy 1 (to naceteme primo z i)
vysledek=i;

%ptame se, zda je vysledny soucet mensi nez 10000, pokud ano, spusti se cyklus while a bude se opakovat, dokud soucat nebude vetsi
while vysledek<10000
    %zvysime hodnotu i o 1
    i=i+1;
    %a o novou hodnotu i zvysime celkovy soucet
    vysledek=vysledek+i;
end

%jakmile se program zastavi, vypise nam celkovy pocet prirzenych cisel
i
%a celkovy soucet
vysledek


%Muzeme si i vypsat nejvyssi pocet prirozenych cisel, ktery jeste nestaci + vysledny nedostatecny soucet
disp('posledni nedostatecne')

i-1
vysledek-i
i = 141
vysledek = 10011
posledni nedostatecne
ans = 140
ans = 9870