This commit is contained in:
Miloslav Ciz 2024-02-15 14:16:28 +01:00
parent 3631b726e5
commit d52544f211
9 changed files with 1722 additions and 1671 deletions

View file

@ -29,9 +29,41 @@ Mandelbrot set (also M-set) is a famous two dimensional [fractal](fractal.md), a
| ':::' |
| : |
|___________________________________________________[0.5,-1]|
___________________________________________________________
| ''.:.:'::::: '' :.'..::'::.:''.::.::: .:''' :'.::'.:'':':|
|: ::.''.':'::::.' :.'::::'::::.:::..' .:::: : ::'::::'::::|
|::' . :::: ' ::. : :' :.'::.' .:::''.'::'.: ':.:.':':':.'|
|'::: .'.':.' '':. ..'.'::::':.':::' ..:'::'. ':::'.':::'|
| ::::..'::'.'.'.'.: : :: ::::': .:. :''..::.::... :..':::::|
|:'::: ':.:::... ':''.: ..::::'::':::': :'::'':: '': :.':'.|
|:::.:':::':. :::.':...::: : . ''.'.: .:. '.:::: .::' :|
|:::::'.'' .::':. :..:.::.::..' .::. ::'' :'' |
|:::::: :.::''''. ::. .:'::::. .':''. ' . ...': :|
|:::''''' :'' :''::: '.':'' : . . '':':'.'.|
|':''':::.. ::'::.::.' . ' :':::::.:::: .:::|
|:. .:.::.. '': ' ::. '::: . '':::'..::' :.'.|
|:: : :. ' '..:: ' ::: : .':::.:::::'::::|
|..::.::' . ...:'':.' ::.'.':'': ':':'.:.:'':::..:|
|.:::::::: ': .'''.....:: ::.'::.:.....'. |
|:::::::::. .' . ' ':.::::.. :':.' : ': ' |
|:::::::::.' :':. ''.':::. .:: :.. .:':. '|
|:.::::'':': .:.:: ::'':. .'::'.::'.:. '.: '|
|:..''''': :.::::'. ::. : :'''':':: .::|
| ::: '. . .. '':'::::: '.:: :.:'. ..''' :.. ':'.|
|: :::' ::... :..::.::::.::::': .::'':.:'::::: . :|
|'.. . '.. '' .: ::::: '::::::.':.:..:.::. ' .:.'|
|::.... ' . ' :: '.'::::::.:..'':. ''::' .' '|
|:':.:::. ..'..'': :..:''' .. :' ' .':|
| .':::: :. . . ':::::.:.'::..' . .:::: :. .|
| .::.:: '..:'. :''.::':::''::'..:: ' ' ::''|
|:'' .:'::. ': ::''::''. ..:'' :: :::::.:::. ' ':|
|::.:.' .''' .::::::::..':.''': ':...::''.:: .' ..|
| :':' ' . :::::':':..::::::..'.:::':'::'':' ' |
|'': . '::''::: ::::::'.:.::: : . '' ' '|
|___________________________________________________________|
```
*Simple ASCII rendering of Mandelbrot set.*
*Simple ASCII rendering of Mandelbrot set, below a zoomed-in detail.*
**Definition**: we use [complex numbers](complex_number.md) to define the set. Consider the following series of complex numbers *z[n]*:
@ -39,11 +71,13 @@ Mandelbrot set (also M-set) is a famous two dimensional [fractal](fractal.md), a
Mandelbrot set is the set of all points *p* for which the [absolute value](abs.md) ("length") of *z[n]* stays bounded (i.e. doesn't grow beyond any limits) as *n* goes towards infinity.
NOTE: here is the series equation rewritten to just work with *x* and *y* coordinates. Checking the point *[px,py]*, your series will be *x[n + 1] = x[n]^2 - y[n]^2 + px* and *y[n + 1] = 2 * x[n] * y[n] + py*.
I.e. taking any point *p* in the complex plane (whose real and imaginary parts we see as the *x* and *y* coordinates), plugging it into the above equation and iterating the series infinitely many times, if the absolute value of *z[n]* stays bounded under some finite value (even very large, just not infinitely large), the number belongs to the set, otherwise not (if the absolute value diverges towards infinity). I.e. in other words the Mandelbrot set is a set of kind of "well behaved" points that don't shoot away to infinity when we keep applying some operation to them over and over. Of course computers cannot evaluate infinitely many iterations of the series so they cannot compute the set 100% accurately, but we may very well [approximate](approximation.md) by performing many iterations (let's 100000) and seeing if the value we get is "very large" (let's say 1000000000) when we stop -- this will work correctly for most points and those few points near the set borders where we make a wrong guess won't really be noticed unless we zoom in very close -- in such cases we can simply perform more iterations to increase precision. To add **[colors](color.md)** to the visualization (so that we don't observe just the borders but also some kind of structure inside and outside of the set) we may simply assign different colors to the points depending e.g. on how big the absolute value is at the time we stop the evaluation, or how many iterations it took for the absolute value to exceed given limit (for points outside the set). Also note that for nice pictures we should apply [antialiasing](antialiasing.md). Additional fancy filters and [shaders](shader.md) such as some kind of postprocessing or fake 3D can also be applied to make the result even more impressive.
TODO: example on specific point
There are further **[optimizations](optimization.md)** we may apply to calculate the set faster. The set itself also lies in the circle centered at [0,0] with radius 2, so points outside this area can be safely marked as lying outside the set. Furthermore it's proven that if absolute value of *z[n]* ever gets greater than 2, the point won't lie in the set (because getting absolute value greater than 2 basically means we start checking a point that inevitably lies outside the circle with radius 2 inside which the whole set lies, so we know the point won't lie in the set). A quick [bailout](bailout.md) check (not requiring square roots etc.) here can therefore be e.g. checking if either the real of imaginary component absolute value exceeds 2 (which implies the whole vector length must exceed 2 as well), or checking if the sum of squares of the components exceeds 4 (i.e. we squared both sides of the equation and got rid of the square root). [Symmetry](symmetry.md) of the set can also be used to skip computing some points. Further more complex optimizations exist, based e.g. on estimating distance of any given point to the set border etc.
There are further [optimizations](optimization.md) we may apply to calculate the set faster, for example it's proven that if absolute value of *z[n]* ever gets greater than 2, the point won't lie in the set. The set itself also lies in the circle centered at [0,0] with radius 2, so points outside this area can be safely marked as lying outside the set.
**Quick example**: does point *[-0.75,1]* lie in the Mandelbrot set? Taking the above *x* and *y* coordinate equations we set *px = -0.75* and *py = 1*, our starting values are also these, i.e. *x[0] = -0.75* and *y[0] = 1*. Now *x[1] = x[0]^2 - y[0]^2 + px = (-0.75)^2 - 1^2 - 0.75 ~= -1.1875*, *y[1] = 2 * x[0] * y[0] + py = 2 * -0.75 * 1 + 1 ~= -0.5*. So after first iteration we got to approximately *[-1.1875,-0.5]*, the length of this vector is *sqrt((-1.1875)^2 + (-0.5)^2) ~= 1.28*, so we're still in the game. Now we repeat this all with these new coordinates, getting *x[2] ~= 0.4101* and *y[2] ~= 2.1875*, with length of the vector *sqrt(0.4101^2 + 2.1875^2) ~= 2.2256*. This value surpassed 2, so by the mentioned optimization we now know iterating further the value will only be getting higher and higher until infinity, so we conclude the original point *[-0.75,1]* does NOT lie in the Mandelbrot set.
As an alternative to drawing the set in the traditional plane with *x*/*y* axes correspond to the *real*/*imaginary* parts of the complex number, we may utilize different mappings, for example [polar coordinates](polar_coords.md) or the "inversion mode" (swapping zero and infinity) used in xaos. These may offer yet different angles of view of the set.
@ -71,11 +105,11 @@ As the set is being studied and explored a lot, some even started to make maps o
- Point [0.372138,0.0903982] shows an infinitely zoomable point from which circular arms stem.
- ...
**Generalizations and modifications**: mentioned [Julia sets](julia_set.md) are very similar to the Mandelbrot set. **[Multibrot](multibrot.md)** sets are sets similar to the Mandelbrot which we define by requiring *abs(z[n])* to not surpass some given value *T* under inifinite iteration, i.e. Mandelbrot set is one of Multibrot sets, that in which we set *T = 2* (because as mentioned above, reaching 2 always leads to divergence towards infinity); for different values of *T* we'll get similar but different Multibrot fractal sets. We may also modify the iterative equation from quadratic to cubic (replace *z[n]^2* with *z[n]^3*), or a different power (or modify the equation in similar ways) to again get sets similar to the Mandelbrot. Using [quaternions](quaternion.md) instead of complex numbers generalized Mandelbrot from 2D to 4D.
**Generalizations and modifications**: mentioned [Julia sets](julia_set.md) are very similar to the Mandelbrot set. **[Multibrot](multibrot.md)** sets are sets similar to the Mandelbrot which we define by requiring *abs(z[n])* to not surpass some given value *T* under inifinite iteration, i.e. Mandelbrot set is one of Multibrot sets, that in which we set *T = 2* (because as mentioned above, reaching 2 always leads to divergence towards infinity); for different values of *T* we'll get similar but different Multibrot fractal sets. We may also modify the iterative equation from quadratic to cubic (replace *z[n]^2* with *z[n]^3*), or a different power (or modify the equation in similar ways) to again get sets similar to the Mandelbrot. Using [quaternions](quaternion.md) instead of complex numbers generalized Mandelbrot from 2D to 4D. [Buddhabrot](buddhabrot.md) is another famous fractal (which looks like Buddha) and is related to Mandelbrot set.
## Code
The following code is a simple [C](c.md) program that renders the Mandelbrot set into terminal (for demonstrative purposes, it isn't efficient or do any [antialiasing](antialiasing.md)).
The following code is a simple [C](c.md) program that renders the Mandelbrot set into terminal (for demonstrative purposes, it isn't efficient or do any [antialiasing](antialiasing.md), also using [float](float.md) for simplicity but keep in mind [fixed point](fixed_point.md) can be easily used as well).
```
#include <stdio.h>
@ -90,13 +124,13 @@ unsigned int mandelbrot(double x, double y)
{
double cx = x, cy = y, tmp;
for (int i = 0; i < 1000; ++i)
for (int i = 0; i < 1000; ++i) // 1000 iterations
{
tmp = cx * cx - cy * cy + x;
cy = 2 * cx * cy + y;
cx = tmp;
if (cx * cx * cy * cy > 1000000000)
if (cx * cx + cy * cy > 4) // optimization
return 0;
}
@ -131,6 +165,10 @@ int main(void)
}
```
Note on the optimization above: a naive line checking the divergence of the series would look e.g. like `if (sqrt(cx * cx + cy * cy) > 1000000000)`. However, as said above, it is enough to check if the value exceeds 2, as it's proven that then the series will surely diverge, so we can change it to `if (sqrt(cx * cx + cy * cy) > 2)`. Furthermore we can get rid of the [square root](sqrt.md) by squaring both sides of the inequality, so we get `if (cx * cx + cy * cy > 4)`. Hopefully this is one small example of why [math](math.md) is important for programming.
## See Also
- [fractal](fractal.md)
- [Julia set](julia_set.md)
- [Buddhabrot](buddhabrot.md)