diff --git a/.gitignore b/.gitignore index e257658..bd98b81 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,7 @@ *.out *.app +# Linux executables (keine Endung) +* +!*/ +!*.* diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..a63dca5 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,43 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: g++ build active file", + "command": "/usr/bin/g++", + "args": [ + "-fdiagnostics-color=always", + "-g", + "-std=c++26", + "-pedantic-errors", + "-Wall", + "-Weffc++", + "-Wextra", + "-Wconversion", + "-Wsign-conversion", + "-Werror", + "${fileDirname}/**.cpp", + "-o", + "${fileDirname}/${fileBasenameNoExtension}", + "-lraylib", + "-lGL", + "-lm", + "-lpthread", + "-ldl", + "-lrt", + "-lX11" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "Task generated by Debugger." + } + ], + "version": "2.0.0" +} diff --git a/include/constants.hpp b/include/constants.hpp new file mode 100644 index 0000000..0034932 --- /dev/null +++ b/include/constants.hpp @@ -0,0 +1,11 @@ +#pragma once + +namespace Constants { +constexpr int maxIterations{2000}; +constexpr int windowWidth{600}; +constexpr int windowHeight{600}; +constexpr double posRealRange{3.0}; +constexpr double negRealRange{-3.0}; +constexpr double posImagRange{3.0}; +constexpr double negImagRange{-3.0}; +} // Namespace Constants diff --git a/include/mandelbrot.hpp b/include/mandelbrot.hpp new file mode 100644 index 0000000..fdc75a8 --- /dev/null +++ b/include/mandelbrot.hpp @@ -0,0 +1,3 @@ +#pragma once + +int calculateMandelbrot(double cReal, double cImag); diff --git a/main.cpp b/main.cpp index e69de29..aa62630 100644 --- a/main.cpp +++ b/main.cpp @@ -0,0 +1,57 @@ +#include "include/constants.hpp" +#include "include/mandelbrot.hpp" +#include +#include + +Color LerpColor(Color a, Color b, float t) { + return {(unsigned char)(a.r + (b.r - a.r) * t), + (unsigned char)(a.g + (b.g - a.g) * t), + (unsigned char)(a.b + (b.b - a.b) * t), 255}; +} + +void drawMandelbrot() { + using namespace Constants; + + double xNorm{}; + double yNorm{}; + double cReal{}; + double cImag{}; + + for (int x{}; x <= Constants::windowWidth; ++x) { + for (int y{}; y <= Constants::windowHeight; ++y) { + xNorm = x / static_cast(Constants::windowWidth); + yNorm = y / static_cast(Constants::windowHeight); + + cReal = negRealRange + xNorm * (posRealRange - negRealRange); + cImag = negImagRange + yNorm * (posImagRange - negImagRange); + + int iterationsMandelbrot{calculateMandelbrot(cReal, cImag)}; + + if (iterationsMandelbrot - 1 == maxIterations) { + DrawPixel(x, y, BLACK); + } else { + float t = static_cast(iterationsMandelbrot) / maxIterations; + Color color = LerpColor(BLUE, RED, t); + DrawPixel(x, y, color); + } + // std::cout << "Iterations: " << iterationsMandelbrot << '\n'; + } + } +} + +int main() { + InitWindow(Constants::windowWidth, Constants::windowHeight, + "Mandelbrot Plot"); + SetTargetFPS(60); + + while (!WindowShouldClose()) { // Runs until ESC or window close + + BeginDrawing(); + ClearBackground(RAYWHITE); + drawMandelbrot(); + EndDrawing(); + } + + CloseWindow(); + return 0; +} diff --git a/mandelbrot.cpp b/mandelbrot.cpp new file mode 100644 index 0000000..2ca4240 --- /dev/null +++ b/mandelbrot.cpp @@ -0,0 +1,28 @@ +#include "include/mandelbrot.hpp" +#include "include/constants.hpp" + +int calculateMandelbrot(double cReal, double cImag) { + double zImag{0}; + double zReal{0}; + double zImagNeu{}; + double zRealNeu{}; + double zImagSquared{}; + double zRealSquared{}; + int iterations{}; + + for (; iterations <= Constants::maxIterations; ++iterations) { + zRealSquared = (zReal * zReal); + zImagSquared = (zImag * zImag); + + zRealNeu = zRealSquared - zImagSquared + cReal; + zImagNeu = 2 * zReal * zImag + cImag; + + zReal = zRealNeu; + zImag = zImagNeu; + + if (zRealSquared + zImagSquared > 4) { + break; + } + } + return iterations; +} diff --git a/md/erklärung.md b/md/erklärung.md new file mode 100644 index 0000000..48f801f --- /dev/null +++ b/md/erklärung.md @@ -0,0 +1,684 @@ +# Die Mandelbrot-Menge: Von Null auf Visualisierung + +## 1. Was sind komplexe Zahlen? + +### 1.1 Die imaginäre Einheit + +Normale Zahlen (reelle Zahlen) kennen wir alle: 1, 2, 3.5, -7, π usw. Diese liegen alle auf einem eindimensionalen Zahlenstrahl. + +Komplexe Zahlen erweitern dieses Konzept in die zweite Dimension. Der Trick: Wir erfinden eine neue Zahl namens **i** (die imaginäre Einheit) mit der Eigenschaft: + +``` +i² = -1 +``` + +Das ist zunächst verwirrend, weil keine normale Zahl diese Eigenschaft hat (sowohl 2² = 4 als auch (-2)² = 4). Aber mathematisch können wir mit **i** genauso rechnen wie mit normalen Zahlen. + +### 1.2 Aufbau komplexer Zahlen + +Eine komplexe Zahl besteht aus zwei Teilen: + +``` +z = a + bi +``` + +- **a** = Realteil (eine normale Zahl) +- **b** = Imaginärteil (auch eine normale Zahl) +- **i** = die imaginäre Einheit + +**Beispiele:** +- `3 + 4i` → Realteil: 3, Imaginärteil: 4 +- `2 - 5i` → Realteil: 2, Imaginärteil: -5 +- `7 + 0i = 7` → eine rein reelle Zahl +- `0 + 3i = 3i` → eine rein imaginäre Zahl + +### 1.3 Visualisierung: Die komplexe Ebene + +Statt einem Zahlenstrahl verwenden wir eine Ebene: +- **x-Achse (horizontal)**: Realteil +- **y-Achse (vertikal)**: Imaginärteil + +Die Zahl `3 + 4i` liegt also am Punkt (3, 4) in dieser Ebene. + +``` + Imaginärteil (y) + ↑ + 5 | + 4 | • (3+4i) + 3 | + 2 | + 1 | + 0 |-------|-------|→ Realteil (x) + -1 | 2 4 + -2 | +``` + +### 1.4 Rechnen mit komplexen Zahlen + +#### Addition +Einfach: Addiere Real- und Imaginärteile getrennt. + +``` +(a + bi) + (c + di) = (a + c) + (b + d)i +``` + +**Beispiel:** +``` +(3 + 4i) + (1 + 2i) = (3+1) + (4+2)i = 4 + 6i +``` + +#### Multiplikation +Hier wird's interessanter. Wir multiplizieren wie bei Klammern, aber beachten dass **i² = -1**: + +``` +(a + bi) × (c + di) = ac + adi + bci + bdi² + = ac + adi + bci + bd(-1) + = (ac - bd) + (ad + bc)i +``` + +**Beispiel:** +``` +(3 + 4i) × (1 + 2i) = 3×1 + 3×2i + 4i×1 + 4i×2i + = 3 + 6i + 4i + 8i² + = 3 + 10i + 8×(-1) + = 3 + 10i - 8 + = -5 + 10i +``` + +#### Spezialfall: Quadrieren +Besonders wichtig für die Mandelbrot-Menge ist das Quadrieren: + +``` +(a + bi)² = (a + bi) × (a + bi) + = a² + abi + abi + (bi)² + = a² + 2abi + b²i² + = a² + 2abi - b² + = (a² - b²) + 2abi +``` + +**Merke dir diese Formel:** +``` +(a + bi)² = (a² - b²) + (2ab)i +``` + +**Beispiel:** +``` +(3 + 4i)² = (3² - 4²) + (2×3×4)i + = (9 - 16) + 24i + = -7 + 24i +``` + +### 1.5 Betrag (Abstand vom Ursprung) + +Der Betrag einer komplexen Zahl ist ihr Abstand vom Ursprung (0, 0). Mit dem Satz des Pythagoras: + +``` +|a + bi| = √(a² + b²) +``` + +**Beispiel:** +``` +|3 + 4i| = √(3² + 4²) = √(9 + 16) = √25 = 5 +``` + +In der Ebene visualisiert ist das die Länge des Pfeils vom Ursprung zum Punkt (3, 4). + +--- + +## 2. Die Mandelbrot-Iteration + +### 2.1 Die Grundidee + +Die Mandelbrot-Menge ist eine Menge von komplexen Zahlen **c**, die eine bestimmte Eigenschaft haben. + +Für jede komplexe Zahl **c** führen wir folgende Iteration durch: + +``` +z₀ = 0 +z₁ = z₀² + c = 0² + c = c +z₂ = z₁² + c +z₃ = z₂² + c +z₄ = z₃² + c +... +``` + +**Die Frage:** Bleibt die Folge z₀, z₁, z₂, z₃, ... beschränkt (in der Nähe des Ursprungs), oder explodiert sie gegen unendlich? + +**Definition:** Die Zahl **c** gehört zur Mandelbrot-Menge, wenn die Folge beschränkt bleibt (nicht gegen unendlich geht). + +### 2.2 Beispiel 1: c = 0 + +``` +z₀ = 0 +z₁ = 0² + 0 = 0 +z₂ = 0² + 0 = 0 +z₃ = 0² + 0 = 0 +... +``` + +Die Folge bleibt bei 0. **c = 0 gehört zur Mandelbrot-Menge.** + +### 2.3 Beispiel 2: c = 1 + +``` +z₀ = 0 +z₁ = 0² + 1 = 1 +z₂ = 1² + 1 = 2 +z₃ = 2² + 1 = 5 +z₄ = 5² + 1 = 26 +z₅ = 26² + 1 = 677 +... +``` + +Die Folge explodiert! **c = 1 gehört NICHT zur Mandelbrot-Menge.** + +### 2.4 Beispiel 3: c = -1 + +``` +z₀ = 0 +z₁ = 0² + (-1) = -1 +z₂ = (-1)² + (-1) = 1 - 1 = 0 +z₃ = 0² + (-1) = -1 +z₄ = (-1)² + (-1) = 0 +... +``` + +Die Folge springt zwischen -1 und 0 hin und her. Sie bleibt beschränkt. **c = -1 gehört zur Mandelbrot-Menge.** + +### 2.5 Beispiel 4: c = i (eine komplexe Zahl!) + +``` +z₀ = 0 +z₁ = 0² + i = i +z₂ = i² + i = -1 + i +z₃ = (-1 + i)² + i +``` + +Berechnen wir z₃ mit unserer Quadrierformel (a=-1, b=1): +``` +(-1 + i)² = ((-1)² - 1²) + (2×(-1)×1)i + = (1 - 1) + (-2)i + = -2i + +z₃ = -2i + i = -i +``` + +Weiter: +``` +z₄ = (-i)² + i = (0 + (-1)i)² + i + = (0² - (-1)²) + (2×0×(-1))i + i + = -1 + 0i + i + = -1 + i +``` + +Moment! z₄ = z₂. Die Folge wiederholt sich jetzt: +``` +z₂ = -1 + i +z₃ = -i +z₄ = -1 + i +z₅ = -i +... +``` + +Die Folge bleibt beschränkt (pendelt zwischen zwei Werten). **c = i gehört zur Mandelbrot-Menge.** + +--- + +## 3. Der Algorithmus zur Visualisierung + +### 3.1 Warum nicht unendlich lange testen? + +Wir können nicht unendlich viele Iterationen durchführen. Daher verwenden wir zwei Abbruchkriterien: + +**Kriterium 1: Divergenz erkannt** +Mathematisch bewiesen: Wenn der Betrag von z jemals größer als 2 wird (|z| > 2), dann wird die Folge definitiv gegen unendlich gehen. + +Da |z| = √(real² + imag²) ist, können wir stattdessen prüfen: +``` +real² + imag² > 4 +``` +(Das spart die Wurzelberechnung, weil 2² = 4) + +**Kriterium 2: Maximale Iterationen** +Wir setzen eine Obergrenze, z.B. 100 oder 1000 Iterationen. Wenn wir diese erreichen ohne Divergenz, nehmen wir an, dass c zur Menge gehört. + +### 3.2 Der Pseudocode + +Für jede komplexe Zahl c = (c_real, c_imag): + +``` +z_real = 0 +z_imag = 0 +iteration = 0 +max_iterations = 1000 + +solange (iteration < max_iterations): + // Berechne z² + c + z_real_neu = z_real² - z_imag² + c_real + z_imag_neu = 2 × z_real × z_imag + c_imag + + z_real = z_real_neu + z_imag = z_imag_neu + + // Divergenz-Check + wenn (z_real² + z_imag² > 4): + break // Divergenz erkannt! + + iteration = iteration + 1 + +// Ergebnis: iteration +// - Wenn iteration = max_iterations: c ist in der Menge (schwarz färben) +// - Sonst: c ist außerhalb (Farbe basierend auf iteration) +``` + +### 3.3 Wichtige Details zur Implementierung + +**1. Reihenfolge der Berechnung** + +```cpp +// FALSCH: +z_real = z_real * z_real - z_imag * z_imag + c_real; +z_imag = 2 * z_real * z_imag + c_imag; // Nutzt bereits das neue z_real! +``` + +```cpp +// RICHTIG: +double z_real_neu = z_real * z_real - z_imag * z_imag + c_real; +double z_imag_neu = 2 * z_real * z_imag + c_imag; +z_real = z_real_neu; +z_imag = z_imag_neu; +``` + +**2. Optimierung der Divergenz-Prüfung** + +```cpp +// Berechne die Quadrate nur einmal: +double z_real_squared = z_real * z_real; +double z_imag_squared = z_imag * z_imag; + +double z_real_neu = z_real_squared - z_imag_squared + c_real; +double z_imag_neu = 2 * z_real * z_imag + c_imag; + +// Divergenz-Check +if (z_real_squared + z_imag_squared > 4.0) { + break; +} +``` + +--- + +## 4. Von Pixeln zur komplexen Ebene + +### 4.1 Das Problem + +Dein Bildschirm hat Pixel mit Koordinaten: +- x: 0 bis fenster_breite (z.B. 0 bis 800) +- y: 0 bis fenster_hoehe (z.B. 0 bis 600) + +Die interessante Region der Mandelbrot-Menge liegt bei: +- Real-Achse: ungefähr -2.5 bis +1.0 +- Imaginär-Achse: ungefähr -1.0 bis +1.0 + +Wir müssen jeden Pixel auf einen Punkt in der komplexen Ebene abbilden. + +### 4.2 Die Mapping-Formel + +#### Schritt 1: Normalisiere Pixelkoordinaten auf [0, 1] + +``` +x_normiert = x / fenster_breite // Wert zwischen 0 und 1 +y_normiert = y / fenster_hoehe // Wert zwischen 0 und 1 +``` + +#### Schritt 2: Skaliere auf den gewünschten Bereich + +``` +c_real = min_real + x_normiert × (max_real - min_real) +c_imag = min_imag + y_normiert × (max_imag - min_imag) +``` + +#### Beispiel mit konkreten Zahlen + +Angenommen: +- Fenster: 800×600 Pixel +- Bereich: real [-2.5, 1.0], imaginär [-1.0, 1.0] + +Für Pixel (400, 300) (die Fenstermitte): + +``` +x_normiert = 400 / 800 = 0.5 +y_normiert = 300 / 600 = 0.5 + +c_real = -2.5 + 0.5 × (1.0 - (-2.5)) + = -2.5 + 0.5 × 3.5 + = -2.5 + 1.75 + = -0.75 + +c_imag = -1.0 + 0.5 × (1.0 - (-1.0)) + = -1.0 + 0.5 × 2.0 + = -1.0 + 1.0 + = 0.0 +``` + +Die Fenstermitte entspricht also der komplexen Zahl c = -0.75 + 0i. + +### 4.3 Koordinatensysteme beachten + +**Problem:** In den meisten Grafiksystemen ist y=0 oben und y wächst nach unten. In der Mathematik wächst die imaginäre Achse nach oben. + +**Lösung 1:** Y-Koordinate umdrehen +``` +y_normiert = 1.0 - (y / fenster_hoehe) +``` + +**Lösung 2:** min_imag und max_imag vertauschen +``` +c_imag = max_imag - y_normiert × (max_imag - min_imag) +``` + +Beide führen zum gleichen Ergebnis: Die Mandelbrot-Menge wird richtig herum angezeigt. + +### 4.4 Seitenverhältnis (Aspect Ratio) + +Wenn dein Fenster nicht quadratisch ist, musst du aufpassen, dass Kreise nicht zu Ellipsen werden. + +**Option 1:** Passe den Bereich an das Fensterverhältnis an + +``` +aspect_ratio = fenster_breite / fenster_hoehe + +real_span = max_real - min_real +imag_span = max_imag - min_imag + +// Zentriere und passe an +center_real = (min_real + max_real) / 2 +center_imag = (min_imag + max_imag) / 2 + +if (aspect_ratio > 1.0) { + // Fenster ist breiter als hoch → erweitere Real-Achse + half_span = imag_span * aspect_ratio / 2 + min_real = center_real - half_span + max_real = center_real + half_span +} else { + // Fenster ist höher als breit → erweitere Imaginär-Achse + half_span = real_span / aspect_ratio / 2 + min_imag = center_imag - half_span + max_imag = center_imag + half_span +} +``` + +**Option 2:** Rendere in ein quadratisches Bild und zeige es zentriert im Fenster + +--- + +## 5. Färbung und Visualisierung + +### 5.1 Basis-Färbung + +Das Einfachste: +- **In der Menge** (max_iterations erreicht): Schwarz +- **Außerhalb**: Färbung basierend auf der Iterationszahl + +``` +if (iteration == max_iterations) { + farbe = SCHWARZ +} else { + // iteration geht von 0 bis max_iterations-1 + helligkeitswert = iteration / max_iterations + farbe = helligkeitswert // z.B. 0 = schwarz, 1 = weiß +} +``` + +### 5.2 Farb-Paletten + +Statt Graustufen kannst du Farbverläufe verwenden: + +**Linear mapping:** +``` +farbindex = (iteration × 256) / max_iterations +farbe = farbpalette[farbindex] +``` + +**Beliebte Paletten:** +- Regenbogen (HSV mit variierendem Hue) +- Blau-Violett-Verlauf +- Feuer (Schwarz → Rot → Orange → Gelb → Weiß) + +### 5.3 Smooth Coloring (kontinuierliche Färbung) + +Problem: Mit der einfachen Methode sieht man harte "Bänder" zwischen den Iterationsstufen. + +Lösung: Nutze den finalen Betragswert für eine feinere Färbung: + +``` +wenn divergiert: + // Wie stark über der Grenze sind wir? + betrag_quadrat = z_real² + z_imag² + + // Smooth iteration count + smooth_iteration = iteration + 1 - log(log(betrag_quadrat) / log(2)) / log(2) + + // Nutze smooth_iteration für Färbung +``` + +Das ergibt sanfte Farbverläufe ohne Bänder. (Dies ist mathematisch etwas fortgeschritten, aber das Ergebnis sieht viel besser aus.) + +--- + +## 6. Zoom und Navigation + +### 6.1 Zoom implementieren + +Beim Zoomen verkleinerst du den sichtbaren Bereich der komplexen Ebene. + +**Zoom um einen Faktor:** +``` +zoom_factor = 2.0 // 2x näher heran + +center_real = (min_real + max_real) / 2 +center_imag = (min_imag + max_imag) / 2 + +span_real = (max_real - min_real) / zoom_factor +span_imag = (max_imag - min_imag) / zoom_factor + +min_real = center_real - span_real / 2 +max_real = center_real + span_real / 2 +min_imag = center_imag - span_imag / 2 +max_imag = center_imag + span_imag / 2 +``` + +### 6.2 Zoom auf Mausposition + +Wenn der User auf Pixel (mouse_x, mouse_y) klickt: + +``` +// Berechne die komplexe Zahl an der Mausposition +mouse_real = min_real + (mouse_x / fenster_breite) × (max_real - min_real) +mouse_imag = min_imag + (mouse_y / fenster_hoehe) × (max_imag - min_imag) + +// Zentriere auf diese Position und zoome +span_real = (max_real - min_real) / zoom_factor +span_imag = (max_imag - min_imag) / zoom_factor + +min_real = mouse_real - span_real / 2 +max_real = mouse_real + span_real / 2 +min_imag = mouse_imag - span_imag / 2 +max_imag = mouse_imag + span_imag / 2 +``` + +### 6.3 Interaktive Navigation + +**Pan (Verschieben):** +``` +verschiebung_real = delta_x / fenster_breite × (max_real - min_real) +verschiebung_imag = delta_y / fenster_hoehe × (max_imag - min_imag) + +min_real -= verschiebung_real +max_real -= verschiebung_real +min_imag -= verschiebung_imag +max_imag -= verschiebung_imag +``` + +--- + +## 7. Performance-Optimierungen + +### 7.1 Frühe Abbrüche + +**Periodizitätsprüfung:** Speichere z in regelmäßigen Abständen. Wenn z sich wiederholt, bist du in einem Zyklus → in der Menge. + +**Hauptkardioiden-Test:** Der große "Körper" der Mandelbrot-Menge (eine Kardioidform) kann analytisch getestet werden: + +``` +// Teste ob c in der Hauptkardioide liegt +q = (c_real - 0.25)² + c_imag² +if (q × (q + (c_real - 0.25)) < 0.25 × c_imag²) { + // In der Hauptkardioide → direkt als "in der Menge" werten + return max_iterations +} + +// Teste ob c im Periode-2-Bulb liegt +if ((c_real + 1)² + c_imag² < 0.0625) { + // Im Bulb → in der Menge + return max_iterations +} +``` + +### 7.2 Symmetrie nutzen + +Die Mandelbrot-Menge ist symmetrisch zur reellen Achse: +- Wenn (a + bi) in der Menge ist, dann auch (a - bi) + +Du kannst nur die obere Hälfte berechnen und spiegeln. + +### 7.3 Multi-Threading + +Jeder Pixel kann unabhängig berechnet werden → perfekt für Parallelisierung! + +Teile das Bild in Streifen oder Kacheln auf und berechne diese in verschiedenen Threads. + +--- + +## 8. Interessante Koordinaten zum Erkunden + +### Klassische Ansicht (Gesamtüberblick) +``` +Real: [-2.5, 1.0] +Imag: [-1.25, 1.25] +``` + +### Seepferdchen-Tal +``` +Real: [-0.75, -0.735] +Imag: [0.1, 0.115] +max_iterations: 500+ +``` + +### Spiralen +``` +Real: [-0.7, -0.65] +Imag: [0.4, 0.45] +max_iterations: 1000+ +``` + +### Mini-Mandelbrot +``` +Real: [-0.16, -0.14] +Imag: [1.025, 1.045] +max_iterations: 2000+ +``` + +**Tipp:** Je tiefer du zoomst, desto höher sollte max_iterations sein, um Details zu sehen! + +--- + +## 9. Häufige Fehler und deren Lösung + +### 9.1 "Ich sehe nur Schwarz oder nur Weiß" + +**Ursachen:** +- max_iterations zu niedrig oder zu hoch +- Koordinatenbereich außerhalb der interessanten Region +- Mapping-Formel falsch + +**Lösung:** Beginne mit der klassischen Ansicht und max_iterations = 100. + +### 9.2 "Das Bild ist verzerrt" + +**Ursache:** Seitenverhältnis nicht korrekt berücksichtigt. + +**Lösung:** Siehe Abschnitt 4.4 zur Aspect Ratio. + +### 9.3 "Die Iteration zählt falsch" + +**Ursache:** Du verwendest das neue z_real bei der Berechnung von z_imag_neu. + +**Lösung:** Speichere beide neue Werte in temporären Variablen. + +### 9.4 "Beim Zoomen wird das Bild unscharf" + +**Ursache:** Bei tiefen Zoom-Stufen reicht die Präzision von `double` nicht mehr aus. + +**Lösung:** +- Nutze höhere Präzision (z.B. `long double`) +- Für extreme Zooms: arbitrary-precision Bibliotheken (GMP, MPFR) + +### 9.5 "Die Berechnung ist sehr langsam" + +**Lösungen:** +- Reduziere max_iterations für Vorschau-Rendering +- Implementiere Multi-Threading +- Nutze Periodizitätsprüfung und analytische Tests +- Rendere in niedrigerer Auflösung und skaliere hoch + +--- + +## 10. Zusammenfassung: Die komplette Visualisierungspipeline + +``` +FÜR JEDEN PIXEL (x, y) IM FENSTER: + + 1. MAPPING: Konvertiere Pixel zu komplexer Zahl + c_real = min_real + (x / breite) × (max_real - min_real) + c_imag = min_imag + (y / höhe) × (max_imag - min_imag) + + 2. ITERATION: Teste ob c in der Menge liegt + z_real = 0 + z_imag = 0 + iteration = 0 + + SOLANGE iteration < max_iterations: + // Berechne z² + c + temp_real = z_real² - z_imag² + c_real + temp_imag = 2 × z_real × z_imag + c_imag + z_real = temp_real + z_imag = temp_imag + + // Divergenz? + WENN z_real² + z_imag² > 4: + BREAK + + iteration++ + + 3. FÄRBUNG: Basierend auf Iterationszahl + WENN iteration == max_iterations: + farbe = SCHWARZ (in der Menge) + SONST: + farbe = berechne_farbe(iteration) + + 4. ZEICHNE: Setze Pixel (x, y) auf farbe +``` + +--- + +## Viel Erfolg! + +Die Mandelbrot-Menge ist ein faszinierendes mathematisches Objekt. Beim Hineinzoomen entdeckst du immer neue Strukturen – Spiralen, Seepferdchen-Täler, Mini-Kopien der gesamten Menge. + +Ein paar abschließende Tipps: +- Beginne mit niedrigen max_iterations (50-100) für schnelle Tests +- Implementiere Zoom und Pan für interaktive Exploration +- Experimentiere mit verschiedenen Farbpaletten +- Speichere interessante Koordinaten, die du findest + +Die Selbstähnlichkeit der Mandelbrot-Menge ist unendlich – du kannst beliebig tief zoomen und findest immer neue Details (bis zur Grenze der Gleitkomma-Präzision).