Universität des Saarlandes Fakultät 6.2 – Informatik Theoretische Informatik (WS 2015) Team der Tutoren Aufgaben aus den Übungsgruppen 6(Lösungsvorschläge) Aufgabe 6.1 (Divergenz) Entwerfen Sie eine Registermaschine, die divergiert. Lösungsvorschlag 6.1 L1 : L2 : STOP: x1 = 0 goto L2 i f ( x1 =? 0 ) then goto L1 e l s e goto STOP Aufgabe 6.2 (Einfache Registermaschinen) Entwerfen Sie einfache Registermaschinen, die die folgenden Funktionen berechnen: ( 0 falls x = 0 1. sgn : N → N, sgn(x) = 1 falls x > 0 ( 0 falls x ≤ y 2 2. grtr : N → N, grtr(x, y) = 1 falls x > y ( x falls 3 | x 3. div3 : N → N, div3(x) = 3 ⊥ falls 3 - x Hierbei bedeutet ⊥, dass die Funktion divergiert. Quelle: Vertiefungsvorlesung „Recursion Theory“, Universität des Saarlandes, Sommersemester 2015, Übungsblatt 1 Lösungsvorschlag 6.2 1. L1 : L2 : L3 : L4 : STOP: if x1 if x1 ( x1 =? = x1−1 ( x1 =? = x1+1 0 ) then goto STOP e l s e goto L2 goto L3 0 ) then goto L4 e l s e goto L2 goto STOP 2. Idee: Input (x, y), dekrementiere x und x, bis (x0 , 0) erreicht wird. Gebe 1 zurück, wenn x0 > 0 CHECK1: CHECK2: DEC1 : DEC2 : SET1 : SET2 : L1 : STOP: if if x1 x2 x1 if x1 ( x2 =? ( x1 =? = x1−1 = x2−1 = x1−1 ( x1 =? = x1+1 0 ) then goto CHECK2 e l s e goto DEC1 0 ) then goto STOP e l s e goto SET1 goto DEC2 goto CHECK1 goto SET2 0 ) then goto L1 e l s e goto SET1 goto STOP 3. CHECK1: i f ( x1 =? 0 ) then goto TRANSF e l s e goto DEC1 DEC1 : x1 = x1−1 goto CHECK2 CHECK2: i f ( x1 =? 0 ) then goto UNDEF e l s e goto DEC2 1/6 DEC2 : CHECK3: DEC3 : GOT3: UNDEF: TRANSF: T1 : T2 : STOP: x1 = x1−1 goto CHECK3 i f ( x1 =? 0 ) then goto UNDEF e l s e goto DEC3 x1 = x1−1 goto GOT3 x2 = x2+1 goto CHECK1 goto UNDEF i f ( x2 =? 0 ) then goto STOP e l s e goto T1 x2 = x2−1 goto T2 x1 = x1+1 goto TRANSF Aufgabe 6.3 (Syntaktischer Zucker: Prädikate) Bisher können wir in Anweisungen der Form L: if P then A else B nur Ps der Form a =? b verwenden. Simulieren Sie Anweisungen der Form: 1. if x ≥ y then A else B 2. if x > y then A else B 3. if x 6= y then A else B Lösungsvorschlag 6.3 1. Größer L1 : xi = y − x goto L2 L2 : i f xi = 0 then A goto NextLine e l s e B goto NextLine NextLine : 2. Größer-gleich L0 : xi = y + 1 goto L2 L2 : i f x ≥ xi then A goto NextLine e l s e B goto NextLine NextLine : 3. Ungleich L1 : i f x > y then ( t u n i x ) goto L2 e l s e B goto NextLine L2 : i f ( y > x ) then A goto NextLine e l s e B goto NextLine NextLine : Aufgabe 6.4 (Syntaktischer Zucker: Schleifen) Zeigen Sie, dass f or-Schleifen mit Registermaschinen simuliert werden können. Hierbei soll sich L1 : BODY1: .. . BODYn: L2 : L3 : f o r xi do ... ... od wie folgt verhalten: Sei der Registerinhalt von xi durch j gegeben. Dann soll der Rumpf der f or-Schleife (hier gegeben durch die Label BODY1 bis BODYn) genau j-mal ausgeführt werden. Insbesondere ist die Anzahl der Wiederholungen nicht abhängig von Änderungen des Registerinhaltes von xi . Anschließend wird mit der Ausführung am Label L3 fortgefahren. Lösungsvorschlag 6.4 Wir stellen f or-Schleifen wie folgt in Registermaschinen-Code dar. Sei hierbei xk ein bisher nicht genutztes Register. Der Sprung goto L2 im Rumpf der Schleife (also der Sprung, der die Schleife beendet) wird ersetzt durch goto DEC. Den Sprung zu FIN könnte man auch direkt mit dem Sprung zu L3 verknüpfen, wir nutzen ihn aber zur besseren Verständlichkeit. L1 : xk = x1 goto CHECK 2/6 CHECK: BODY1: .. . i f ( xk =? 0 ) then goto FIN e l s e goto BODY1 ... BODY2: DEC: FIN : L3 : ... xk = xk−1 goto CHECK goto L3 Aufgabe 6.5 (Syntaktischer Zucker: Schleifen die Zweite) Zeigen Sie, dass while-Schleifen mit Registermaschinen simuliert werden können. Hierbei soll sich L1 : BODY1: .. . BODYn: L2 : while ( xi 6= 0 ) do ... ... od wie folgt verhalten: Sei der Registerinhalt von xi durch j gegeben. Dann soll der Rumpf der while-Schleife (hier gegeben durch die Label BODY1 bis BODYn) so lange ausgeführt werden, bis der Registerinhalt von xi 0 ist. Insbesondere ist die Anzahl der Wiederholungen abhängig von Änderungen des Registerinhaltes von xi . Anschließend wird mit der Ausführung am Label L3 fortgefahren. Lösungsvorschlag 6.5 Wir können while-Schleifen nahezu genau so, wie f or-Schleifen in Registermaschinen-Code darstellen: Wir streichen L1, prüfen in CHECK x1 auf 0 statt xk und streichen DEC. Dementsprechend muss der Sprung nach DEC durch einen direkten Sprung zu CHECK ersetzt werden. Aufgabe 6.6 (Syntaktischer Zucker: Funktionsaufrufe) Aus Programmiersprachen wie SML oder Java kennen Sie die Möglichkeit Prozeduren/Methoden zu definieren, die sie dann später in weiteren Programmen verwenden können. Diese Möglichkeit möchten wir auch für Registermaschinen haben. Entwerfen Sie eine Methode um Aufrufe der Form: Funkionsname ( arg1 , arg2 , . . . , argn ) mit einer Registermaschine zu simulieren. Lösungsvorschlag 6.6 Sei m das größte genutzte Register im Hauptprogramm und n das größte genutzte Register in der aufgerufenen Prozedur. Schreibe nun jeweils argi in das Register m + i. Füge danach den Code der Prozedur hinten an, wobei jedes vorkommen des Registers j durch m + j + 1 ersetzt wird. Namen von Labeln werden konsisten in neue Label umbenannt. Zum Schluss wird das Ergebnis des Funktionsaufrufs in das gewünschte Zielregister geschrieben. Aufgabe 6.7 (Bekanntes in neuem Licht) Ein Stack ist eine Datenstruktur mit folgenden Operationen: push(S, x): Auf S wird das Element x gelegt. pull(S): Das oberste Element von S wird entfernt. Ist S leer, so bleibt S unverändert. top(S): Das oberste Element von S wird zurückgegeben. isEmpty(S): Gibt 1 zurück, falls S leer ist, und 0 sonst. Implementieren Sie diese vier Operationen mit Hilfe von Registermaschinen. Hinweis: Alle Elemente eines Stacks sind natürliche Zahlen. Wir stellen einen Stack mit Hilfe der cantorschen Paarungsfunktion dar. Sei f die bijketive Funktion, die ein Tupel (a, b) auf eine natürliche Zahl n ∈ N abbildet (d.h. insbesondere, dass fa−1 und fb−1 existieren, wobei fa−1 (n) = a und fb−1 (n) = b). Durch wiederholtes Anwenden von f können wir so den gesamten Stack in einer einzigen Zahl speichern. Besitzt der Stack n Elemente 3/6 x1 , . . . , xn , so werden sie wie folgt gespeichert: f (n, f (xn , f (xn−1 , . . . , f (x1 , 0) . . . ))). An erster Stelle steht also die Größe des Stacks, danach folgen die Elemente. Mit Hilfe von f erhalten wir so eine eindeutige natürliche Zahl als Kodierung für den Stack. Lösungsvorschlag 6.7 push(S, x): L1 : L2 : L3 : L4 : Fin : x3 x4 x1 x1 = fa−1 (S) + 1 goto L2 = fb−1 (S) goto L2 = f (x, x4 ) goto L4 = f (x3 , x1 ) goto FIN pull(S): CHECK: L1 : L2 : L3 : L4 : FIN : i f ( isEmpty(S)=? 1 ) then goto FIN e l s e goto L1 x2 = fa−1 (S) − 1 goto L2 x1 = fb−1 (S) goto L3 x1 = fb−1 (x1 ) goto L4 x1 = f (x2 , x1 ) goto FIN top(S): L1 : L2 : FIN : x2 = fb−1 (S) goto L2 x1 = fa−1 (x2 ) goto FIN isEmpty(S): L1 : TRUE: FALSE : FIN : i f ( fa−1 (S) =? 0 ) then goto TRUE e l s e goto FALSE x1 = 1 goto FIN x1 = 0 goto FIN Aufgabe 6.8 (Und jetzt alles zusammen...) Schreiben Sie nun eine Registermaschine, die Palindrome erkennt. Sie dürfen hierfür alles benutzen, was sie in den vorherigen Aufgaben implementiert haben! Das Zeichen des Wortes, das Sie überprüfen sollen, befinden sich in ASCII-Code (also als Zahl kodiert) auf dem Stack S. Falls es sich beim Wort in S um ein Palindrom handelt, geben Sie 1 zurück, falls nicht, geben sie 0 zurück. Falls der Stack initial leer ist, divergieren Sie. (Viel Spaß beim Genießen des synaktischen Zuckers!) Lösungsvorschlag 6.8 Die Idee ist, den Stack zu kopieren und diese Kopie zu reversieren und dann auf Gleichheit zu prüfen. EMPTY0: EMPTY1: DIVERGE: COPY_STACK0: COPY_STACK1: COPY_STACK2: COPY_STACK3: COPY_STACK4: COPY_STACK5: COPY_STACK6: x1 = isEmpty ( S ) i f ( x1 =? 0 ) then goto DIVERGE e l s e goto GOAHEAD i f ( x1 =? 0 ) then goto CHECK_EMPTY 2 e l s e goto STOP while ( x1 6= 0 ) do x2 = top ( S ) pull (S) push (T, x2 ) push (U, x2 ) x1 = isEmpty ( S ) od 4/6 REVERSE0 : REVERSE1 : REVERSE2 : REVERSE3 : REVERSE4 : REVERSE5 : REVERSE6 : EQUAL0: EQUAL1: EQUAL2: EQUAL3: EQUAL4: EQUAL5: EQUAL6: EQUAL7: EQUAL8: EQUAL9: EQUAL10 : EQUAL11 : EQUAL12 : EQUAL12 : NOTEQUAL: x1 = isEmpty (T) while ( x1 6= 0 ) do x2 = top (T) p u l l (T) push (V, x2 ) x1 = isEmpty (T) od x1 = stackEmpty (U) while ( x1 6= 0 ) do x2 = top (U) x3 = top (V) p u l l (U) p u l l (V) x4 = x2 − x3 x5 = x3 − x2 i f ( x4 = 0 ) then goto EQUAL9 e l s e goto NOTEQUAL i f ( x5 = 0 ) then goto EQUAL10 e l s e goto NOTEQUAL x1 = isEmpty (U) od x0 = 1 goto STOP x0 = 0 STOP: Aufgabe 6.9 (Zum Knobeln: Programmiersprachen) In dieser Aufgabe betrachten wir zwei verschiedene Programmiersprachen, die FOR- und die WHILE-Sprache. Diese sind wie folgt definiert: Beide Sprachen enthalten Variablen x1 , x2 , x3 , . . . und Konstanten 0, 1, 2, . . . . Wir bezeichnen die Menge der Variablen mit V ar und die der Konstanten mit Kon. Einfache Anweisungen haben die folgende Form: (1) xi := xj + xk (2) xi := xj − xk (3) xi := c oder oder wobei xi , xj , xk ∈ V ar und c ∈ Kon. Alle diese Anweisungen verhalten sich erwartungesgemäß. Ein FORProgramm ist entweder eine einfache Anweisung oder eine Anweisung der folgenden Form: (4) for xi do P1 od (5) P1 ; P2 oder wobei xi ∈ V ar und P1 und P2 FOR-Programme darstellen. (5) stellt die Konkatenation zweier Programme dar. Analog können WHILE-Programme definiert werden. Jedoch enthalten sie statt f or-Schleifen while-Schleifen der Form while (xi 6= 0) do P1 od und es können nur WHILE-Programme konkateniert werden. 1. 2. 3. 4. 5. Entwerfen Sie ein FOR-Programm, dass die Funktion grtr aus Aufgabe 6.2 berechnet. Entwerfen Sie ein WHILE-Programm, dass die Funktion div3 aus Aufgabe 6.2 berechnet. Zeigen oder widerlegen Sie: Jedes FOR-Programm kann durch ein WHILE-Programm simuliert werden. Zeigen oder widerlegen Sie: Jedes WHILE-Programm kann durch ein FOR-Programm simuliert werden. Diskutieren Sie: In welchem Verhältnis stehen Registermaschinen, FOR- und WHILE-Programme? Lösungsvorschlag 6.9 1. Wir nehmen an, dass x in Variable x1 und y in Variable x2 steht. x3 = x1 x1 = 0 x2 = x3 − x2 // Berechne x − y f o r ( x2 ) do// F a l l s x−y > 0 i s t , dann wird x1 a u f 1 g e s e t z t x1 = 1 od 2. noch keine Beispiellösung 5/6 3. Es brauchen nur for-Schleifen simuliert zu werden, da alles andere identisch ist. Eine for-Schleife kann durch xj = 0 // xj i s t e i n e neue V a r i a b l e xj = xi + xj xk = 1 // xk i s t e i n e neue V a r i a b l e while ( xj 6= 0 ) do P1 xj = xj − xk od simuliert werden. 4. Nicht jedes While Programm, kann durch ein For-programm simuliert werden, da es WHILE-Programme gibt, die partielle Funktionen berechnen. Das While Programm while ( x1 6= 0 ) do x1 = 1 od berechnet zum Beispiel, eine Funktion, die nur auf dem Argument 0 definiert ist. Da For-Programme immer terminieren, kann dieses While-Programm nicht von einem For-Programm simuliert werden. 5. While Programme und Registermaschinen sind gleichmächitig. For Programme hingegen können weniger berechnen. 6/6
© Copyright 2024 ExpyDoc