Verzögerte Evaluation und Streams
Inhaltsverzeichnis |
Hilfsfunktionen
Die folgende Tabelle zeigt ihnen Hilfsfunktionne die Ihnen bei der Arbeit mit streams helfen. Machen Sie sich mit desen Vertraut
| Bezeichnung | Parameter | Beschreibung |
|---|---|---|
| stream-car | stream | Äquivalent zu car nur für streams |
| stream-cons | stream | Äquivalent zu car nur für streams |
| stream? | parameter | Testet ob der parameter ein Stream ist |
| make-stream | seed proc | gibt einen neuen stream mit den Anfngswert seed und der zu funktion proc zum berechnen der Folgeglieder |
| stream->list | stream n | gibt eine Liste der ersten n Glieder des Streams |
| stream-item | stream n | gibt das n. Element eines Streams aus |
| stream-map | funktion stream | gibt einen Stream zurück bei dem die Funktion auf alle glieder des Streams angewendet wird |
Desweiteren sind folgende Definitionen als Hilfestellung gegeben:
<eval>(stream->list integers 10)</eval>
Delay und Force
Machen Sie sich mit den Sprachelementen delay und force vertraut. Diskutieren Sie zu zweit darüber, warum streams in Scheme als Paar dargestellt werden und die Verbindung zu den eben genannten Sprachelementen.
Schreiben Sie eine Prozedur stream+, welche zwei streams mit Zahlen als Parameter nimmt und deren Werte paarweise bis zum n-ten Element addiert und als Liste zurückgibt.
Aufrufbeispiel: > (stream->list (stream+ integers integers) 5) 0, 2, 4, 6, 8, ...
<eval>(stream->list (stream+ integers integers) 5)</eval>
Zahlenfolgen
In den folgenden Aufgaben wird es um Zahlenfolgen gehen. Folgende zwei Zahlenfolgen sind gegeben:
(a von n)
$(a_{n})=\frac{1}{\sqrt{2 + \textcolor{red} {0}}}, {\frac{1}{\sqrt{2 + {\frac{1}{\sqrt{2 + 0}}} }}}, {\frac{1}{\sqrt{2 + {\frac{1}{\sqrt{2 + \frac{1}{\sqrt{2 + 0 }}} }}} }}$(b von n)
$(b_{n})=\frac{1}{\sqrt{1 + \color{red} {0}}}, {\frac{1}{1 + {\frac{1}{1 + 0}} }}, {\frac{1}{1 + {\frac{1}{1 + \frac{1}{1 + 0 }}} } }$Es gibt in diesen Zahlenfolgen einen “Fortschritt”. Versuchen Sie das Erzeugungsmuster nachzuvollziehen. Hinweis: aus eigener Erfahrung weiß ich, dass es oft hilfreich ist beim Programmieren einen Zettel und einen Stift parat zu haben, um sich einige Gedankengänge zu notieren (es kommt manchmal vor, dass man eine gute Idee hat und eine Minute später wieder vergessen hat)!
Implementation
Implementieren Sie nun die beiden Zahlenfolgen von oben in Scheme mit Hilfe von Streams und Rekursion. Aufrufbeispiel für $(a_{n}):
> (define an (an-stream-maker 0))) > (stream->list an 5) 0.7071067811865475, 0.6077812620656623, 0.6192477250610301,0.6178907764054561, 0.6180508933676908, ...
<eval> (define an (an-stream-maker 0))) (stream->list an 5) </eval>
Aufrufbeispiel für $(a_{n}):
> (define bn (bn-stream-maker 0))) > (stream->list bn 5) 1, 1/2, 2/3, 3/5, 5/8, ...
<eval> (define bn (bn-stream-maker 0))) (stream->list bn 5) </eval>
grenzwert
Schreiben Sie eine Prozedur grenzwert, die den Grenzwert einer Zahlenfolge bestimmt.
Diese soll wie folgt aussehen:
( grenzwert stm eps max )
Genauer gesagt soll diese Prozedur den Grenzwert einer als Stream repräsentierten Zahlenfolge stm zurückgeben, wenn dieser innerhalb einer hinreichend kleinen ε- Umgebung (eps) liegt. Falls nicht max Folgenglieder in dieser ε-Umgebung liegen, wird Divergenz vermutet und #f zurückgegeben.
Ermitteln und vergleichen Sie die Grenzwerte der Zahlenfolgen (an ) und (bn ).
<eval>;Feld zum testen des Grenzwertes von an und bn</eval>
Testen Sie ihre Grenzwert-Prozedur wenigstens mit folgenden Aufrufbeispielen. (Dabei wird nicht erwartet, dass Sie die Definition von tf wirklich verstehen):
<eval>(grenzwert tf 1/110 10)</eval> <eval>(grenzwert tf 1/110 9)</eval> <eval>(grenzwert tf 1/111 11)</eval> <eval>(grenzwert tf 1/111 10)</eval>
Zahlenfolge
Erstellen sie einen STream der folgende Zahlenfolge implementiert:
$(e_{n})=\frac{1}{0!},\frac{1}{1!},\frac{1}{2!},\frac{1}{3!},\frac{1}{4!},\frac{1}{5!},...,\frac{1}{n!}$Hinweis: 0! = 1
Aufrufbeispiel für $(e_{n})
> (define en (en-stream-maker 0))) > (stream->list en 5) 11, 1, 1/2, 1/6, 1/24, ...
<eval></eval>
Pasu Stream
Schreiben Sie anschließend eine Prozedur pasu-stream, die eine Zahlenfolge als Stream nimmt und die zu dieser Zahlenfolge gehörende Partialsummenfolge als Stream zurückgibt. Falls diese Partialsummenfolge konvergiert, entspricht ihr Grenzwert der Summe der unendlichen Reihe
\sum^\infty \limits_{i=0}\frac{1}{i!}=\frac{1}{0!},\frac{1}{1!},\frac{1}{2!},\frac{1}{3!}...Aufrufbeispiel:
> (stream->list (pasu-stream en) 5) 1, 2, 5/2, 8/3, 65/24, ...
<eval> (stream->list (pasu-stream en) 5)</eval>
Mit Hilfe der Prozeduren grenzwert und pasu-stream kann nun die Summe einer Reihe ermittelt werden. <eval>(grenzwert (pasu-stream en) 1/10 10)</eval> <eval>(grenzwert (pasu-stream en) 1/100 10)</eval> <eval>(grenzwert (pasu-stream en) 1/1000 10)</eval>