Fraktale: Natur und Fälschung

Wer kennt sie nicht, die faszinierenden Bilder eines verblüffend naturgetreuen Farns (Bild 1) oder einer Berglandschaft, erzeugt im Computer. Im folgenden wird gezeigt, wie man solche Gebilde einfach mathematisch beschreiben kann, und ein Verfahren vorgestellt, das diese und andere Bilder mit einem interessanten Algorithmus erzeugt. Dabei wird hauptsächlich auf die deterministischen Fraktale der linearen und nichtlinearen Gruppe eingegangen.

Strukturen wie Farnblätter lassen sich mit den Mitteln der „normalen“ euklidischen Geometrie nur sehr schwer beschreiben. Das ist gerade für Computerbenutzer nichts neues. Hingegen ist es kein Problem, mittels einer relativ kleinen Anzahl von „Linien“-Befehlen ein Haus oder einen Tisch auf den Bildschirm zu zeichnen. Die Beschreibung eines solchen Gegenstandes mit den Elementen der „euklidischen Sprache“ (Punkt, Gerade, Ebene, Kreis, Zylinder, Kegel...) ist also einfach möglich. Diese Elemente der „euklidischen Sprache“ stellt im allgemeinen auch jedes Computer-Zeichenprogramm zur Verfügung.

Möchte man aber einen Baum, ein Blatt oder einen Berg zeichnen , der einigermaßen natürlich aussieht, so benötigt man sehr viele Geraden (Ebenen, Kreise ...), um ein einigermaßen brauchbares Ergebnis zu erzielen, weil diese Dinge eben eigentlich nicht aus Geraden bestehen, sondern natürliche Zacken, Symmetrien und Ähnlichkeiten haben. Um solche Gegenstände zu beschreiben, sind die Elemente der „linearen fraktalen Sprache“ besser geeignet [1]. Wie die Elemente und Regeln aussehen, läßt sich am besten an einem amüsanten (Bei)Spiel erläutern (vgl. „Fractal modelling of real world images“ von Michael F. Barnsley in [2]).

Bild 1: Eine Auswahl an linearen Fraktalen

Das Chaos-Spiel

Dazu nehme man ein Blatt Papier und markiere darauf die Eckpunkte eines beliebig gearteten Dreiecks und nenne sie P"1-2", P"3-4" und P"5-6". Dann wählt man einen beliebigen Punkt (X1) innerhalb dieses Dreiecks aus und markiert ihn. Mit einem Würfel wählt man eine der Ecken entsprechend der gewürfelten Augenzahl aus. In der Mitte der Verbindungslinie zwischen X, und dem Eckpunkt markiert man wiederum einen Punkt (X2). Jetzt wird erneut gewürfelt, und X3 ergibt sich in der Mitte der Verbindungslinie von X2 zum Eckpunkt. Man wiederhole dieses Spiel einige tausend Mal (Tage später...), um genügend Punkte zu erhalten. Dann entferne man die ersten 20 Punkte und betrachte das Ergebnis. Eigentlich würde man erwarten, eine völlig chaotische Ansammlung von Punkten zu erhalten. Es ergibt sich jedoch ein regelmäßiges Muster, das sogenannte Sierpinski-Dreieck (nach dem polnischen Mathematiker Waclaw Sierpinski 1882 bis 1969). Bild 2 zeigt das entstehende Fraktal, wenn man als Eckpunkte ein gleichschenkliges Dreieck wählt.

Bild 2: Hilfreich für das Chaos-Spiel - das Sierpinski-Dreieck

Diese Spielregeln lassen sich relativ einfach mathematisch beschreiben: Einen neuen Punkt Xn+1 erhält man, indem man vom alten Punkt Xn die halbe Weglänge zwischen Xn und dem ausgewürfelten Eckpunkt Pi zurücklegt, also (vgl Bild 3):

Xn+1= Xn + 0.5*(Pi-Xn) (vektoriell)

oder, wenn man die Gleichung umformt und jeweils für die x- und y-Komponente eine getrennte Gleichung angibt:

xn+1 = 0.5xn+0.5pxi
yn+1 = 0-5yn+0.5pyi

Dies läßt sich auch kompakter als eine Gleichung mit Hilfe von Matrix und Vektor darstellen:

oder

xn+1 = A * Xn + bi

Bild 3: Konstruktion der Transformationsgleichung zum Sierpinski-Dreieck

Diese Formel stellt eine einfache lineare Transformation eines Punktes der Ebene im R2 auf einen anderen Punkt der Ebene dar. Da zusätzlich zu den linearen Gewichten in der Matrix A , mit denen der alte Punkt multipliziert wird, noch eine konstante Verschiebung (der Vektor b) hinzukommt, spricht man nicht mehr von einer linearen, sondern von einer affinlinearen Transformation. Es sei noch angemerkt, daß im allgemeinen Fall nicht nur die Vektoren b unterschiedlich sein können (eben bis), sondern genauso auch die Matrizen A (die dann zu Ai s werden).

In unserem Beispiel sind drei Eckpunkte vorhanden, also erhält man drei verschiedene Transformationsgleichungen (T1-T3). Bei Wahl der Eckpunkte entsprechend Bild 3 ergibt sich:

Damit läßt sich unser Chaos-Spiel auch folgendermaßen ausdrücken:

(1) Wähle einen Startpunkt X1.
(2) Wähle aus den n(=3) Transformationen die Transformation i zufällig aus.
(3) Berechne den nächsten Punkt mittels der gewählten Transformationformel: Xn+1 =Ti{Xn}.
(4) Wiederhole ab (2).

Aus programmtechnischen Gründen (man möchte möglichst schnell das Ergebnis sehen) kommt noch eine kleine Erweiterung dazu. Es werden nicht alle Transformationen gleich häufig ausgewählt, sondern jede Transformation enthält eine bestimmte Wahrscheinlichkeit pi, mit der sie auftreten soll. Die pis bestimmen sich aus den Matrizen Ai - wieso, sehen wir später. Mit dieser Erweiterung lautet das Chaos-Spiel:

(1) Bestimme die Wahrscheinlichkeiten pi.
(2) Wähle einen Startpunkt X1.
(3) Wähle aus den n Transformationen die Transformation i mit der Wahrscheinlichkeit pi aus.
(4) Berechne den nächsten Punkt mittels der gewählten Transformationsformel: Xn+1=Ti{Xn}.
(5) Wiederhole ab (3).

Genau diesen Algorithmus in BASIC übersetzt führt die Prozedur CHAOS_SPIEL() im Listing aus. Sie erwartet nr% Transformationsgleichungen in den drei- bzw. zweidimensionalen Feldern a() und b(). Die erste Dimension dieser Felder wählt dabei die Transformationsgleichung aus, in den restlichen Dimensionen stehen die Matrizen A bzw. die Vektoren b. Bleibt noch ks() zu erklären: In diesem 2x2-Feld steht der Bereich der XY-Ebene, der auf dem Bildschirm dargestellt wird. In dieser Prozedur werden die ersten 20 Punkte nicht gezeichnet, da diese Punkte je nach Wahl des Startpunktes unter Umständen noch nicht zu dem Fraktal gehören.

Das liegt daran, daß die entstehende Figur, das Fraktal, ein Attraktor für die angegebenen Transformationen des Chaos-Spiels ist. Das heißt, daß man immer nach einer ausreichenden Anzahl von Iterationen auf einem Punkt dieser Figur landet, egal, mit welchem Punkt man die Iteration beginnt. Um diese „ausreichende Anzahl“ zu erfüllen, werden denn auch die ersten 20 Iteration beim Chaos-Spiel nicht gezeichnet. Ist man erstmal auf dem Attraktor angelangt, so bewegt man sich nur noch darauf und kommt von ihm nicht mehr los.

Die Darstellung mittels Transformationsgleichungen erweist sich als überaus vielseitig. Denn um andere (affin-lineare) Fraktale zu erzeugen, ändert sich an den Spielregeln nichts, nur der Inhalt von A und b sowie die Anzahl der Transformationsgleichungen variiert. Mit vier Transformationsgleichungen und anderen Werten für die Matrizen und Vektoren ergibt sich zum Beispiel das Famblatt aus Bild 1. Auch das Ahomblatt und die Kochkurve im selben Bild sind weitere bekannte Fraktale, die sich auf diese Weise erzeugen lassen (diese Beispiele sind auch bereits im Programm eingebaut).

Die „fraktale Sprache“ - um auf die Einleitung zurückzukommen - besteht also im wesentlichen aus einem Algorithmus, dem „Chaos-Spiel“, der Transformationen rekursiv anwendet. Die Parameter der Transformationen (Inhalte von A und b) bestimmen dabei das endgültige Bild. Mit diesen wenigen Werten, im Beispiel des Sierpinski-Dreiecks nur 18 Zahlen (als Float-Werte z.B 144 Byte), ist also ein sehr kompliziertes Bild festgelegt, das z.B im Screen-Format 32kB benötigt! Damit würde sich die-ses Verfahren gut zur Verringerung der Datenmenge bei Bildübertragungen oder Bildspeicherung eignen (im Beispiel eine Datenkompression von 1:227). Denn es müßten nur noch die wenigen Transformationsgleichungen gespeichert werden, aus denen bei Bedarf das ursprüngliche Bild berechnet werden kann, und nicht mehr das gesamte Bild. Das Problem ist nur (abgesehen von der Rechenzeit), aus einem vorgegebenen Bild , also z.B einer Landschaftsfotografie, einen möglichst kleinen Satz von Transformationsgleichungen T1, T2,... Tn zu extrahieren. Dieses Problem ist noch nicht gelöst, aber einen ersten Ansatz gibt das Collage-Theorem. Damit können für einfache Vorlagen die Transformationsgleichungen bestimmt werden. Doch dazu später mehr.


Komplexe Zahlen

Da die Gleichung x2= -1 in R (den reellen Zahlen) nicht lösbar ist, definiert man eine Zahl i mit der Eigenschaft i2=-1. i heißt „imaginäre Einheit“, und x1=-i und x2=+i stellen somit die Lösungen der obigen Gleichung dar. Eine komplexe Zahl ergibt sich allgemein zu

c = a + i*b , a,b aus R

Die Menge der komplexen Zahlen bezeichnet man mit C. Im obigen Beispiel heißt a „Realteil von c“ [Re(c)], b „Imaginärteil von c“ [Im(c)]. Die einfachen Grundrechenarten lauten im Komplexen:

Addition:       (r+i*s) + (t+i*u) = (r+t) + i* (s+u)
Subtraktion:    (r+i*s) - (t+i*u) = (r-t) + i* (s-u)
Multiplikation: (r+i*s) * (t+i*u) = (r*t-s*u) + i* (r*u+s*t)
Division:       t+i*u   / r+i*s   = (t*r + s*u) / r2+s2 + i* u*r - t*s / r2+s2

Die Darstellung komplexer Zahlen erfolgt in einer Ebene (komplexe Zahlenebene, Gaußsche Zahlenebene), indem man senkrecht zur reellen Achse der „normalen“ Zahlen eine zweite Achse, die imaginäre Achse einführt. Jede komplexe Zahl läßt sich als Vektor dieser Ebene beschreiben. Führt man r als Länge des Vektors ein und bezeichnet mit Φ den Winkel zwischen Vektor und der reellen Achse, erhält man mittels einfacher Trigonometrie (siehe auch Bild):

a = rcos(Φ) b = rsin(Φ)

bzw. aufgelöst nach r und Φ

r = sqr(a2+b2) Φ = arctan(b/a)

Drücken wir nun die komplexe Zahl c mittels r und Φ aus:

c = rcos(Φ) +irsin(Φ) = rexp(i*Φ)

Komplexe Zahlen als Vektoren: Umrechnung zwischen Rechteck (a,b)- und Polar (r)-Koordinaten

Diese Gleichung ist die sogenannte Euler-Beziehung. Die komplexe e-Funktion ist leider nötig, um Wurzeln aus komplexen Zahlen einfach berechnen zu können. Man kann sie in diesem Zusammenhang einfach als abkürzende Schreibweise für den umständlichen Sinus-Cosinus-Ausdruck auffassen. Hat man das geschluckt, muß man nur noch glauben, daß diese Funktion - wie Sinus und Cosinus - die Periode 2n hat. Schreibt man dann

c = a + ib = rexp(i*[ Φ + k*2π]), k = 0,1,2,...

hat sich nichts geändert, denn für alle ganzzahligen Werte von k ergibt sich für die Exponentialfunktion dieselbe komplexe Zahl, da sich das Argument von exp() nur um Vielfache von 2π ändert. Das c ist also auch immer dasselbe.

Will man nun die n-te Wurzel aus c ziehen, kann man die „normalen“ Potenzgesetze anwenden:

Zählt man das k durch (k=0,1,...) und ersetzt die e-Funktion entsprechend der Euler-Beziehung wieder durch Sinus und Cosinus, erhält man:

z0 = r1/nexp(i Φ/n ) (k=0) z1 = r1/nexp(i[ Φ/n + (2π)/n ]) (k=1) z2 = r1/nexp(i[ Φ/n + (4π)/n ]) (k=2) z3 = r1/nexp(i[ Φ/n + (6π)/n ]) (k=3)

usw.

Die vier komplexen vierten Wurzeln von c=16+i*16

z0 heißt Hauptwert der Wurzel aus c. Er läßt sich aus Betrag und Winkel besonders leicht berechnen: man zieht aus dem Betrag die n-te Wurzel und dividiert den Winkel durch n. Man stellt fest, daß sich nach n Werten die Wurzeln wiederholen, also zn=z0, zn+1=z1 usw. Es gibt also genau n n-te Wurzeln einer Zahl, die sich alle nur im Winkel unterscheiden. Sie liegen in der komplexen Zahlenebene also auf einem Kreis mit Radius r1/n; sie stellen die Ecken eines regelmäßigen n-Ecks dar, der erste Eckpunkt ist der Hauptwert der Wurzel.

Als kleines Beispiel (vgl. Bild) wollen wir die vierte Wurzel aus c=16+i*16 berechnen. Dazu stellen wir c erst einmal durch Betrag und Phase dar:

Φ=arctan(b/a)=arctan(1) = π/4

also

c= sqr(512) * exp(i*π/4)

Nun zur vierten Wurzel aus c:

z = c1/4 = 5121/8exp(i[π/16 + k*π/2])

Mit 5121/8=2.18 und durch Aufzählen der k erhalten wir die gesuchten Wurzeln zu

z0 = 2.18exp(i0.196) z1 = 2.18exp(i[0.196+1.571]) z2 = 2.18exp(i[0.196+3.142] z3 = 2.18exp(i[0.196+4.712]) (z4 = 2.18exp(i[0.196+6.283]))

Ersetzt man nun wieder r und Φ durch Real- und Imaginärteil (a und b):

z0 = 2.138 + i0.425 z1 = -0.425 + i2.138 z2 = -2.138 - i0.425 z3 = 0.425 - i2.138 (z4 = 2.138 + i*0.425 = z0)


Der fraktale Kopierer

Betrachtet man noch einmal das Sierpinski-Dreieck in Bild 2, fällt auf, daß dieses Bild offensichtlich aus drei gleichen, halbgroßen Kopien seiner selbst besteht. Das ist nicht verwunderlich, denn die oben gefundenen Transformationsgleichungen beschreiben genau das, wenn man sie etwas anders interpretiert: Anstatt abwechselnd eine Transformationsgleichung nur auf einen Punkt anzuwenden, könnte man alle Punkte des Bildes auf einmal transformieren. Das Bild wird also in x- und y-Richtung um die Hälfte gestaucht (so, wie es die Matrix A angibt) und dann ein Stück verschoben (entsprechend dem Vektor b). Wendet man alle drei Transformationen auf das ursprüngliche Bild an, so erhält man ein neues Bild, das aus drei Kopien (daher „fraktaler Kopierer“) des ursprünglichen Bildes besteht. Dieses Bild kann nun Vorlage für einen weiteren Durchlauf sein, und so erhält man ein Bild mit neun kleinen Kopien des ersten Bildes (usw.). Genau diese Eigenart ist in Bild 2 gut zu erkennen.

Nimmt man also das Sierpinski-Dreieck als Vorlage für den fraktalen Kopierer, erhält man als Ergebnis wieder das Sierpinski-Dreieck. Das ist nun nicht besonders aufregend. Doch wenn man sich erinnert, daß das Fraktal ein Attraktor ist, leuchtet ein, daß es völlig egal ist, mit welcher Vorlage man die Transformation startet! Wenn man das Verfahren genügend oft anwendet, wird sich irgendwann das Bild nicht mehr ändern (wenn man eine endliche Auflösung betrachtet). Das entstandene Bild, das sogenannte Limesbild (Limesbild, weil sich bei weiteren Transformationen nichts mehr ändert, also eine Grenze erreicht ist), ist nur von den Transformationsvorschriften abhängig. Man kann also ein beliebiges Bild nehmen, es einige Male durch den auf „Farn“ eingestellten fraktalen Kopierer schicken, und wird immer das Famblatt als Resultat erhalten. In Bild 4 ist eine Bilderserie, ausgehend von dem ST-COMPUTER-Symbol, gezeigt.

Im Programm wird ein solcher Iterationsschritt von der Prozedur KOPIERER durchgeführt. In bild$ muß das zu transformierende Bild übergeben werden, das Ergebnis erhält man dort auch wieder zurück. Die übrigen Parameter entsprechen denen der Prozedur CHAOS_SPIEL().

Bild 4: So wird die ST-Computer zum Farnblatt (Iterationsstufen 0,1, 3, 5,10, 20)

Kontraktion

Nun wollen wir uns noch einmal kurz mit der Frage befassen, welche Anforderungen die Transformationsgleichungen erfüllen müssen, damit ein Fraktal entsteht, und wie man aus einer gegebenen Vorlage die Transformationsgleichungen bestimmt.

Die Hauptanforderung an die Transformationsgleichungen ist, daß sie kontrahierend sind. Bildlich gesprochen darf beim An wenden des fraktalen Kopierers ein entstehendes Teilbild nicht größer sein als das ursprüngliche Bild. Das leuchtet auch sofort ein, denn sonst würde mit jeder Anwendung der Transformation das Bild immer größer werden. In den Transformationsgleichungen müssen die Koeffizienten von A also immer kleiner oder gleich 1 sein.Mittels der Bedeutung von A kann man sich auch erklären, warum man die Matrix A benutzt, um die Häufigkeit festzusetzen, mit der eine Transformation ausgewählt wird. Denn je größer das Ergebnis einer Transformation im fraktalen Kopierer ist, umso mehr trägt sie zum Gesamtbild bei. Es ist also sinnvoll, eine solche Transformation im Chaos-Spiel häufiger anzuwenden.

Ein gutes Maß, um die Größe einer Abbildung zu bestimmen, stellt der Betrag der Matrix A (die Determinante) dar. Sind alle Determinanten gleich, werden natürlich alle Gleichungen mit der gleichen Wahrscheinlichkeit ausgewählt, so z.B. beim Sierpinski-Dreieck.

Collage-Theorem

Um nun aus einem vorgegeben Bild die Transformationsgleichungen zu bestimmen, versucht man, dieses Bild aus (verkleinerten) Kopien seiner selbst aufzubauen. Dies kann mit Hilfe eines Rechners geschehen, auf dessen Bildschirm das vorgegebene Bild zu sehen ist. Nun versucht man, einen Teil dieses Bildes durch eine verkleinerte Kopie abzudecken, indem man die Größe, Lage und Drehung dieser Kopie solange verändert, bis sie paßt. Aus der Größe, dem Drehwinkel und der Verschiebung kann man dann die erste Transformationsgleichung bestimmen. Dann fügt man nach demselben Verfahren solange weitere Teile zu, bis das gesamte Originalbild vollständig abgedeckt ist. Für jedes Teil erhält man eine weitere Transformationsgleichung; alle Transformationsgleichungen zusammen ergeben dann die Daten für das Chaos-Spiel bzw. den fraktalen Kopierer, aus denen sich das Originalbild wieder erzeugen läßt.

Man erkennt, daß dieses Verfahren doch relativ aufwendig ist und sich schlecht automatisieren läßt. Für das Sierpinski-Dreieck ließen sich die Kopien noch relativ schnell finden, aber bei einem beliebigen Bild mit komplizierterem Inhalt, der mehrere hundert Transformationsgleichungen erfordert, stößt das Verfahren an seine Grenzen.

Nichtlineare Fraktale

Bis jetzt haben wir nur affin-lineare Funktionen als Transformationsvorschriften zugelassen. Läßt man auch nichtlineare Funktionen zu, kann man auch die sehr berühmten Bilder von Julia-Mengen erzeugen (siehe Bild 5). Wer sich schon einmal damit befaßt hat, weiß, daß diese leider nur mit Hilfe komplexer Zahlen beschrieben werden können. Wer sich hierin nicht so firm fühlt, sollte sich zunächst den Kasten über komplexe Zahlen zu Gemüte führen.

Julia-Mengen entstehen nach der schon legendären Iterationsformel

W{z}= w =z2+c (z,c komplex)

Der Bildschirm stellt dabei die z-Ebene dar. Für jeden Punkt der z-Ebene (des Bildschirms) gibt es bei der wiederholten Anwendung von W zwei Möglichkeiten: entweder strebt der Punkt z ins Unendliche oder gegen einen bestimmten Fixpunkt. Die (unendlich schmale) Grenze zwischen beiden Gebieten stellt die Julia-Menge dar. c ist eine Konstante, die im wesentlichen das Aussehen des Bildes bestimmt. Dabei lassen sich zwei Typen von Bildern unterscheiden: Die Julia-Menge ist zusammenhängend, oder sie ist eine „Staubwolke“ aus unendlich vielen nicht zusammenhängenden Punkten (eine Cantor-Menge). Die Unterscheidung führt übrigens zur Mandelbrot-Menge, dem unter dem Namen Apfelmännchen wohl berühmtesten Fraktal: Alle Werte von c, für die die Julia-Menge zusammenhängend ist, gehören zur Mandelbrot-Menge, bilden also das Apfelmännchen.

Doch zurück zu den Julia-Mengen. Programmtechnisch unterscheidet man die beiden Fälle des „Strebens“ von z0 (Startwert) im allgemeinen dadurch, daß man sich eine obere Schranke für z vorgibt und bei z größer dieser Schranke den Startpunkt z0 zu den Unendlichkeits-Strebern zählt. Tritt dieser Fall nach einer vorgegebenen maximalen Anzahl von Iterationen nicht ein, so strebt z0 gegen einen endlichen Fixpunkt. Markiert man die beiden Fälle mit unterschiedlichen Farben auf dem Bildschirm, ergibt sich die übliche Darstellung der Julia-Mengen (Bild 6). Hierbei ist zu beachten, daß nicht nur die eigentliche Julia-Menge (Grenze zwischen den beiden Attraktoren) gezeichnet wird, sondern eine Art Einzugsgebiet, für das der Attraktor Julia-Menge erreicht wird. Die Julia-Menge kann man aber auch anders erhalten. Dazu dreht man die obige Iterationsgleichung für w einfach um, d.h. löst sie sich nach z auf:

z = sqr(w - c) = ( w - c )1/2

Bild 5: Julia-Mengen mittels Chaos-Spiel
Bild 6: Julia-Menge aus Bild 5, erzeugt mit "klassischem" Verfahren

Man erhält zwei Transformationsgleichungen, da es zwei Quadratwurzeln zu einer Zahl gibt:

U1: zn+1 =+ sqr(zn - c) = +( zn - c )1/2 U2: zn+1 =- sqr(zn - c) = -( zn - c )1/2

wobei hier gleich die Rekursion eingesetzt wurde.

Hier sollte (könnte) einem ein Licht aufgehen: Mehrere Transformationsgleichungen, die zudem noch kontrahierend sind - das bietet sich für das Chaos-Spiel bzw. den fraktalen Kopierer geradezu an. Ersetzen wir also die affin-linearen Transformationen von oben durch die neu gefundenen komplexen Formeln, können wir mit demselben Prinzip Julia-Mengen erzeugen. Beispiele hierzu zeigen Bild 5 und Bild 7.

Sieht man sich die oben angegebenen Transformationsgleichungen an, stellt man fest, daß es relativ einfach möglich ist, diese auf beliebige Potenzen zu erweitern. Alle Formeln der Art

w = zn +c (z,c komplex, n natürliche Zahl)

lassen sich durch Umformung in

zn+1 = n sqr(zn - c) = ( zn - c )1/n

mit demselben Prinzip berechnen. Allerdings ist zu berücksichtigen, daß eine komplexe Zahl n unterschiedliche n-te Wurzeln hat (siehe Kasten über komplexe Zahlen). Es gibt dann also n unterschiedliche Transformationsgleichungen. Das n bestimmt die Symmetrie des entstehenden Bildes (Doppelsymmetrie für n=2, Dreifachsymmetrie für n=3 usw).

Im Programm werden diese Berechnungen von den Prozeduren JULIA_SPIEL (das Chaos-Spiel mit Julia-Mengen) bzw. JULlA_KOPIERER (fraktaler Kopierer für Julia-Mengen) durchgeführt. Als Parameter wird der Prozedur JULIA_SPIEL in cre (Realteil von c) bzw. cim (Imaginärteil von c) und exp% (Exponent n) die bestimmenden Parameter der Julia-Menge entsprechend der obigen Formel angegeben. ks() enthält auch hier wieder die Eckpunkte des auf dem Bildschirm dargestellten Koordinatenausschnitts. Die Prozedur JULIA KOPIERER benötigt zusätzlich noch das zu transformierende Bild in dem String screen$ (analog zu KOPIERER).

Bild 7: Die ST-Computer mausert sich zur Julia-Menge (Iterationsstufen 0,1, 3, 6,10,17)

Das Programm

Da wir gerade so schön dabei sind: Das Programm ist in GFA-BASIC 3.5 geschrieben und läuft in der mittleren und hohen Auslösung. Es ist menügesteuert, und somit sollte es selbsterklärend sein, wenn man es einmal zum Laufen gebracht hat.

Die zu verarbeitenden Bilder können im DEGAS-Format geladen und gespeichert werden. Als affin-lineare Transformationen sind im Programm das Sierpinski-Dreieck, die Kochkurve, das Farnblatt und das Ahornblatt implementiert. Man kann aber beliebige andere Fraktale erzeugen, wenn man die Matrizen A und Vektoren b in der Prozedur INIT_TRANSFORMATION einsetzt. Bei den Julia-Mengen kann man sich mit den Parametern für c {cre,cim} und exp% voll austoben (einstellbar im Menüpunkt „Funktion...“). Einige interessante Werte sind in Bild 8 zusammengestellt. Dabei ist es empfehlenswert, sich eine neue Transformation erst einmal mit dem Chaos-Spiel zu betrachten, weil eine Bildtransformation - je nach Bildinhalt - schon mal eine Stunde dauern kann.

Exponent n=6 C(Re-Teil)=-1 C(|m-Teil)=0 Exponent n=2 C(Re-Teil)=-1.13 C(|m-Teil)=0 Exponent n=2 C(Re-Teil)=-0.12 C(|m-Teil)=0.75 Exponent n=3 C(Re-Teil)=-0.685 C(|m-Teil)=0.535 Exponent n=4 C(Re-Teil)=0.56 C(|m-Teil)=0 Exponent n=2 C(Re-Teil)=0.35 C(|m-Teil)=0 Exponent n=3 C(Re-Teil)=0 C(|m-Teil)=0.8

Bild 8: Weitere interessante Parameter für nichtlineare Fractale

Apropos Bildtransformation: Da das neue Bild während der Berechnung auf dem Bildschirm gezeichnet wird, muß die Bildvorlage in einem String (erzeugt mittels SGET) abgelegt sein. Das bedeutet aber, daß die in GFA-BASIC vorhandenen Routinen zum Testen eines Bildschirmpunktes nicht mehr benutzt werden können. Deshalb wurde die Funktion NEXTPIXEL (NEXTPIXEL_MONO, NEXTPIXEL_COLOR) geschrieben, die aus einem String heraus den nächsten gesetzten Bildschirmpunkt bestimmt (vgl. Listing). Diese Funktion ist hinsichtlich der Geschwindigkeit nicht optimiert, aber so ist es möglich, sie relativ leicht in andere Programmiersprachen zu übersetzen.

Zu erwähnen wäre noch das Primitiv-Malprogramm im Menüpunkt „Malen“. Es ist dazu gedacht, einige Skizzen zum Ausprobieren der Transformationen malen zu können, ohne immer das Programm verlassen zu müssen. Hier kann man unterschiedliche Stiftstärken im Menü auswählen, die Zeichenfarbe wird mit den Tasten 0-3 beeinflußt.

Zusammenfassung

In diesem Artikel wurde nur ein sehr kleiner Ausschnitt aus dem faszinierenden Bereich der Fraktale dargestellt, nämlich die deterministischen Fraktale linearer und nichtlinearer Form, erzeugt mittels rekursiver Funktionen (Iterated Function Systems = IFS). Wer Interesse an der Thematik bekommen hat, kann sich mit nachstehend angegebener Literatur weiterbilden. Besonders empfehlenswert ist [2], weil hier neben der relativ verständlichen Darlegung auch viele Programmbeispiele enthalten sind. Leider ist das Buch nicht ganz billig und zudem nur in Englisch erschienen.

Literaturhinweise:

[1] H. Jürgens, H.-O. Peitgen, D. Saupe, „Fraktale - eine neue Sprache für komplexe Strukturen“, Spektrum der Wissenschaft 9/1989.

[2] H.-O. Peitgen, D. Saupe (Hrsg), „The Science of Fractal Images“, Springer-Verlag, 1988.

[3] Benoit B. Mandelbrot, „Die fraktale Geometrie der Natur“, Birkhäuser 1987.

[4] K.-H. Becker, M. Dörfler, „Computergrafische Experimente mit Pascal“, Vieweg 1986

' ------------------------------------------
'               FRACTAL V1.1
'         Fractales einmal anders!
' ------------------------------------------
'          Tobias Blickle 90/91
' ------------------------------------------
'         (c) 1991 MAXON Computer
' ------------------------------------------
'
DIM menu$(60)
DIM decoder%(4)
DIM sierp_a(3,2,2),sierp_b(3,2),sierp_ks(2,2)
DIM koch_a(4,2,2),koch_b(4,2),koch_ks(2,2)
DIM blatt_a(4,2,2),blatt_b(4,2),blatt_ks(2,2)
DIM farn_a(4,2,2),farn_b(4,2),farn_ks(2,2)
DIM komplex_ks(2,2)
DIM det(10)
'
GOSUB aufloesung_bestimmen 
GOSUB global_set_up 
GOSUB mit_transformation 
GOSUB init_raenu
'
DEFMOUSE 0 
DO
    ON MENU 
LOOP 
END
'
PROCEDURE init_menu 
menu_daten:
    DATA "Desk"," über FRACTAL","--------------------",1,2,3,4,5.6,""
    DATA "Datei","—- Bild —-","  laden","  speichern", "---------------", "  Ende", ""
    DATA "Linear","- Chaos-Spiel -","  Sierpinski","  Kochkurve","  Farn","  Ahorn","- Bildtransformation -","  Sierpinski","  Kochkurve","  Farn","  Ahorn",""
    DATA "Julia","  Funktion ...","  Chaos-Spiel", "  Bildtransforraation",""
    DATA "Malen","  Stift 1","  Stift 2","  Stift 3","  Stift 4","  Füllen","  Löschen","","*"
'
RESTORE menu_daten
    i%=0
    REPEAT
        READ menu$(i%)
        INC i%
    UNTIL menu$(i%-1)="*" 
    menu$(i%-1)=""
    SGET screen$
    MENU menu$()
    ON MENU GOSUB menu_auswertung 
RETURN
PROCEDURE menu_auswertung 
    LOCAL i%
    IF menu$(MENU(0))="  Ende"
        END 
    ENDIF
    IF menu$(MENU(0))="  über FRACTAL"
        ALERT 0,"   Fractal V1.1|Fractals einmal anders !| Tobias Blickle 91",1,"ok",i%
    ENDIF
    '
    IF MENU(0)=19 
        CLS
        GOSUB chaos_spiel(3,sierp_a(),sierp_b(),sierp_ks())
        SGET screen$
    ENDIF
    IF MENU(0)=20 
        CLS
        GOSUB chaos_spiel(4,koch_a(),koch_b(),koch_ks())
        SGET screen$
    ENDIF
    IF MENU(0)=21 
        CLS
        GOSUB chaos_spiel(4,farn_a(),farn_b(),farn_ks())
        SGET screen$
    ENDIF
    IF MENU(0)=22 
        CLS
        GOSUB chaos_spiel(4,blatt_a(),blatt_b(),blatt_ks())
        SGET screen$
    ENDIF
    '
    IF MENU(0)=24
        GOSUB kopierer(3,screen$,sierp_a(),sierp_b(),sierp_ks())
    ENDIF
    IF MENU(0)=25
        GOSUB kopierer(4,screen$,koch_a(),koch_b(),koch_ks())
    ENDIF
    IF MENU(0)=26
        GOSUB kopierer(4,screen$,farn_a(),farn_b(),farn_ks())
    ENDIF
    IF MENU(0)=27
        GOSUB kopierer(4,screen$,blatt_a(),blatt_b(),blatt_ks())
    ENDIF
    '
    '
    IF menu$(MENU(0))="  Füllen"
        GOSUB fuellen 
    ENDIF
    IF menu$(MENU(0))="  Stift 1"
        DEFLINE 1,2 
        GOSUB grafik 
    ENDIF
    IF menu$(MENU(0))="  Stift 2"
        DEFLINE 1,4 
        GOSUB grafik 
    ENDIF
    IF menu$(MENU(0))="  Stift 3"
        DEFLINE 1, 6 
        GOSUB grafik 
    ENDIF
    IF menu$(MENU(0))=" Stift 4"
        DEFLINE 1,8 
        GOSUB grafik 
    ENDIF
    IF menu$(MENU(0))=" Löschen"
        ALERT 0,"Soll das Bild wirklich|gelöscht werden ?",1,"Nein|Ja",a%
        IF a%=2 
            CLS
            SGET screen$
        ENDIF
    ENDIF
    '
    IF menu$(MENU(0))="  speichern"
        FILESELECT pfad$+"*."+ext$,"",name$
        GOSUB speichern(name$,screen$)
    ENDIF
    IF menu$(MENU(0))="  laden"
        FILESELECT pfad$+"*."+ext$,"",name$
        GOSUB laden(name$,screen$)
        SPUT screen$
    ENDIF
    '
    IF MENU(0)=30
        GOSUB funktions_parameter(exp%,cre,cim)
    ENDIF
    IF MENU(0)=31 
        CLS
        GOSUB julia_spiel(exp%,cre,cim,komplex_ks())
        SGET screen$
    ENDIF
    IF MENU(0)=32
        GOSUB julia_kopierer(screen$,exp%,cre,cim,komplex_ks())
    ENDIF
    '
    MENU menu$()
    MENU OFF 
RETURN
'
PROCEDURE global_set_up 
    pfad$="\" 
    decoder%(0)=0
    decoder%(1)=3
    decoder%(2)=2 
    decoder%(3)=1 
    komplex_ks(0,0)=-2 
    komplex_ks(0,1)=-1.5 
    komplex_ks(1,0)=2 
    komplex_ks(1,1)=1.5 
    CLS
    SGET screen$ 
    cre$="-1.6" 
    cre=-1 
    cim$="0" 
    cim=0 
    anz$="1" 
    anz%=1 
    exp$="2" 
    exp%=2 
RETURN
PROCEDURE init_transformation
'
transformations_daten:
    ' data-Reihenfolge : a11,a12,a21,a22,b1,b2,xmin,ymin,xmax,ymax
    '
    ' Daten für Koch-Kurve
    DATA 0.3333333,0,0,0.33333333,0,0
    DATA 0.3333333,0,0,0.33333333,0.6666666,0
    DATA 0.1666667,-0.28867,0.28867,0.16666667,0.3333333333,0 
    DATA -0.1666667,0.28867,0.28867,0.16666667,0.6666666667,0 
    DATA 0.0,1,05
    '
    ' Daten für Blutenpflanzenblatt
    DATA 0.64987,-0.013,0.013,0.64987,0.175,0
    DATA 0.64948,-0.026,0.026,0.64948,0.165,0.325
    DATA 0.3182,-0.3182,0.3182,0.3182,0.2,0 
    DATA -0.3182,0.3182,0.3182,0.3182,08,0 
    DATA 0,0,1,1
    '
    ' Daten für Farn 
    DATA 0.0,0,0.17,0,0
    DATA 0.84962,0.0255,-0.0255,0.84962,0,3 
    DATA -0.1554,0.235,0.19583,0.18648,0,1.2 
    DATA 0.1554,-0.235,0.19583,0.18648,0,3 
    DATA -10,0,10,20
    '
    ' Daten für Sierpinski-Dreieck 
    DATA 0.5,0,0,0.5,0,0 
    DATA 0.5,0,0,0.5,0.5,0 
    DATA 0.5,0,0,0.5,0.25,0.5 
    DATA 0,0,1,1
    '
    RESTORE transformatxons_daten 
    read_data(4,koch_a(),koch_b(),koch_ks()) 
    read_data(4,blatt_a(),blatt_b(),blatt_ks()) 
    read_data(4,farn_a(),farn_b(),farn_ks()) 
    read_data(3,sierp_a(),sierp_b(),sierp_ks())
RETURN
PROCEDURE read_data(nr%,VAR a(),b(),ks()) 
    LOCAL i%,j%,k%
    FOR i%=0 TO nr%-l1
        FOR j%=0 TO 1 
            FOR k%=0 TO 1
                READ a(i%,j%,k%)
            NEXT k%
        NEXT j%
        FOR j%=0 TO 1 
            READ b(i%,j%)
        NEXT j%
    NEXT i%
    READ ks(0,0)
    READ ks(0,1)
    READ ks(1,0)
    READ ks(1,1)
RETURN
'
PROCEDURE laden (name$, VAR screen$)
    IF name$<>""
        OPEN "i",#1,nameS 
        d$=INPUT$(2,#1)
        FOR i%=0 TO 15
            hb%=ASC(INPUT$(1,#1)) 
            col%=ASC(INPUTS(1,#1))+256*hb% 
            SETCOLOR i%,col%
        NEXT i%
        BGET #1,V:screen$,32000 
        CLOSE #1 
    ENDIF 
RETURN
PROCEDURE speichern(name$,screen$)
    IF name$<>""
        HIDEM
        OPEN "o",#1,name$
        OUT #1,0 
        OUT #1,res%
        FOR i%=0 TO 15
            OUT #1,PEEK(&HFF8240+2*i%) AND &H7 
            OUT #1,PEEK(&HFF8240+2*i%+1) AND &H77 
        NEXT i%
        BPUT #1,V:screen$,32000 
        CLOSE #1 
        SHOWM 
    ENDIF 
RETURN
PROCEDURE grafik 
    DEFMOUSE 3 
    SPUT screen$
    PAUSE 10 
    REPEAT
        a$=INKEY$
        IF a$<>""
            col%=VAL(a$)
            COLOR col%
            DEFFILL col%
        ENDIF
        IF MOUSEK=1
            LINE MOUSEX,MOUSEY,MOUSEX+1,MOOSEY+1 
        ENDIF 
    UNTIL MOUSEK=2 
    SGET screen$
    DEFMOUSE 0 
    DEFLINE 1,2 
RETURN
PROCEDURE fuellen 
    REPEAT
    UNTIL MOUSEK=0 
    DEFMOUSE 5 
    SPUT screen$ 
    REPEAT
        IF MOUSEK=1
            FILL MOUSEX,MOUSEY 
        ENDIF 
    UNTIL MOUSEK=2 
    SGET screen$ 
    DEFMOUSE 0 
RETURN
' ------------------------------------------
' Die Funktion NEXTPIXEL liefert die Farbe 
' des nächsten gesetzten Bildpunkts 
' und seine Bildschirmkoordinaten in x%,y%.
' Initialisierung mit x%=-1
' Kein weiterer Bildschirmpunkt mehr 
' gesetzt, wenn y%>yres%
' ------------------------------------------
PROCEDURE aufloesung_bestimmen 
    res%=XBIOS(4)
    IF res%=2 
        xres%=640 
        yres%=400 
        ext$="PI3"
    ELSE IF res%=1 
        xres%=640 
        yres%=200 
        ext$="PI2"
    ELSE
        ALERT 3,"FRACTAL läuft nur|in mittlerer oder|hoher Auflösung",1," OK ", dummy 
        END 
    ENDIF 
RETURN
FUNCTION nextpixel(res%,screen$,VAR x%,y%)
    LOCAL col%
    IF y%<yres%
        IF res%=2
            ' Pixelbestimmung für hohe Auflösung 
            col%=FN nextpixel_mono(screen$,x%,y%)
        ELSE
            ' Farbbestimmung für mittlere Auflösung
            col%=FN nextpixel_color(screen$,x%,y%)
        ENDIF
        RETURN col%
    ENDIF 
ENDFUNC
FUNCTION nextpixel_mono(screen$,VAR x%,y%) 
    LOCAL b%,w%,bit% 
    b%=y%*80+(x% DIV 16)*2 
    bit%=14-x% MOD 16 
    IF x%<0 
        bit%=15 
    ENDIF
    w%=DPEEK(V:screen$+b%)
    WHILE (bit%>=0) AND NOT (BTST(w%,bit%))
        DEC bit% 
    WEND
    IF bit%<0 
        REPEAT 
            ADD b%,2
        UNTIL (DPEEK(V:screen$+b%)<>0) OR (b%>32000) 
        bit%=15
        w%=DPEEK(V:screen$+b%)
        WHILE (bit%>=0) AND NOT (BTST(w%,bit%)) 
            DEC bit%
        WEND
    ENDIF
    y%=DIV(b%,80)
    x%=(b%-y%*80)*8+15-bit%
    RETURN 1 
ENDFUNC
FUNCTION nextpixel_color(screen$,VAR x%,y%) 
    LOCAL b%,w1%,w2%,bit%,col% 
    b%=y%*160+(x% DIV 16)*4 
    w1%=DPEEK(V:screen$+b%) 
    w2%=DPEEK(V:screen$+b%+2) 
    bit%=14-x% MOD 16 
    IF x%<0 
        bit%=15 
    ENDIF
    WHILE (bit%>=0) AND NOT (BTST(w1%,bit%) OR BTST(w2%,bit%))
        DEC bit%
    WEND
    IF bit%<0 
        REPEAT 
            bft=b%+4
        UNTIL DPEEK(V: screen$+b%)<>0 OR DPEEK(V:screen$+b%+2)<>0 OR b%>32000 
        bit%=15
        w1%=DPEEK(V:screen$+b%) 
        w2%=DPEEK(V:screen$+b%+2)
        WHILE (bit%>=0) AND NOT (BTST(w1%,bit%) OR BTST(w2%,bit%))
            DEC bit%
        WEND
    ENDIF
    y%=DIV(b%, 160)
    x%=(b%-160*y%+4)*4-bit%-1
    col*=decoder%(-2*BTST(w1%,bit%)-BTST(w2%,bit%))
    RETURN col%
ENDFUNC

' ------------------------------------------
'  Lineare affine Transformation :
'
'  Fi (x, y)=A*(x,y)+b (Vektoriell)
'  i=1,...,nr%
'  Sichtbarer Ausschnitt entsprechend ks()
' ------------------------------------------

PROCEDURE chaos_spiel(nr%,VAR a(),b(),ks()) 
    LOCAL x_n,y_n,zufall,zufalls_zahl,zufall_cnt,x,y,cnt%,i%,detsum
    '
    ' Determinanten der einzelnen
    ' Transformationsmatrizen bestimmen 
    detsum=0
    FOR i%=0 TO nr%-1
        det(i%)=ABS(a(i%,0,0)*a(i%,1,1)-a(i%,0,1)*a(i%,1,0)+0.01) 
        detsum=detsum+det(i%)
    NEXT i%
    '
    ' Startwerte für x und y wählen (beliebig!) 
    x=0.5 
    y=0.5 
    cnt%=0
    DEFMOUSE 2
    '
    ' Transformationen durchführen, bis man keine Lust mehr hat 
    WHILE INKEY$="" AND MOUSEK<>2
        '
        ' Eine Transformation mit gewichteter Wahrscheinlichkeit auswählen 
        zufalls_zahl=RND(0) 
        zufall_cnt=0 
        zufall=-1
        REPEAT
            INC zufall
            ADD zufall_cnt,det(zufall)/detsum 
        UNTIL zufall_cnt>=zufalls_zahl OR zufall=nr%
        '
        ' Zufallszahl "zufall" aus [0 ... nr%-1] ausgewählt
        '
        ' Transformation "zufall" ausrechnen 
        x_n=a(zufall,0,0)*x+a(zufall,0,1)*y+b(zufall,0) 
        y_n=a(zufall,1,0)*x+a(zufall,1,1)*y+b(zufall,1) 
        x=x_n 
        y=y_n 
        IF cnt%>20
            PLOT INT((x-ks(0,0))*xres%/(ks(1,0)-ks(0,0))+0.5),yres%-1-INT((y-ks(0,1))*yres%/(ks(1,1)-ks(0,1))+0.5) 
        ENDIF 
        INC cnt% 
    WEND
    DEFMOUSE 0
    ALERT 0,"Abbruch nach "+STR$(cnt%-100)+" Iterationen. ",1," Menu ",dummy%
RETURN
PROCEDURE kopierer(nr%,VAR bild$,a(),b(),ks())
    LOCAL x%,y%     !Koordinaten des Ausgangsbildes in Pixel 
    LOCAL x,y       !Koordinaten des Ausgangsbildes reell 
    LOCAL x_,y_     !Transformierte Koordinaten, reell 
    LOCAL x_%,y_%   !Transformierte Koordinaten, in Pixel
    CLS
    DEFMOUSE 2
    x%=-1   !Startwerte fur NEXTPIXEL 
    y%=0
    '
    COLOR FN nextpixel(res%,bild$,x%,y%)
    WHILE y%<yres%
        '
        ' Pixelkoordinaten in reelle Koordinaten umrechnen 
        x=(ks(1,0)-ks(0,0))/xres%*x%+ks(0,0)
        y=(ks(1,1)-ks(0,1))/yres%*(yres%-1-y%)+ks(0,1)
        FOR i%=0 TO nr%-1
            '
            ' Transformation durchführen 
            x_=a(i%,0,0)*x+a(i%,0,1)*y+b(i%,0) 
            y_=a(i%,1,0)*x+a(i%,1,1)*y+b(i%,1)
            '
            ' x,y wieder in Pixelkoordinaten umrechnen
            x_%=INT((x_-ks(0,0))*xres%/(ks(1,0)-ks(0,0))+0.5) 
            y_%=yres%-l-INT((y_-ks(0,1))*yres%/(ks(1,1)-ks(0,1))+0.5)
            PLOT x_%,y_%
        NEXT i%
        COLOR FN nextpixel(res%,bild$,x%,yft) 
    WEND
    DEFMOUSE 0 
    SGET bild$
RETURN
'
' Führt die Transformationen in der Komplexen Z-Ebene durch 
' für Funktionen der Art:
'       w = z^(exp%) + c
' durch Auflösen in <exp%> verschxedene Wurzeln:
'           z(n+1) = (z(n)-c)^(1/exp%)
'
' Sichtbarer Ausschnitt entsprechend ks()
' -----------------------------------------
PROCEDURE julia_kopierer(VAR screen$,exp%,cre,cim, ks()) !Bildtransformation 
    LOCAL i%,x,y,r,phi 
    CLS
    DEFMOUSE 2 
    x%=1 
    y%=0
    COLOR FN nextpixel(res%,screen$,x%,y%) 
    WHILE y%<yres%
        ' Pixelkoordinaten in komplexe Koordinaten umrechnen 
        x=(ks(1,0)-ks(0,0))/xres%*x%+ks(0,0) 
        y=(ks(1,1)-ks(0,1))/yres%*(yres%-1-y%)+ks(0,1)
        '
        ' Transformation
        GOSUB recht_polar(x-cre,y-cim,r,phi)
        r=r^(1/exp%)
        phi=phi/exp%
        FOR i%=0 TO exp%-1
            GOSUB polar_recht(r/phi+i%/exp%*2*PI,x_, y_)
            '
            ' x,y wieder in Pixelkoordxnaten umrechnen 
            x_%=INT((x_-ks(0,0))*xres%/(ks(1,0)-ks(0,0))+0.5) 
            y_%=yres%-1-INT((y_-ks(0,1))*yres%/(ks(1,1)-ks(0,1))+0.5)
            PLOT x_%,y_%
        NEXT i%
        COLOR FN nextpixel(res%,screen$,x%,y%) 
    WEND
    DEFMOUSE 0 
    SGET screen$
RETURN
PROCEDURE julia_spiel(exp%,cre,cim,VAR ks()) ! Chaos-Spiel 
    LOCAL x_n,y_n,zufall x,y 
    CLS
    DEFMOUSE 2 
    cnt%=0 
    x=0.1 
    y=0
    COLOR 1
    WHILE INKEY$="" AND MOUSEK<>2
        GOSUB recht_polar(x-cre,y-cim,r,phx) 
        zufall=INT(exp%*RND(0)+0.5) 
        polar_recht(r^(1/exp%),phi/exp%+zufall/exp%*2*PI,x,y)
        IF cnt%>100
            PLOT INT((x-ks(0,0))*xres%/(ks(1,0)-ks(0,0))+0.5),yres*-1-INT((y-ks(0,1))*yres%/(ks(1,1)-ks(0,1))+0.5) 
        ENDIF 
        INC cnt%
    WEND
    DEFMOUSE 0
    ALERT 0,"Abbruch nach "+STR$(cnt%-100)+" Iterationen. ",1," Menu ",dummy%
RETURN
PROCEDURE funktions_parameter(VAR exp%,cre,cim)
    PRINT AT(2,2)
    PRINT "Exponent  :";
    FORM INPUT 10 AS exp$
    PRINT "Real-Teil :";
    FORM INPUT 10 AS cre$
    PRINT "Imgainär-Teil :";
    FORM INPUT 10 AS cim$ 
    cre=VAL(cre$) 
    cim=VAL(cim$) 
    exp%=INT(VAL(exp$))
    SPUT screen$
RETURN
'
' Komplexe Funktionen 
PROCEDURE recht_polar(re,xm,VAR r,phi) 
    r=SQR(im*im+re*re)
    IF re=0 
        IF im>0 
            phi=PI/2 
        ELSE
            phi=-PI/2
        ENDIF
    ELSE
        phi=ATN(im/re)
        IF re<0 
            IF im>=0 
                phi=phi+PI 
            ELSE
                phi=phi-PI
            ENDIF
        ENDIF
    ENDIF
RETURN
PROCEDURE polar_recht(r,phi,VAR re,im)
    IF phi>2*PI 
        SUB phi,2*PI 
    ENDIF
    re=r*COS(phi) 
    im=r*SIN(phi)
RETURN

Tobias Blickle
Aus: ST-Computer 11 / 1991, Seite 104

Links

Copyright-Bestimmungen: siehe Über diese Seite