Appearance
Julia-Mengen
Mathematische Grundlagen
Komplexe Zahlen
Eine komplexe Zahl z=a+bi setzt sich aus dem Realteil a und dem Imaginärteil b zusammen. ∣z∣=√a2+b2 ist der Betrag von z.
Im Gegensatz zu anderen Programmiersprachen unterstützt Python komplexe Zahlen:
| Beschreibung | Mathematisch | Python |
|---|---|---|
| komplexe Zahl, Variante 1 | 5+4i | 5 + 4j |
| komplexe Zahl, Variante 2 | z=a+bi | z = complex(a, b) |
| Betrag | ∣z∣ | abs(z) |
Folgen
Eine Folge von Zahlen a0,a1,a2,… kann durch eine Anfangswert a0 und eine Funktionsvorschrift a_n+1=f(an) definiert werden. Beispielsweise wird mit
a⋅0=1,an+1=an+2
die Folge der ungeraden natürlichen Zahlen definiert.
Eine Folge heisst beschränkt, wenn die Beträge ihrer Glieder nie grösser als eine festgelegte Schranke S werden:
Beispiel: Wir verwenden die Funktionsvorschrift
an+1=an2
Für die Anfangswerte a0=1 und a0=−1 sind alle weiteren Folgenglieder 1. Für Anfangswerte zwischen −1 und 1 werden die Folgenglieder immer kleiner, für andere Anfangswerte immer grösser.
| Anfangswert | Verhalten | Bedeutung |
|---|---|---|
| ∣a0∣=1 | ∣an∣ bleibt 1 | beschränkt |
| ∣a0∣<1 | ∣an∣ wird immer kleiner | beschränkt |
| ∣a0∣>1 | ∣an∣ wird immer grösser | gegen unendlich |
Folge von komplexen Zahlen
Nun betrachten wir eine Folge von komplexen Zahlen z0,z1,z2,… mit der Funktionsvorschrift zn+1=f(zn)=zn2. Hier können wir das gleiche Verhalten wie oben feststellen: Die Folge ist beschränkt, wenn der Betrag des Anfangswerts nicht grösser als 1 ist:
| Anfangswert | Verhalten | Bedeutung |
|---|---|---|
| ∣z0∣=1 | ∣zn∣ bleibt 1 | beschränkt |
| ∣z0∣<1 | ∣zn∣ wird immer kleiner | beschränkt |
| ∣z0∣>1 | ∣zn∣ wird immer grösser | gegen unendlich |
Die komplexen Zahlen zi können auch als Punkte in der zweidimensionalen Ebene interpretiert werden. Für ∣z0∣=1 bleiben die Punkte auf dem Einheitskreis. Für ∣zi∣<1 gehen die Punkte gegen den Ursprung und für ∣z0∣>1 entfernen sie sich immer weiter davon.

Julia-Menge
Definition: Die Julia-Menge der komplexen Zahl c ist die Menge aller Punkte z0, für welche die Folge mit Startwert z0 und Funktionsvorschrift zn+1=zn2+c beschränkt ist.
Nach dieser Definition ist die Julia-Menge für c=0 der Einheitskreis.
Sobald andere Werte für c gewählt werden, wird die Julia-Menge zu einem Fraktal:

Programmierung
Der Algorithmus für die Darstellung einer Julia-Menge
- Für jedes Pixel des Fensters muss bestimmt werden, ob es zur Juliamenge gehört.
- Dazu müssen die Pixelkoordinaten in komplexe Zahlen umgerechnet werden.
Für jedes Pixel
Um für jedes Pixel eine Operation durchzuführen, verwenden wir zwei verschachtelte for -Schleifen:
python
def zeichneJulia(c):
for x in range(0, WIDTH):
for y in range(0, HEIGHT):
zeichneJuliaPunkt(x, y, c)Koordinatentransformation
Julia-Mengen befinden sich in der Nähe des Ursprungs, im Bereich ∣z∣<1. Um eine Julia-Menge in einem Fenster mit Pixelkoordinaten darzustellen, müssen die Pixelkoordinaten in die komplexe Zahlenebene transformiert werden.

Dazu wird erst der Ursprung in die Mitte des Fensters verschoben, anschliessend wird eine Skalierung vorgenommen. Für die Pixelkoordinaten x und y wird die komplexe Zahl so berechnet:
python
re = (x - WIDTH / 2) / skalierung
im = (y - HEIGHT / 2) / skalierung
z = complex(re, im)Dabei beschreibt skalierung den Radius des Einheitskreises in Pixel.
Näherungsverfahren
Nun muss bestimmt werden, ob die Zahlenfolge für den Startwert z beschränkt ist. Dazu wird ein Näherungsverfahren verwendet: Wir berechnen die ersten N Glieder der Folge. Falls diese den Schwellwert S nicht überschreiten, nehmen wir an, dass die Folge beschränkt ist. Dieses Verfahren wird mit grösserem N immer genauer.

In Python programmieren wir diese Vorgehensweise mit Hilfe einer vorabprüfenden Schleife:
- Setze n auf 0.
- Wiederhole so lange wie n<N und ∣z∣<S:
- berechne das (n+1)-te Element
- erhöhe n um 1.
In Python sieht das so aus:
python
n = 0
while n < N and abs(z) < S:
z = z * z + c
n = n + 1Grafische Darstellung
Ein Pixel repräsentiert eine rechteckige Fläche der komplexen Ebene, welche unendlich viele Punkte enthält. Wir betrachten die Folge aber nur für einen Punkt davon. Es ist unmöglich festzustellen, ob und wie viele Punkte der Julia-Menge in diesem Rechteck liegen. Deshalb behelfen wir uns mit einer weiteren Näherung:
Wir nehmen an, dass mehr Punkte der Juliamenge innerhalb des Pixels liegen, je länger die Folge des untersuchten Punkts innerhalb des Schwelle bleibt. Diese Schätzung stellen wir grafisch als Farbverlauf dar. Je grösser das n, bei welchem die Schwelle überschritten wird, desto dunkler die Farbe.
Der Bereich von 0 bis N muss also auf den Bereich 0 bis 255 abgebildet werden. Die einfachste Variante ist die lineare Abbildung. Bessere Resultate erhält man aber mit der Wurzelfunktion oder dem Logarithmus:
g1(n)=255−255⋅Nn
g2(n)=255−255⋅√N√n
g3(n)=255−255⋅lnNlnn


In Python wird die Umrechnung von n in eine Farbe zum Beispiel folgendermassen programmiert:
python
helligkeit = 255 - int(255 * math.sqrt(n) / math.sqrt(N))
farbe = (helligkeit / 2, helligkeit / 2, helligkeit)Schliesslich muss noch das Pixel gezeichnet werden:
python
screen.draw.rect(Rect(x, y, 1, 1), farbe)Bildschirmfoto
Um ein Bildschirmfoto der aktuellen Zeichnung zu erstellen, wird das Modul pygame benötigt:
python
import pygameMit der folgenden Anweisung wird eine Kopie des aktuellen Fensterinhalts in der Datei julia.png gespeichert:
python
pygame.image.save(screen.surface, "julia.png")Übung mit vorgegebenem Programm
Suchen Sie eine schöne Julia-Menge, indem Sie verschiedene Werte für c ausprobieren. Experimentieren Sie ebenfalls mit dem Wert für N und mit Farbverläufen. Wenn Sie eine passende Darstellung gefunden haben, dann erstellen Sie davon ein Bild in der Grösse 3200×2000 Pixel.
ACHTUNG: Vergessen Sie nicht, den Wert von SCALE entsprechend anzupassen.
python
import math
import pgtrun
import pygame
TITLE = "Juliamenge"
WIDTH = 500
HEIGHT = 500
skalierung = 200
hintergrundfarbe = 255, 255, 255
N = 500
S = 4
def zeichneJuliaPunkt(x, y, c):
re = (x - WIDTH / 2) / skalierung
im = (y - HEIGHT / 2) / skalierung
z = complex(re, im)
n = 0
while n < N and abs(z) < S:
z = z * z + c
n = n + 1
helligkeit = 255 - int(math.sqrt(n) * 255 / math.sqrt(N))
farbe = (helligkeit / 2, helligkeit / 2, helligkeit)
screen.draw.rect(Rect(x, y, 1, 1), farbe)
def zeichneJulia(c):
for x in range(0, WIDTH):
for y in range(0, HEIGHT):
zeichneJuliaPunkt(x, y, c)
def draw():
screen.fill(hintergrundfarbe)
zeichneJulia(-0.1 + 0.651j)
pygame.image.save(screen.surface, "julia.png")
pgtrun.go()