ϵ">]>
3. CVIČENIE Z PREDMETU ÚVOD DO DEKLARATÍVNEHO PROGRAMOVANIA 2013/2014
ČASŤ B
http://dai.fmph.uniba.sk/courses/udp/ex/ex03.zip
Dátum: 4. a 5. 3. 2014
Odporúčaná verzia CL: 5.81.20
WWW stránka predmetu: http://dai.fmph.uniba.sk/courses/udp
Kontakt: udp(zavináč)lists.dai.fmph.uniba.sk
Úvodná poznámka. Toto cvičenie je venované priraďujúcim diskrimináciám (ex03a) a chvostovej rekurzii (ex03b).
Literatúra.
[1] J. Kľuka. Prednášky z Úvodu do deklaratívneho programovania LS 2013/2014.
http://dai.fmph.uniba.sk/courses/udp/udp-prednasky-2014.pdf
[2] D. Guller. Poznámky k prednáškam z CL.
[3] J. Komara and P. J. Voda. Metamathematics of Computer Programming. 2001.
Poznámka. Podrobnejší návod na riešenie nasledujúcich úloh nájdete napríklad v prednáškach [1].
Úlohy označené hviezdičkou riešte v druhom prechode po vyriešení všetkých neoznačených úloh.
Výpočet faktoriálu while cyklom. Funkciu
vypočítame pomocou pythonovského while cyklu nasledovne:
def Fact(n): f = 1 } Fact while n != 0: - f = f*n |_ While_fact n = n-1 | return f -
Úloha. Faktoriál chvostovou rekurziou. Simulujte uvedený while cyklus chvostovorekurzívnou funkciou a použite ju na zadefinovanie funkcie . Pomocný argument nazývame akumulátor.
Ako je naznačené vyššie, funkcia počíta iba cyklus a vrátenie výsledku.
Hlavná funkcia inicializuje akumulátor vhodným volaním funkcie .
Invariant:
Úloha. Umocnenie chvostovou rekurziou. Naprogramujte umocnenie pomocou simulácie while cyklu.
a) Do nasledujúcej poznámky vpíšte fragment pythonovského programu, ktorý vypočíta umocnenie do akumulátora , podobne ako pri faktoriáli.
b) Zadefinujte chvostovorekurzívnu funkciu , ktorá simuluje váš while cyklus, ale nie inicializáciu akumulátora.
Invariant:
(While_exp_inv) |
Efektívny výpočet členov Fibonacciho postupnosti while cyklom. Funkciu pre -tý člen Fibonacciho postupnosti
môžeme efektívne vypočítať pomocou while cyklu s dvoma akumulátormi , , v ktorých si pamätáme dva po sebe nasledujúce členy postupnosti:
def Fib_efficient(n): if n == 0: - return 0 | else: |_ Fib_efficient n = n - 1 # !!! | m = 0 # Fib(0) | d = 1 # Fib(1) - while n != 0: - # m == Fib(i) & d == Fib(i+1) | m1 = d | d1 = m+d | m = m1 |- While_fib d = d1 | # m == Fib(i+1) & d == fib(i+2) | n = n-1 | return d -
Úloha. Efektívny výpočet členov Fibonacciho postupnosti chvostovou rekurziou.
a) Simulujte while cyklus z predchádzajúcej poznámky chvostovorekurzívnu funkciou . Úvodný test a inicializáciu premenných zatiaľ neberte do úvahy.
Invariant:
b) Naprogramujte funkciu , ktorá vykoná úvodný test pythonovského programu a spustí simuláciu while cyklu so správne inicializovanými hodnotami premenných , , .
Úloha. Podobne ako v predchádzajúcej úlohe zadefinujte efektívnu verziu nasledujúcej funkcie chvostovou rekurziou.
a) Do nasledujúcej poznámky vpíšte pythonovský program, ktorý počíta funkciu while cyklom. Výpočet je podobný výpočtu Fibonacciho postupnosti. Program si pamätá 3 po sebe nasledujúce členy postupnosti v akumulátoroch , , .
def F1_efficient(n):
if n == 0:
...
elif n == 1:
...
else:
n = ...
a = ... # F1(0)
b = ... # F1(1)
c = ... # F1(2)
while ...:
# a == F1(i) & b == F1(i+1) & c == F1(i+2)
...
# a == F1(i+1) & b == F1(i+2) & c == F1(i+3)
return c
c) Vo funkcii ošetrite okrajové prípady a odštartujte cyklus so správne inicializovanými premennými.
Faktoriál cyklom for. Faktoriál môžeme počítať aj pomocou pythonovského for cyklu:
def Fact1(n): f = 1 } Fact1 for i in range(1,n+1): - # f == (i-1)! | f = f*i |- For_fact # f == i! | return f -
Úloha. Faktoriál spätnou chvostovou rekurziou. Naprogramujte funkciu využitím pomocnej funkcie .
a) Funkcia simuluje for cyklus z predchádzajúcej poznámky. Zadefinujte ju chvostovou spätnou rekuziou, pri ktorej rekurzívny argument rastie, kým neprekročí hranicu . Uvedomte si, že program
for i in range(1,n+1): TELO
je ekvivalentný programu
i = 1 while i <= n: TELO i = i+1
Úloha. Zadefinujte efektívnu verziu nasledujúcej funkcie využitím spätnej chvostovej rekurzie.
Funkciu môžeme efektívne vypočítať nasledujúcim for cyklom.
def F2_efficient(n): if n == 0: - return 0 | elif n == 1: | return 1 |_ F2_efficient else: | n = n - 2 # !!! | a = 0 # F2(0) | b = 1 # F2(1) - for i in range(0,n+1): - # a = F2(i) & b = F2(i+1) | a1 = b | b1 = a+b+i |_ For_f2 a = a1 | b = b1 | # a = F2(i+1) & c = F2(i+2) | return b -
Simulujte for cyklus pomocnou funkciou zadefinovanou spätnou chvostovou rekurziou.
Invariant:
Úvodné testy, inicializáciu premenných a štart cyklu implementujte v hlavnej funkcii
Úloha. Zadefinujte efektívnu verziu funkcie spätnou chvostovou rekurziou podobne ako v predchádzajúcej úlohe.
Prémiová domáca úloha du03. (2+2 body) Pravidlá pre prémiové domáce úlohy nájdete na http://dai.fmph.uniba.sk/courses/udp#pdu
a) (2 body)
Zadefinujte funkciu tak, aby , ak a zápis čísla v číselnej sústave so základom je palindróm, teda rovnaký pri čítaní zľava doprava aj sprava doľava. Inak .
Príklad. , ; (lebo je v dvojkovej sústave 1001 ), ( je 1010).
Návod. Zadefinujte pomocnú chvostovorekurzívnu funkciu, ktorá v akumulátore obráti zápis čísla v sústave so základom .
b) (2 body)
Zistite presný počet rekurzívnych volaní potrebných na výpočet podľa klasickej neefektívnej definície (viď vyššie). Vysvetlite, ako ste k tomuto počtu dospeli.
Návod. Využite techniky, ktoré sme preberali na tomto cvičení.
[CL] Poznámka. Pri výpočte odpovede pomocou CL narazíte na nasledovný problém: Hľadaný počet rekurzívnych volaní je viac ako 30-bitové číslo. Takéto čísla CL normálne zobrazuje v zmiešanom desiatkovo-dyadickom zápise (vysvetlíme neskôr). V iba desiatkovej sústave číslo zobrazíte použitím formátu podľa nasledujúceho príkladu:
123456789*1000000001 = x:N