Paradigmata programování 1 poznámky k přednášce. 3. Rekurze 1

Podobné dokumenty
Přednáška 3. Rekurze 1

1. Od Scheme k Lispu

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

Paradigmata programování 1

Mgr. et Mgr. Jan Petrov, LL.M. Ph.D. BYZNYS A PRÁVO

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

PARADIGMATA PROGRAMOVÁNÍ 2 PŘÍSLIBY A LÍNÉ VYHODNOCOVÁNÍ

- funkce, které integrujete aproximujte jejich Taylorovými řadami a ty následně zintegrujte. V obou případech vyzkoušejte Taylorovy řady

Informatika 8. třída/6

= - rovnost dvou výrazů, za x můžeme dosazovat různá čísla, tím měníme

Logické programování I

Paradigmata programování 1

Paradigmata programování 1

FUNKCE 2. Autor: Mgr. Dana Kaprálová. Datum (období) tvorby: září, říjen Ročník: sedmý. Vzdělávací oblast: Informatika a výpočetní technika

2.8.6 Čísla iracionální, čísla reálná

Excel Matematické operátory. Excel předdefinované funkce

7. přednáška - třídy, objekty třídy objekty atributy tříd metody tříd

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

Algoritmizace a programování

Vzorce. StatSoft. Vzorce. Kde všude se dá zadat vzorec

Obsahy. Trojúhelník = + + 2

Lekce 01 Úvod do algoritmizace

1 PRVOCISLA: KRATKY UKAZKOVY PRIKLAD NA DEMONSTRACI BALIKU WEB 1

MS EXCEL_vybrané matematické funkce

Paradigmata programování 2

Sada 1 - Základy programování

1.1.3 Práce s kalkulátorem

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

Paměť počítače. alg2 1

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

Vzorová písemka č. 1 (rok 2015/2016) - řešení

Goniometrické rovnice

Příklad 1. Řešení 1a Máme vyšetřit lichost či sudost funkce ŘEŠENÉ PŘÍKLADY Z M1A ČÁST 3

ANALYTICKÁ GEOMETRIE LINEÁRNÍCH ÚTVARŮ V ROVINĚ

V této aplikaci si ukážeme jakým způsobem zobrazovat čas a datum. Pro ovládání zobrazení času a datumu se naučíme využívat nabídku.

INTEGRÁLY S PARAMETREM

Lokální definice (1) plocha-kruhu

Výpočet excentrického klikového mechanismu v systému MAPLE 11 Tomáš Svoboda Technická fakulta Česká Zemědělská Univerzita

Práce s kalkulátorem

NPRG030 Programování I, 2010/11

VY_32_INOVACE_In 6.,7.13 Vzorce vložení funkce

Kapitola 1. Úvod. 1.1 Značení. 1.2 Výroky - opakování. N... přirozená čísla (1, 2, 3,...). Q... racionální čísla ( p, kde p Z a q N) R...

Základní vzorce a funkce v tabulkovém procesoru

1.2.9 Usměrňování zlomků

Paradigmata programování 1

Asymptoty funkce. 5,8 5,98 5,998 5,9998 nelze 6,0002 6,002 6,02 6, nelze

Základy programování (IZP)

VZOROVÝ TEST PRO 3. ROČNÍK (3. A, 5. C)

LEKCE10-RAD Otázky

NPRG030 Programování I, 2016/17 1 / :58:13

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

sin(x) x lim. pomocí mocninné řady pro funkci sin(x) se středem x 0 = 0. Víme, že ( ) k=0 e x2 dx.

Data v počítači. Informační data. Logické hodnoty. Znakové hodnoty

Operátory. Základy programování 1 Martin Kauer (Tomáš Kühr)

Programovací jazyk Pascal

Programy a algoritmy pracující s čísly. IB111 Úvod do programování skrze Python

CZ.1.07/1.5.00/

Výrazy a operátory. Operátory Unární - unární a unární + Např.: a +b

Martin Flusser. Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague. October 17, 2016

Úvod do databázových systémů

5 Přehled operátorů, příkazy, přetypování

Faculty of Nuclear Sciences and Physical Engineering Czech Technical University in Prague

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

Logaritmická rovnice

Gymnázium Vysoké Mýto nám. Vaňorného 163, Vysoké Mýto

KOMPLEXNÍ ČÍSLA INVESTICE DO ROZVOJE VZDĚLÁVÁNÍ

Programování v jazyce JavaScript

Matematická analýza pro informatiky I. Limita posloupnosti (I)

Operátory, výrazy. Tomáš Pitner, upravil Marek Šabo

SEMESTRÁLNÍ PRÁCE Z PŘEDMĚTU MODELOVÁNÍ MATLABEM

15. Goniometrické funkce

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

6. Lineární (ne)rovnice s odmocninou

Programování: základní konstrukce, příklady, aplikace. IB111 Programování a algoritmizace

SPECIÁLNÍCH PRIMITIVNÍCH FUNKCÍ INTEGRACE RACIONÁLNÍCH FUNKCÍ

PRIMITIVNÍ FUNKCE DEFINICE A MOTIVACE

V každém kroku se a + b zmenší o min(a, b), tedy vždy alespoň o 1. Jestliže jsme na začátku dostali 2

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

Algoritmizace Dynamické programování. Jiří Vyskočil, Marko Genyg-Berezovskyj 2010

VZORCE A VÝPOČTY. Autor: Mgr. Dana Kaprálová. Datum (období) tvorby: září, říjen Ročník: sedmý

Bakalářská matematika I

Přednáška 7. Celočíselná aritmetika. Návratový kód. Příkazy pro větvení výpočtu. Cykly. Předčasné ukončení cyklu.

Zákony hromadění chyb.

Logo2 operace, rekurze, větvení výpočtu

M - Kvadratické rovnice a kvadratické nerovnice

55. ročník matematické olympiády

KAPITOLA 9 - POKROČILÁ PRÁCE S TABULKOVÝM PROCESOREM

2.4.9 Rovnice s absolutní hodnotou I

KTE / PPEL Počítačová podpora v elektrotechnice

CVIČNÝ TEST 15. OBSAH I. Cvičný test 2. Mgr. Tomáš Kotler. II. Autorské řešení 6 III. Klíč 15 IV. Záznamový list 17

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

Úvod do informatiky. Miroslav Kolařík

IB015 Neimperativní programování. Organizace a motivace kurzu, programovací jazyk Haskell. Jiří Barnat

Implementace LL(1) překladů

2.8.9 Parametrické rovnice a nerovnice s absolutní hodnotou

Digitální učební materiál

Michal Fusek. 10. přednáška z AMA1. Ústav matematiky FEKT VUT, Michal Fusek 1 / 62

Tabulkové limity. n! lim. n n) n + lim. n + n β = 0. n + a n = 0. lim. (d) Pro α > 0 (tj. libovolně velké) a pro β > 0 (tj.

Obsah. Aplikovaná matematika I. Gottfried Wilhelm Leibniz. Základní vlastnosti a vzorce

V této kapitole si zobecníme dříve probraný pojem limita posloupnosti pro libovolné funkce.

Transkript:

KATEDRA INFORMATIKY UNIVERZITA PALACKÉHO V OLOMOUCI www.inf.upol.cz Michal Krupka krupka.inf.upol.cz michal.krupka@upol.cz 17. listopadu 12, 771 46 Olomouc Paradigmata programování 1 poznámky k přednášce 3. Rekurze 1 1 Příklady Procentuální podíl Procedura percentage-1 počítá procentuální podíl hodnoty parametru part v celku whole: (define (percentage-1 part whole) (* (/ part whole) 100)) Použití: > (percentage-1 20 300) 6 2 3 > (percentage-1 #i20 300) #i6.666666666666667 Řekněme, že chceme, aby celek (hodnota parametru whole) měl nějakou výchozí hodnotu (v našem případě to bude počet obyvatel ČR). Pojmenujeme ji the-whole: (define the-whole 10625449) Aby si uživatel nemusel hodnotu ani její jméno pamatovat, umožníme mu jako druhý argument použít. Význam aplikace procedury s touto hodnotou druhého argumentu bude, že procedura má použít číslo the-whole. Proceduru tedy přizpůsobíme: (define (percentage-2 part whole) (let ((whole (if (eq? whole ) the-whole whole))) (* (/ part whole) 100))) Použili jsme zatím neznámý predikát eq?, který zjišťuje, zda jsou dvě zadané hodnoty totožné: 1

> (eq? 1 1) > (eq? 1 ) #false > (eq? #false #false) Od už známého predikátu = se liší tím, že ten požaduje jako argumenty čísla: > (= 1 ) =: expects a number as 2nd argument, given V proceduře jsme použili speciální operátor let, pomocí kterého jsme zastínili existující vazbu symbolu whole (viz látku z minulé přednášky). Test procedury: > (percentage-2 #i100378 10625449) #i0.9446941959817415 > (percentage-2 #i100378 ) #i0.9446941959817415 Jiná možnost je použít proceduru percentage-1: (define (percentage-3 part whole) (percentage-1 part (if (eq? whole ) the-whole whole))) Stejný test jako u procedury percentage-2 ukáže, že procedura percentage-3 by mohla fungovat: > (percentage-3 #i100378 10625449) #i0.9446941959817415 > (percentage-3 #i100378 ) #i0.9446941959817415 A ještě jedna, nejdůležitější možnost: (define (percentage-4 part whole) (if (eq? whole ) ;je-li whole rovno (percentage-4 part the-whole) ;aplikujeme znovu percentage-4 (* (/ part whole) 100))) ;jinak výpočet 2

(Středníkem začíná komentář, který se nevyhodnocuje.) V těle procedury vidíme rekurzivní aplikaci téže procedury. Informace o vyhodnocovacím procesu z minulých přednášek nám umožní pochopit, jak procedura pracuje. K tomu nám pomůže obrázek prostředí, která se používají během aplikace (percentage-4 100378 ): Počáteční (globální) prostředí symbol hodnota percentage-4 #<procedure:percentage-4>.. Prostředí procedury percentage-4 (první aplikace) symbol hodnota part 100378 whole Prohledávání intervalu Prostředí procedury percentage-4 (druhá aplikace) symbol hodnota part 100378 whole 10625449 Napíšeme proceduru (predikát), která zjistí, zda se mezi danými celými čísly nachází druhá mocnina celého čísla (tzv. čtverec). Budeme potřebovat predikát rozhodující, zda dané celé číslo je čtverec. Ten poznáme podle toho, že jeho odmocnina je celé číslo. Použijeme proceduru sqrt na druhou odmocninu, kterou už známe, a nový predikát integer?, který zjišťuje, zda zadané číslo je celé: > (integer? 10) > (integer? #i10) > (integer? 1/2) #false Teď můžeme napsat první verzi predikátu: (define (square-1? n) (if (integer? (sqrt n)) #false)) 3

Doufám, že jste si všimli, že je zbytečně složitá (takhle programuje začátečník). Jednodušší a správnější je napsat prostě (define (square-2? n) (integer? (sqrt n))) Proceduru by bylo dobré ještě vylepšit, protože takto by vracela nesprávné výsledky, pokud by procedura sqrt počítala odmocninu nepřesně (což by mohla). Bez dalšího vysvětlování uvedu vylepšenou verzi: (define (square-3? n) (= (sqr (round (sqrt n))) n)) A teď k hlavnímu úkolu v tomto příkladu. Množina čísel mezi zadanými dvěma čísly se nazývá interval. V našem příkladě jde ovšem jen o celá čísla. Například mezi čísly 2 a 5 (včetně) najdeme čísla 2, 3, 4, 5. Jde o interval s koncovými body 2 a 5. Tento interval obsahuje čtverec, a to číslo 4. Interval s koncovými body 5 a 5 obsahuje jen číslo 5 (a žádný čtverec), pro koncové body 5 a 4 neobsahuje nic, protože číslo 5 není menší nebo rovno číslu 4. Interval prohledáme tak, že 1. Podíváme se, zda není prázdný. Pokud je, určitě neobsahuje čtverec. 2. Když není prázdný, podíváme se na jeho levý koncový bod. Pokud jde o čtverec, prohledávání bylo úspěšné, procedura může skončit. 3. Levý koncový bod čtvercem není. Vypustíme ho z intervalu a pro nový interval provedeme tutéž činnost. Výslednou proceduru vidíme tady: (define (contains-square-1? a b) (if (> a b) ;když je interval prázdný #false ;čtverec neobsahuje (if (square-2? a) ;je-li dolní konec čtverec ;interval čtverec obsahuje (contains-square-1? (+ a 1) b)))) ;jinak zkoumáme ;interval [a + 1, b] rekurzivní aplikace Jiná varianta téže procedury: 4

(define (contains-square-2? a b) (cond ((> a b) #false) ((square? a) ) ( (contains-square-2? (+ a 1) b)))) Zde jsme použili speciální operátor cond, který používáme při větvení na více než dvě větve. Odbočka: speciální operátor cond větev (cond ( { (> a b) }}{}{{} #false }{{} ) podmínka větve tělo větve } ((square? a) ) další větve ( (contains-square-2? (+ a 1) b))) 1. Postupně se vyhodnocují podmínky větví. 2. Jakmile je nějaká splněna, vyhodnotí se tělo příslušné větve. 3. Další podmínky se nevyhodnocují. 4. Vrátí se výsledek vyhodnoceného těla, pokud žádná podmínka nebyla splněna, dojde k chybě. A ještě jedna varianta stejné procedury, tentokrát s použitím logických spojek. (define (contains-square-3? a b) (and (<= a b) (or (square? a) (contains-square-3? (+ a 1) b)))) Odbočka: speciální operátory and a or, procedura not 5

(and e1 e2... en ) Vrací, pokud se všechny ei vyhodnotí na, jinak vrací #false. Používá zkrácené vyhodnocování : vyhodnocuje (zleva doprava) pouze tolik svých argumentů, aby mohl rozhodnout o výsledku: > (and (= 1 1) (= 1 0) (= (/ 1 0) 0)) #false (or e1 e2... en ) Vrací, pokud se některé ei vyhodnotí na, jinak #false. Používá zkrácené vyhodnocování : > (or (= 2 2) (= (/ 1 0) 0)) Procedura not počítá logickou negaci: > (not (= 1 1)) #false Pevný bod funkce cos Hledáme přibližnou hodnotu čísla x takového, že cos x = x. přesností udělat metodou postupných aproximací : To jde s libovolnou Začneme libovolným číslem x 0 a budeme na ně stále aplikovat funkci cos: x 1 = cos x 0 x 2 = cos x 1 x 3 = cos x 2 x 4 = cos x 3. Budeme získávat čísla, která se budou stále více přibližovat hledané hodnotě. (To je zvláštnost funkce cos; pro jiné funkce to samozřejmě nejde, zkuste si třeba funkci f(x) = x 2.) 6

Matematickými úvahami můžeme zjistit, že pokud je x n+1 x n ɛ (ɛ je zadaná největší přípustná chyba), pak se x n+1 liší od hledaného čísla nejvýše o ɛ a je to tedy dostatečné přiblížení k hledanému číslu. Následující řešení používá na přibližné porovnávání predikát approx-=, který má tři parametry: dvě čísla, která porovnáváme, a požadovanou přesnost (precision). U čísel vypočítá absolutní hodnotu jejich rozdílu (tedy jejich vzdálenost) a výsledek porovná s požadovanou přesností. (define (approx-= a b prec) (<= (abs (- a b)) prec)) Testy: > (approx-= 1 2 0.5) #false > (approx-= 22/7 pi 0.01) Procedura cos-fixpoint-iter vypočítá hledané číslo na základě počáteční hodnoty a požadované přesnosti. Procedura cos-fixpoint je řešením příkladu, používá předchozí proceduru a počátečním bodem 0: (define (cos-fixpoint-iter x prec) (let ((y (cos x))) (if (approx-= x y prec) y (cos-fixpoint-iter y prec)))) (define (cos-fixpoint prec) (cos-fixpoint-iter 0 prec)) Testy: > (cos-fixpoint 0.1) #i0.7013687736227565 > (cos-fixpoint 0.001) #i0.7387603198742112 > (cos-fixpoint 0.00000001) #i0.7390851366465718 > (cos-fixpoint 0.00000000000001) #i0.7390851332151572 > (cos #i0.7390851332151572) #i0.7390851332151629 7

2 Rekurzivní procedury a rekurzivní výpočetní proces Definition 1 (rekurzivní procedura). Procedura je rekurzivní, když ve svém těle obsahuje aplikaci sebe sama. je poznat ze zdrojového kódu procedury procedury percentage-4, contains-square-1?, contains-square-2?, contains-square-3?, cos-fixpoint-iter jsou rekurzivní Definition 2 (rekurzivní výpočetní proces). Výpočetní proces je rekurzivní, když během aplikace procedury dojde znovu k aplikaci téže procedury. je poznat, když program běží některá aplikace procedury by k aplikaci téže procedury vést neměla (ukončovací podmínka) Speciální případ: Definition 3 (iterativní výpočetní proces). Výpočetní proces je iterativní, když na konci aplikace procedury dojde opět k aplikaci téže procedury. uvedené procedury generují iterativní výpočetní proces 3 Další příklady Nyní si ukážeme rekurzivní procedury, které generují rekurzivní výpočetní proces, ale nikoliv iterativní výpočetní proces. Obecná mocnina Na minulém cvičení jsme programovali procedury na umocňování: (define (power2 a) (* a a)) (define (power3 a) (* a (power2 a))) (define (power4 a) (* a (power3 a))) (define (power5 a) (* a (power4 a))) 8

Obecnou (n-tou) mocninu čísla a můžeme vypočítat takto: 1. Je-li n = 0, je výsledkem číslo 1. (To neplatí pro a = 0, ale tuto možnost pomineme.) 2. Je-li n > 0, je výsledkem číslo a a n 1. Napsáno v proceduře: (define (power a n) (if (= n 0) 1 (* a (power a (- n 1))))) Procedura power je rekurzivní a negeneruje iterativní výpočetní proces, protože aplikaci sebe sama neprovádí nakonec (po aplikaci musí výsledek ještě vynásobit číslem a). Faktoriál Jak víme, faktoriál nezáporného celého čísla n je dán tímto předpisem: 1 když n = 0 n! = n (n 1)! když n > 0 Napsáno do procedury: (define (fact-1 n) (if (= n 0) 1 (* n (fact-1 (- n 1))))) Tato verze faktoriálu generuje iterativní výpočetní proces: (define (fact-2-iter n ir) (if (= n 0) ir (fact-2-iter (- n 1) (* ir n)))) (define (fact-2 n) (fact-2-iter n 1)) 9

Výpočet probíhá možná přirozenějším způsobem, než u procedury fact-1, protože kopíruje způsob, jak bychom počítali faktoriál ručně. Například 5! bychom počítali tak, že bychom postupně násobili dvě čísla a pamatovali si mezivýsledky (ir, intermediate result) a čísla, kterými je je třeba ještě vynásobit: krok zbývá vypočítat mezivýsledek 1. 5! 1 2. 4! 5 1 = 5 3. 3! 4 5 = 20 4. 2! 3 20 = 60 5. 1! 2 60 = 120 5. 0! 1 120 = 120 Kontrolní otázky 1. Podívejte se na definici procedury percentage-2. Ve kterém prostředí se při její aplikaci vyhodnocuje výraz (eq? whole ) a ve kterém výraz (/ part whole)? 2. Jaký je rozdíl mezi rekurzivní procedurou a rekurzivním výpočetním procesem? 3. Existuje rekurzivní procedura, která nikdy negeneruje rekurzivní výpočetní proces? 4. Existuje nerekurzivní procedura, která generuje rekurzivní výpočetní proces? Otázky a úkoly na cvičení 1. Obsah elipsy s poloosami a a b je πab. b a Proto jej můžeme vypočítat pomocí následující procedury: (define (ellipse-area-1 a b) (* pi a b)) Když a = b, je elipsa kružnicí. Upravte proceduru tak, aby v takovém případě stačilo místo druhého argumentu zadat. Udělejte to co nejvíce způsoby, jeden z nich by měl být rekurzivní. 10

2. Napište proceduru my-gcd (greatest common divisor; procedura gcd už ve Scheme je), která Eukleidovým algoritmem vypočte největší společný dělitel zadaných dvou přirozených čísel: > (my-gcd 5 3) 1 > (my-gcd 12 8) 4 > (my-gcd 9 24) 3 Jak víme, Eukleidův algoritmus vychází z následujícího poznatku: a jestliže b = 0, gcd(a, b) = gcd(b, c) jinak (c je zbytek po dělení a : b). Na zjištění zbytku po dělení použijte proceduru remainder. 3. Zvolme kladné číslo a. Podobně jako dříve pro funkci cos můžeme metodou postupných aproximací najít pevný bod funkce f dané předpisem f(x) = x + a x. 2 Jak víme, pevným bodem bude číslo x, pro které platí f(x) = x. Zajímavé je, že takovým pevným bodem je číslo a. (K ověření stačí dosadit a do vzorečku; vyjde f( a) = a.) Metodou postupných aproximací tedy v případě této funkce f najdeme odmocninu z čísla a. Napište proceduru heron-sqrt, která metodou postupných aproximací vypočítá odmocninu ze zadaného čísla se zadanou přesností. Přesnost testujte tak, že přibližné číslo umocníte na druhou a porovnáte s a. (Tedy jinak, než jak jsme dělali na prvním cvičení.) 4. Ukažte na příkladě, že kdyby procedura square-2? používala na výpočet odmocniny proceduru heron-sqrt, tak by nemusela vracet správné výsledky. 5. Napište hloupou proceduru na výpočet součtu prvků intervalu celých čísel. 6. Upravte ji tak, aby generovala iterativní výpočetní proces. 7. Upravte proceduru power, aby generovala iterativní výpočetní proces. 8. Číslo π lze s libovolnou přesností vypočítat pomocí Leibnizovy formule: π 4 = 1 1 3 + 1 5 1 7 + 1 9 Dosažená přesnost odhadu čísla π je přitom dána posledním přičítaným (odečítaným) zlomkem. Napište proceduru leibniz, která vypočítá číslo pi se za- 4 danou přesností. Napište jak obyčejnou, tak iterativní verzi této procedury. 11

9. Napište jednoduchou hru na hádání čísel. Počítač náhodně vygeneruje číslo od 1 do 100 a úkolem hráče je číslo co nejrychleji uhodnout. Píše programu své tipy a dostává odpovědi čtyř typů: úspěch, navrhované číslo je příliš malé, navrhované číslo je příliš velké, příliš mnoho pokusů. Program se spustí vyhodnocením (start-game) a může s uživatelem komunikovat například takovými dialogy: Abyste mohli s dialogy pracovat, musíte použít knihovnu. Tu načtete tím, že na začátek vašeho souboru napíšete (require racket/gui/base). Dialog s dotazem vyvoláte procedurou get-text-from-user. Například toto: 12

> (get-text-from-user "Dotaz" "Zadej číslo") otevře dialog a jako výsledek vrátí (ve formě textu) číslo napsané uživatelem. Na převod textu na číslo použijete proceduru string->number, takže k získání čísla od uživatele můžete použít > (string->number (get-text-from-user "Dotaz" "Zadej číslo")) K zobrazení dialogového okna na závěr použijte proceduru message-box: > (message-box "Zpráva" "Příliš mnoho pokusů. Prohrál jsi.") K vygenerování náhodného čísla od 1 do 100 použijte > (+ (random 100) 1) (samotný výraz (random 100) vrací náhodné číslo od 0 do 99). 13