Náhradní text k cvičení 4.11.



Podobné dokumenty
Programování. Debugging a testování. Martin Urza

Čtvrtek 8. prosince. Pascal - opakování základů. Struktura programu:

Kolekce ArrayList. Deklarace proměnných. Import. Vytvoření prázdné kolekce. napsal Pajclín

Programování. Psaní čistého kódu. Martin Urza

dovolují dělení velkých úloh na menší = dekompozice

Test prvočíselnosti. Úkol: otestovat dané číslo N, zda je prvočíslem

Úvod do programování

Pascal. Katedra aplikované kybernetiky. Ing. Miroslav Vavroušek. Verze 7

NPRG030 Programování I, 2017/18 1 / :22:16

type Obdelnik = array [1..3, 1..4] of integer; var M: Obdelnik;

1 PRVOCISLA: KRATKY UKAZKOVY PRIKLAD NA DEMONSTRACI BALIKU WEB 1

1.1 Struktura programu v Pascalu Vstup a výstup Operátory a některé matematické funkce 5

Intervalové stromy. Představme si, že máme posloupnost celých čísel p 0, p 1,... p N 1, se kterou budeme. 1. Změna jednoho čísla v posloupnosti.

Anotace. Dynamické programování, diskrétní simulace.

ALGORITMIZACE A PROGRAMOVÁNÍ

Programovací jazyk Pascal

NPRG030 Programování I, 2015/16 1 / :25:32

Implementace seznamů do prostředí DELPHI pomocí lineárního seznamu

- znakové konstanty v apostrofech, např. a, +, (znak mezera) - proměnná zabírá 1 byte, obsahuje kód příslušného znaku

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

Klíčové pojmy: Cyklus, řídící proměnná, inicializace, test podmínky, přerušení cyklu, vnořování cyklů.

Tematický celek Proměnné. Proměnné slouží k dočasnému uchovávání hodnot během provádění aplikace Deklarace proměnných

Rekurze. Pavel Töpfer, 2017 Programování 1-8 1

Programovani v Maplu Procedura

IB108 Sada 1, Příklad 1 Vypracovali: Tomáš Krajča (255676), Martin Milata (256615)

Algoritmizace a programování

10. Editor databází dotazy a relace

2 Základní funkce a operátory V této kapitole se seznámíme s použitím funkce printf, probereme základní operátory a uvedeme nejdůležitější funkce.

Sada 1 - Základy programování

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Vyučovací hodina. 1vyučovací hodina: 2vyučovací hodiny: Opakování z minulé hodiny. Procvičení nové látky

Interpret jazyka IFJ2011

Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 21.

Distanční opora předmětu: Programování v jazyce C Tématický blok č. 8: Dynamické datové struktury, ladění programů Autor: RNDr. Jan Lánský, Ph.D.

1. D Y N A M I C K É DAT O V É STRUKTUR Y

Sada 1 - Základy programování

PODPROGRAMY PROCEDURY A FUNKCE

Identifikátory označují objekty v programu používané (proměnné, typy, podprogramy).

Anotace. Soubory a práce s nimi, rekurze podruhé, struktury (datový typ record), Martin Pergel,

Seminář z IVT Algoritmizace. Slovanské gymnázium Olomouc Tomáš Kühr

PES lib (C + PASCAL) KNIHOVNY KOMUNIKAÈNÍCH FUNKCÍ 03/ PESlib KOMUNIKAČNÍ KNIHOVNY C, PASCAL 03/ stran 1

EVROPSKÝ SOCIÁLNÍ FOND. Úvod do PHP PRAHA & EU INVESTUJEME DO VAŠÍ BUDOUCNOSTI

Digitální učební materiál

Teoretické minimum z PJV

Registrační číslo projektu: CZ.1.07/1.5.00/ Elektronická podpora zkvalitnění výuky CZ.1.07 Vzděláním pro konkurenceschopnost

VY_32_INOVACE_08_2_04_PR

Logické operace. Datový typ bool. Relační operátory. Logické operátory. IAJCE Přednáška č. 3. může nabýt hodnot: o true o false

Příklady: (y + (sin(2*x) + 1)*2)/ /2 * 5 = 8.5 (1+3)/2 * 5 = /(2 * 5) = 1.3. Pavel Töpfer, 2017 Programování 1-3 1

2.1 Podmínka typu case Cykly Cyklus s podmínkou na začátku Cyklus s podmínkou na konci... 5

Sbírka příkladů. verze

Obecná informatika. Matematicko-fyzikální fakulta Univerzity Karlovy v Praze. Podzim 2012

Programování 2 (NMIN102) Soubory. RNDr. Michal Žemlička, Ph.D.

1. lekce. do souboru main.c uložíme následující kód a pomocí F9 ho zkompilujeme a spustíme:

Vyhledávání. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 12.

Základy programování. Úloha: Eratosthenovo síto. Autor: Josef Hrabal Číslo: HRA0031 Datum: Předmět: ZAP

Programy na PODMÍNĚNÝ příkaz IF a CASE

Pracovní listy - programování (algoritmy v jazyce Visual Basic) Algoritmus

MQL4 COURSE. By Coders guru -5 Smyčky & Rozhodnutí Část 2

Skripta ke školení. Základy VBA. vypracoval: Tomáš Herout. tel:

VISUAL BASIC. Práce se soubory

Příklady k prvnímu testu - Matlab

Základy programování (IZP)

for (int i = 0; i < sizeof(hodnoty) / sizeof(int); i++) { cout<<hodonoty[i]<< endl; } cin.get(); return 0; }

Více o konstruktorech a destruktorech

LED_007.c Strana: 1/5 C:\Michal\AVR\Výukové programy\archiv\ Poslední změna: :01:48

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

Předmět: Algoritmizace praktické aplikace

8. Posloupnosti, vektory a matice

5 Rekurze a zásobník. Rekurzivní volání metody

Cvičení 9 - Monitory. monitor m; var proměnné... procedure p; begin... end; begin inicializace; end;

MenuLIB KNIHOVNA SIMPLE4 PRO TVORBU UŽIVATELSKÉHO ROZHRANÍ NA PLC MICROPEL

II. Úlohy na vložené cykly a podprogramy

Binární soubory (datové, typované)

PHP tutoriál (základy PHP snadno a rychle)

přirozený algoritmus seřadí prvky 1,3,2,8,9,7 a prvky 4,5,6 nechává Metody řazení se dělí:

Náznak ukázky syntaxe a sémantiky pro projekt. 1 Syntaktické prvky. Poslední aktualizace: 8.

PROGRAMOVÁNÍ MIKROPOČÍTAČŮ CVIČENÍ 10

Návod pro zadávání zápisů o utkání do BLMFis

Řídicí struktury. alg3 1

NPRG030 Programování I, 2018/19 1 / :25:37

Šablonovací systém htmltmpl vypracoval: Michal Vajbar, Šablonovací systém htmltmpl

Object Pascal je přísně typový procedurální jazyk, který umožňuje jak strukturované, tak objektově orientované programování.

PL/SQL. Jazyk SQL je jazykem deklarativním, který neobsahuje procedurální příkazy jako jsou cykly, podmínky, procedury, funkce, atd.

Hranová konzistence. Arc consistency AC. Nejprve se zabýváme binárními CSP. podmínka odpovídá hraně v grafu podmínek

IAJCE Přednáška č. 8. double tprumer = (t1 + t2 + t3 + t4 + t5 + t6 + t7) / 7; Console.Write("\nPrumerna teplota je {0}", tprumer);

Algoritmizace a programování

Program Podnikání 5. týden. a produktivita

2. lekce Algoritmus, cyklus Miroslav Jílek

Assembler - 5.část. poslední změna této stránky: Zpět

Algoritmus Minimax. Tomáš Kühr. Projektový seminář 1

Závěrečná zkouška z informatiky 2011

Střední škola pedagogická, hotelnictví a služeb, Litoměříce, příspěvková organizace

7. ODE a SIMULINK. Nejprve velmi jednoduchý příklad s numerických řešením. Řešme rovnici

Zadání projektů z BPC2 pro letní semestr 2007/2008

Úvod do programování. Úvod do programování. ing. Miroslav Jílek 2009, SJOP Poděbrady

Základy programování Proměnné Procedury, funkce, události Operátory a podmínková logika Objekt Range a Cells, odkazy Vlastnosti, metody a události

Digitální učební materiál

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

DYNAMICKÉ PROGRAMOVÁNÍ A PROBLÉM BATOHU

Transkript:

Jakub Tomek Náhradní text k cvičení 4.11. Tento text má 3 různé části: první pojednává o podprogramech (funkcích a procedurách), jak se zapisují a používají. Druhá část je stručný popis algoritmu Eratosthenovo síto. Třetí část je návod k používání debuggeru (ladících prostředků). Omlouvám se za místy ošklivé vysázení a přetečení řádků... když to někoho bude smrtelně urážet, dejte mi vědět a spravím to. 1 Podprogramy 1.1 Příklad jednoduché funkce a její rozbor Prve se podívejme na zdrojový kód, ve kterém je deklarována funkce max2, která nám dá větší ze dvou čísel. program testmaxima; var x,y,z:integer; function max2(a,b:integer):integer; if (a>b) then max2:=a else max2:=b; read(x,y); z:=max2(x,y); write(z); end. Rozeberme si tuto ukázku: Funkce se deklarují za proměnnými hlavního programu a před em hlavního programu. Můžete jich deklarovat libovolně mnoho za sebou. Poznámka trochu stranou - pokud voláte funkci A ve funkci B, pak funkce A musí být deklarována před funkcí B. To obecně není problém (jenom otrava), problém je, když vám vznikne cyklus (funkce A vyžaduje funkci B, B vyžaduje C a C vyžaduje A). Pak se neobejdete bez tzv. forward deklarace, což by mělo být brzy na přednášce. Zápis funkce je následující: 1

function - Klíčové slovo, kterým dáváte najevo, že budete vytvářet funkci. název funkce - Zde max2. Pro názvy funkce platí obdobná pravidla jako pro názvy proměnných. seznam parametrů - Zde (a,b,:integer) - tj. funkce má na vstupu dvě proměnné typu integer. Tyto parametry jsou vstupem dané funkce (obdobně jako sčítance jsou vstupem funkce sčítání dvou čísel). Někdy může být funkce i bezparametrická. :typ; - Typ návratové hodnoty: např. když sčítáte 2 čísla, tak návratová hodnota - součet - je celé číslo. Nebo když programujete spojení dvou řetězců (stringů), tak návratová hodnota bude string. Pozor na středník na konci řádku, na ten se s oblibou zapomíná. Návratový typ může být jen jednoduchý typ - integer, string, real, boolean apod. Ne třeba pole. var (tady zrovna není) - Jako u hlavního programu před em můžete dát slovo var a tam definovat tzv. lokální proměnné (vizte dále). - kód funkce, - To, co se vykonává v rámci funkce se omezí, jako u hlavního programu, blokem -end. Ovšem pozor, neukončuje se tečkou, ale středníkem. Jak určit, co funkce vrací, jaká je tedy její návratová hodnota? Když funkce skončí (typicky dojde na end, který ji uzavírá), podívá se na obsah proměnné určený názvem té funkce (jejíž typ jsme deklarovali za dvojtečkou v deklaraci funkce) - v našem případě v proměnné max2 (všimněte si, že jsme ji nikde nedeklarovali, je implicitní, daná existencí funkce toho jména). A tuto hodnotu vrátí. To, že funkce vrací hodnotu, znamená, že tuto hodnotu můžete třeba uložit do jiné proměnné (v našem případě ji ukládáme do proměnné z). Rozhodně funkce nic sama o sobě nevypisuje. Když máte integerovou proměnnou x, také musíte napsat write(x), abyste její hodnotu vypsali. A funkce s návratovým typem integer se v podstatě chová jako integer, jen chvilku trvá, než se zjistí, jakou má hodnotu. Jak vlastně probíhá zavolání funkce? V našem hlavním programu prve načteme dvě čísla a pak do proměnné z uložíme návratovou hodnotu funkce max2. Jak to vůbec funguje? Když se v programu dostaneme k volání funkce, vezmou se hodnoty proměnných, které vkládáme (zde x,y) a zkopírují se do příslušných lokálních proměnných volané funkce (zde a,b). Pak se projde kód funkce až na konec a na konci se zkontroluje, co je uloženo v proměnné s názvem dané funkce (zde max2). Tato návratová hodnota pak nahradí místo, kde jsme funkci zavolali a uloží se do proměnné z. 2

1.2 Procedury Procedura se zapisuje takřka stejně jako funkce - jen klíčové slovo není function, ale procedure a nic nevrací. Až se dostaneme k předávání parametrům odkazem, uvidíme, že procedury nejsou tak k ničemu, jak by se ted mohly zdát. 1.3 Lokální a globální proměnné V programu za slovem var se deklarují proměnné globální - viditelné a platné po celou dobu běhu programu. Uvnitř podprogramů pak můžete deklarovat funkce lokální. Hodnoty parametrů předaných hodnotou (v příkladu výše a,b) jsou také lokální proměnné. Rozdíl oproti globálním proměnným je, že pamět, kterou zabírají lokální proměnné, je uvolněna po doběhnutí podprogramu, kde jsou deklarovány, což je užitečné (proč zabírat pamět zbytečnými globálními proměnnými, když nejsou nutné?). Pozor na používání lokálních proměnných stejného jména jako má nějaká globální proměnná tehdy platí hodnota lokální proměnné. Snažte se používání stejně pojmenovaných proměnných raději vyhnout, je-li to možné, přehlednosti programu to nepomáhá. 1.4 K čemu to vůbec je? Pozitiva podprogramů lze shrnout zkratkou ZOMPIE 1 Znovuvyužitelenost: Když už máte napsanou funkci, u které víte, jak funguje, můžete ji snadno použít i v jiných programech. Dokonce vznikají jen soubory s funkcemi (knihovny, v Pascalu se zvoucí unity), které sdružují často používané funkce určitého typu, vy pak jen ve svém programu dáte počítači najevo, že chcete nějakou knihovnu využít a pak máte přístup k jejím funkcím (takže třeba díky knihovně vektorového počítání dostanete zadarmo funkce, které vám počítají skalární, či vektorový součin, úhel mezi vektory, umí vektory normalizovat a škálovat atd. - tyhle věci pak nemusíte psát sami). Oddělené ladění: Napsat dlouhý kód a zjistit, že vlastně pořádně nefunguje, je nepříjemné. Zjistit kde je chyba může být obtížné. Když používáte podprogramy, můžete odděleně ladit tyto podprogramy (které nebývají tak rozsáhlé) a když víte, že fungují správně, pak je skládat do dalších programů. Méně kódu: Pokud ve svém kódu potřebujete na deseti místech zjistit maximum z dvou čísel, je šetrnější jednou napsat 6 řádků funkce, která vám to maximum počítá a pak na každém místě tu funkci na jednom řádku zavolat, než na každém z potřebných míst vypsat 4 řádky. Také, když nepoužíváte podprogramy a máte jeden kód na více místech, může nastat 1 Pokud máte dojem, že jsou pojmenování maličko ohnutá, abychom měli pěknou zkratku, není to pouze dojem. Ale není to ještě tak zlé - jsou třeba hezké zkratky, ve kterých N je zkratka za non-nonsensical :). 3

problém, když něco na těch kódech chcete změnit. Například můžete jeden z těch kódů opomenout, nevšimnout si ho, a změnit jen ostatní. To pak vede k dost nepříjemným chybám (vždyt vy víte, že jste to všude změnili, tak proč to nefunguje?). Když máte takový kód ve funkci a změníte kód funkce, automaticky se to projeví na všech místech, kde funkci používáte. Přehlednost: Používáním funkcí je zdrojový kód výrazně přehlednější. Podívejte se třeba na metodu logic (stačí dát vyhledat logic a hodí vás to tam) zde: http://code.google.com/p/smart-path-unreal-2004/source/browse /Hunter/src/cz/cuni/amis/pogamut/ut2004/examples/Hunter.java?spec=svn11&r=11 Je to metoda ovládající bota v Unreal Tournamentu 2004. Mělo by být velmi zhruba jasné, jak se bot má chovat - je celkem patrné, co dělá. Když byste funkce (v daném jazyce se tomu říká metody) jako např. canseeenemies(), isshooting() atd. nevolali takto, ale přímo tam napsali jejich kód, bylo by to naprosto nečitelné. Izolace kódu: Když dostanete funkci u které víte, co přijímá za vstupní parametry a co vrací, nemusíte vůbec řešit její vnitřek a můžete ji rovnou použít. Efektivní distribuované programování: Pokud máte kód, kde je potřeba 50 funkcí, můžete každou nechat naprogramovat jiným programátorem a pak je jen poskládat (samozřejmě programátoři musí dodržet dohodnutá pravidla, jak funkce komunikují - co přijímají a co vracejí). Představa, že 50 lidí má napsat kus surového kódu a někdo to pak slepí dohromady, je dosti děsivá. Mají podprogramy nevýhody? Ano - jejich používání trochu zpomaluje běh programu. Ale není to typicky nijak výrazné a výhody převažují. 1.5 Předávání parametrů odkazem a hodnotou Funkce a procedury jak jsme se na ně zatím dívali, mají dva (možná i více) problémy. Například neumí vracet pole. To může být někdy dost potíž. Další problém je, že když funkci voláme, parametry se kopírují do lokálních proměnných. To nevadí, když předáváme dvě čísla. Ale když předáváme velké pole, už to může zabrat nezanedbatelně času. Tyto problémy řeší předávání odkazem. Před proměnné, které chcete předávat odkazem napíšete v seznamu parametrů klíčové slovo var. K čemu to vede? Už víme, že když předáváme parametr hodnotou (bez var), vezmou se hodnoty proměnných v programu a zkopírují se do lokálních proměnných podprogramu. Oproti tomu, když předáváme proměnnou odkazem, ve skutečnosti předáváme adresu proměnné v paměti počítače (čtyř, či osmibytové číslo). Podprogram daný odkaz přijme a dále s ním pracuje. Nic se nekopíruje (takže když dáte jako 4

parametr pole, problém s délkou kopírování odpadá - protože pracujete rovnou na původním poli). Díky tomu, že pracujete na skutečné proměnné z hlavního programu (a ne na kopii), můžete ji změnit. Díky tomu můžete jakoby vracet pole a jiné složené datové typy - předáte je odkazem a uvnitř funkce je změníte. Ilustrujme předávání odkazem na příkladu: program testvymeny; var x,y:integer; procedure vymen(var a,b:integer); var tmp:integer; tmp:=a; a:=b; b:=tmp; read(x,y); vymen(x,y); write(x,,y); end. Používáme zde proceduru, která prohodí obsahy dvou proměnných (tj. pokud načtete do x 5 a do y 6, tak vám program vypíše 6 5). Jak to funguje? Načteme dvě čísla a pak zavoláme proceduru vymen. Parametry předáme odkazem, takže a bude to samé jako x a b to samé co y. Podstatné je, že jde vždy o dvě pojmenování téhož místa v paměti. Proto když v proceduře prohodíme a a b a pak se vrátíme do hlavního programu, změna přetrvá. Oproti tomu, kdybychom proceduru deklarovali bez klíčového slova var, ve chvíli volání by se obsahy x,y zkopírovaly do lokálních proměnných a,b, v rámci procedury by se lokální proměnné prohodily, procedura by skončila, lokální proměnné by zmizely a tedy by se v hlavním programu vůbec nic nezměnilo. Pro představu - k čemu může být takové předání odkazem? Například když chcete vyvtvořit podprogram, která vám setřídí pole, nemůžete to udělat pomocí předávání hodnotou a funkcí - funkce vám nedovolí vrátit pole, protože to není jednoduchý datový typ. Musíte to pole předat podprogramu (proceduře) odkazem, ta procedura se na poli vyřádí a až skončí, učiněné změny přetrvají. Jiný, abstraktní, příklad. Ve zprávách ted někdy šlo, jak jakási matka hrozně tloukla své dítě, protože zlobilo - a tloukla ho, aby se uklidnila. To je matka, která svého potomka předala proceduře bij(var p:dite) odkazem - takže bila skutečně svoje dítě. Chytrá programátorská matka by to dítě předala hodnotou, čímž by se vytvořila lokální kopie dítěte, kterou by bila, ale po skončení procedury by bité dítě (které ani nikdy v reálu neexistovalo) zmizelo, ale původní dítě by bylo v pořádku (bita byla kopie). A matka by byla vyvztekaná. Poučení - pokud nechcete, aby skutečná data byla poškozena, předejte je hodnotou. Pokud 5

je vysloveně chcete změnit, předávejte je naopak odkazem. Dáme-li jiný případ s dítětem (už ne tak strašlivý), pokud dítě křičí a chce k matce, tak pro matku nemá cenu volat proceduru pohladdite(p:dite) - tedy že se dítě předá hodnotou. Tehdy si matka vytvoří kopii dítěte, kterou pohladí, procedura skončí, kopie dítěte zmizí...a původní dítě pořád řve, protože ho nikdo nepohladil. Chytrá matka zde naopak použije předání odkazem, tedy pohladdite(var p:dite) - a pohlazeno v dané proceduře bude skutečné dítě. 1.6 Několik příkladů Triviální procedura, která vypíše zprávu určenou parametrem a za to ještě vypíše hlášku chválící místního krále (což se hodí třeba když vám král hrozí, že vás popraví, když za každý výpis nenapíšete pochvalu jeho vzhledu a inteligence - pak je riskantní používat obyčejné write a writeln, protože třeba zapomenete tam někde tu pochvalu explicitně nat ukat a...). procedure vypis(s:string); write(s,, nas kral je krasny a chytry ); A ted už složitější program - načte daný počet prvků do pole a všechny výskyty maximálního prvku nahradí nulami. Čeho si všimnout - nového slova const, jak využíváme předání hodnotou a odkazem. A taky divnosti, že když předáte pole odkazem, tak se vám posunou jeho indexy. Zkuste si program projít krok po kroku a uvědomit si, proč a jak funguje. program funkcicky; const N=10; {Pred promennymi lze takto deklarovat konstanty - k cemu to je? Kdyz bych vsude v kodu misto N napsal 10 a pak se rozhodl, ze to vlastne chci pro vetsi ulohu a ma tam misto toho byt 100, tak u vetsiho kodu nebude legrace najit vsechny vyskyty. A kdyz nejaky prehlednete, muze to byt dost peklo. Mimochodem, tuto hodnotu muzete pouzit, jak vidno nize, jako urcovac velikosti pole. } var i:integer; pole:array[1..n] of integer; function maximumvpoli(p:array of integer):integer; {Vsimnete si, ze se nedeklaruje velikost} {Vraci maximalni hodnotu v danem poli. Slo by parametr predat i odkazem, jelikoz puvodni pole nenicime, ale jenom cteme.} var j,max:integer; max:=p[1]; {Prvni prvek prohlasime za maximum} 6

for j:=1 to N do {A projdeme zbyvajici prvky.} if (pole[j]>max) then max:=pole[j]; maximumvpoli:=max; {Vratime maximum v danem poli.} {Kdyz je nejaky prvek vetsi nez dosavadni maximum, prohlasime ho za nove maximum.} procedure vynulujmax(var p:array of integer); {Vsechny vyskyty nejvetsiho cisla v posloupnosti nahradi nulami. Je to tzv. "edukativni" priklad, takze se neptejte, proc by to nekdo chtel delat :)} var k,max:integer; max:=maximumvpoli(p); {To je krasa - uz umime maximum, tak to pouzijeme, vubec neni treba to psat znovu.} for k:=0 to N-1 do if (p[k] = max) then p[k]:=0; end {Kdyz predate pole odkazem, automaticky se posune, ze ma zacatek na nule (tj. z [1..10] to vyrobi [0..9]). Zda se vam to taky tak divne jako mne? Priste si rekneme neco, s cehoz pomoci tento problem obejdeme.} {Az tady zacina vlastni hlavni program.} for i:=1 to N do {Nacteme N cisel} read(pole[i]); writeln(maximumvpoli(pole)); {Jen tak pro cvik si napiseme maximum v poli.} vynulujmax(pole); {Zde probehne vynulovani maxim.} for i:=1 to N do {A vysledne pole vypiseme, abychom videli zmenu.} write(pole[i], ); end. 2 Eratosthenovo síto Na cvičení jsme probrali (a doma naprogramovali) jednoduchý algoritmus testování prvočíselnosti. Není to ale možnost jediná. Dejme tomu, že víme, že program nebude pracovat s větším číslem, než je nějaké N a bude pracovat jen s kladnými čísly. Nebylo by krásné mít pole booleanů, kde by pole[x] bylo TRUE, když x je 7

prvočíslo a FALSE, když není? Tj. např. pro N=10 bychom měli pole obsahující {FALSE,TRUE,TRUE,FALSE,TRUE,FALSE,TRUE,FALSE,FALSE,FALSE}. Odpovím si sám - krásné by to bylo a není těžké si takové pole připravit. Proč to může být lepší než postup, který už znáte? Důvod je jednoduchý - rychlost. Když už takovéto pěkné booleovské pole máme, můžeme zjistit, zdali je číslo prvočíslo, v podstatě okamžitě (podíváme se na příslušný prvek pole). Algoritmus postupného testování dělitelnosti přeci jen chvilku trvá. Jak tedy takové pole vyrobit? Mějme sesláno N. Vytvoříme si pole [1..N] booleanů a vyplníme ho samými TRUE (nejdřív tvrdíme, že vše jsou prvočísla, postupně to budeme u některých čísel falzifikovat); jen na první pozici bude FALSE (1 není prvočísslo). Pak bereme čísla 2,3,...round (N) a z našeho pole booleanů vždy násobky tohoto čísla vyškrtneme (protože jsou dělitelná uvažovaným číslem). Jednonásobek nevyškrtáváme - prvočíslo je sebou samým také dělitelné. Po vyškrtání násobků jednoho čísla vezmeme další číslo a zase vyškrtáváme jeho násobky. Příklad pro N=10: Pole={FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE} Ted (v Pascalu bychom to dělali asi for cyklem) vezmeme 2 a jeho násobky. Dostaneme Pole={FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE} Ted vezmeme 3 a vyškrtáváme (něco už je vyškrtnuté, ale to nevadí), získáme: Pole={FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE} A je hotovo, round(sqrt{10})=3. Argument, proč testujeme jen čísla do odmocniny je zcela obdobný jako v algoritmu postupného dělení - tj. algoritmu testování prvočíselnosti, který jsme měli prve. Už víme, že zjišt ovat, zda je číslo prvočíslo, s pomocí takovéhoto pole, je krása (tzn. je to rychlé). Kde je háček? Háček je v tom, že samozřejmě něco trvá si to pole vyrobit. A vyrobit si Eratosthenovo síto pro nějaké N je pomalejší než libovolné číslo od 1 do N otestovat postupným dělením. Použití takovéhoto síta má smysl v situaci, kdy potřebujeme hodně čísel od 1 do N testovat na prvočíselnost. Protože síto si vyrobíme jen jednou a pak už se ptáme v podstatě zadarmo. 3 Ladění programů Dříve či později se vám stane, že vám program nefunguje a není hned jasné, proč tomu tak je. Propříklad tenhle program řešící úlohu Vyhledávání v setříděném poli vypadá pěkně: program shled; {nacte cislo n a cislo k, pote n cisel setridenych vzestupne. Potom cte k cisel - dotazu. Pr vypise prvni pozici jeho vyskytu v nactene posloupnosti. Pokud cislo v posloupnosti neni, vypise nulu} var pole: array[1..1000000] of integer; m,n,i,k,max,min,c: integer; {dotaz, pocet prvku posloupnosti, index, 8

pocet dotazu, horni mez,dolni mez, stred} read(n); read(k); for i:=1 to n do {nacte n, k a posloupnost} read(pole[i]); for i:=1 to k do min:=1; max:=n; c:=((n+1) div 2); {cte dotazy} read(m); while ((max>=min) and (pole[c]<>m)) do {kontroluje, je-li jeste kde hledat} c:=((max + min) div 2); if pole[c]<m then if min<n then {binarni vyhledavani - pokud je} min:=(c+1); {prvek vetsi, nez c, zvedne minimum} end else {zkoumaneho intervalu, pokud mensi} {snizi maximum} if pole[c]>m then if max>1 then max:=(c-1); if pole[c]=m then {pro nalezeny dotaz snizi index} {vyskytu na minimum a vypise} while pole[c-1]=m do c:=(c-1); write(c, ); if (((pole[c]<>m) and (pole[c]>min) and (pole[c]<max)) or (min>max)) then write( 0 ); {pro nenalezeny dotaz vypise nulu} end. 9

Ten program i leckdy funguje, např. na vstup: 8 1 2 5 6 6 6 8 9 10 6 Ale Codex dá 0 bodů. Ono to taky leckdy nefunguje. Například na 2 : 3 1 1 2 3 1 to spadne s range check error. Asi člověk tuší, že se někde dívá mimo pole. Ale kde? A k tomu právě slouží ladící - debugovací 3 - nástroje. Vytvořte si z výše uvedeného kódu program (FreePascalisté normálně mohou nakopírovat do vývojového prostředí, jino-pascalisté necht uloží kód to textového souboru a změní příponu na.pas - pak soubor můžete normálně načíst z vývojového prostředí). Podívejme se ted na některé prvky menu Run (doporučuji znát jejich klávesové zkratky, je to mnohem menší otrava bušit do F7 než pořád otevírat menu): Trace into: Udělá krok programu - tj. vyhodnotí jeden řádek a přesune vás na další. Pokud voláte podprogram, vleze dovnitř a bude postupovat po řádcích podprogramu. Step over: Velmi podobné jako Trace into, ale neleze dovnitř podprogramů. Continue: Objeví se až při krokování (tj. když program běží). Přesune program na další breakpoint (vizte dále). Go to cursor: Skočí na místo označené kurzorem. To má smysl třeba když nechcete milionkrát mačkat F7 v nějakém výpočetně náročném cyklu a zajímá vás až stav programu po doběhnutí toho cyklu - pak má smysl si kurzor dát za onen while cyklus a dát F4. Takto sice můžeme projít program krok po kroku, ale ještě nám něco chybí... chtěli bychom vidět, co je ve které proměnné (tzn. například kdy se podíváme na pole[0] a proč se to stalo). Od toho nám v menu Debug slouží položka Add Watch. Po kliknutí na to se vám objeví okénko, kam zapíšete proměnnou, jejíž obsah chcete sledovat. Neděste se, že před prvním použítím proměnné tam mohou být zdánlivě nesmysly - zmizí v okamžiku prvního použití. 2 Vymyslet vstup, na kterém vám to spadne je samozřejmě trochu umění a přijde to se zvětšující se zkušeností. 3 Víte proč chyby v počítačích jsou zvány bugy? Pochází to z časů, kdy počítače ještě byly obrovské, přes celé místnosti, či budovy. Kvůli větrání samozřejmě musela místnost/budova větrat. No a někdy dovnitř vletěl brouk - bug - který naletěl do obvodů počítače a způsobil poruchu. 10

Seznam všech sledovaných proměnných a jejich hodnot vyvoláte kliknutím na Debug-Watches. Pomocí watchů a krokování programu už můžete docela jednoduše zjistit, kdy a proč vám program padá. Poslední věc, kterou je vhodné zmínit, jsou tzv. breakpointy. Breakpoint na řádce se zapíná přes Ctrl+F8, případně přes menu Debug a položku Breakpoint. Když dáte breakpoint na řádku a spustíte program, program se na daném místě zastaví (a skrze watche můžete zase sledovat proměnné). Pak můžete zase krokovat pomocí Trace into, Step over atd. Continue v této situaci vás přesune na pozici dalšího breakpointu. 11