Exercice : Fractale de Mandelbrot#
La fractale de Mandelbrot est un ensemble de points du plan complexe défini ainsi: soit \(c\) un complexe, on lui associe la suite \((z_n)\) donnée par \(z_0 = 0\) et \(z_{n+1} = z_n^2 + c\). Le complexe \(c\) est dans la fractale ssi la suite \((z_n)\) est bornée.
Le type Complexe
, la fonction initComplexe
, la fonction egaleComplexe
, la
fonction ajouterComplexe
et la fonction moduleComplexe
vous sont données
ci-dessous. Lisez leur code pour bien les comprendre.
struct Complexe {
float re, im;
};
void initComplexe(Complexe *c, float reel, float imaginaire) {
c->re = reel;
c->im = imaginaire;
}
bool egaleComplexe(Complexe a, Complexe b) {
return (a.re == b.re) && (a.im == b.im);
}
void ajouterComplexe(Complexe *a, Complexe b) {
a->re = a->re + b.re;
a->im = a->im + b.im;
}
float moduleComplexe(Complexe c) {
return sqrt(pow(c.re, 2) + pow(c.im, 2));
}
Écrire la fonction
void multiplierComplexe
sur le modèle de la fonctionajouterComplexe
qui prend en entrée deux complexes dont le premier sous la forme d’un pointeur et qui renvoie leur produit en modifiant le premier paramètre.Faites très attention à la formule : \((a_1+i\,b_1)*(a_2+i\,b_2)= a_1 *a_2 - b_1 * b_2 + i\,(a_1*b_2 + a_2 * b_1)\). En effet, comme en programmation modulaire, la moindre erreur risque de vous faire perdre beaucoup de temps. De plus pensez à bien tester votre fonction.
BEGIN SOLUTION
Attention ici, il ne faut pas modifier le contenu de {\tt a} immédiatement lors du calcul de la partie réelle car on en a besoin pour le calcul de la partie imaginaire.
void multiplierComplexe(Complexe *a, Complexe b){ float re, im; re = a->re * b.re - a->im * b.im; im = a->im * b.re + a->re * b.im; a->re = re; a->im = im; }
END SOLUTION
Écrire une fonction booléenne
znResteBorne
qui prend un complexe \(c\), et renvoie vrai si la suite \(z_n\) associée ne tend pas vers l’infini, faux sinon. On calculera la suite des termes \(z_n\), jusqu’à ce que le module de \(z_n\) devienne plus grand que \(2\) (auquel cas on dira que la suite tend vers l’infini), ou \(1000\) itérations ont été faites (auquel cas on dira que la suite reste bornée).BEGIN SOLUTION
bool znResteBorne(Complexe c){ Complexe z; initComplexe(&z, 0, 0); for(int i = 0; i < 1000; i++){ if (moduleComplexe(z) > 2){ return false; } multiplierComplexe(&z, z); ajouterComplexe(&z, c); } return true; }
END SOLUTION
La procédure
mandelbrot
qui vous est donnée ci-dessous utilise la fonctionznResteBorne
que vous venez d’écrire pour afficher l’ensemble de Mandelbrot. Elle fait varier \(x\) entre \(-2\) et \(0.5\) et \(y\) entre \(-1.1\) et \(+1.1\), et fait un affichage ASCII sur \(80\times40\) caractères.void mandelbrot() { const float xmin = -2; const float xmax = 0.5; const float ymin = -1.1; const float ymax = 1.1; const int xresol = 79; const int yresol = 39; for (int i = 0; i <= yresol; i++) { for (int j = 0; j <= xresol; j++) { Complexe z; initComplexe(&z, (xresol - j) * xmin / xresol + j * xmax / xresol, (yresol - i) * ymax / yresol + i * ymin / yresol); if (znResteBorne(z)) { cout << '#'; } else { cout << ' '; } } cout << endl; } }
Exécuter
mandelbrot
, puis modifiez cette procédure pour zoomer sur la figure, en faisant varier x et y sur de plus petits intervalles, autour de points pas trop loin de la frontière.