# The Problem in More Detail This document adds detail to the cursory overview provided in the [readme](https://github.com/ProfJski/FloatCompMandelbrot#readme). ## Preliminary Definitions (For the sake of clarity, at the expense of stating the obvious.) The **Mandelbrot Set** is defined as the set of points on the complex plane for which the iterated function F(Z) = Z^2+C remains bounded when iterated. Z is initially equal to zero and C is the point being evaluated. If the magnitude of Z is greater than 2, then further iterations will produce unboundedly larger values of Z, so a magnitude check of whether |Z|>2 at every iteration is the standard test to evaluate whether a point is outside the Mandelbrot Set. Often the points of the Mandelbrot Set are colored black.[^1] As such, the *Mandelbrot Set* (the black part) is only part of what I call the **Mandelbrot Set Image**, which also includes a color-coded valuation of all points that are unbounded, colored by how many iterations of F(Z) it took a point to escape the boundary check of |F(z)|>2. While unbounded points are not members of the Mandelbrot Set, they are still interesting. [^1]: People have developed coloring algorithms for points in the Mandelbrot Set, but we do not employ them here. The **trajectory** of a point in the Mandelbrot Set Image is the sequence of complex values obtained by iterating Z=Z^2+C. This sequence may be plotted on the complex plane. By definition, the trajectory of any point outside the Mandelbrot set will extend beyond a circle of radius two centered on the origin of the complex plane. For points in the Mandelbrot set, the trajectory remains within this circle, no matter how many iterations are performed. The trajectory of a point in the set may include a repeating series of values, sometimes called a *periodic orbit.* If a value of Z does not exceed the boundary circle and repeats after q iterations, C is surely in the Mandlebrot set, since Z will recur every subsequent q iterations, forever remaining within the boundary circle of radius two. While some points quickly exceed the boundary after only a few iterations, others may take thousands or millions or more. I call **The Mandelbrot Set Algorithm** the computer program whereby one produces a Mandelbrot Set Image. Several practical factors enter into the pure mathematics of the Mandelbrot set as soon as we turn to its computational implementation. These factors critically include the way complex numbers are represented and calculated by the computer. Another consideration is how long to iterate. As noted above, it may take thousands or millions of iterations for the trajectory of a point *outside* the Mandelbrot Set to exceed the boundary check. Points *in* the Mandelbrot Set **never** will exceed the boundary, by definition. Customarily *for the sake of the algorithm terminating,* if a point's trajectory has not escaped the boundary by a certain specified maximum number of iterations, it is "presumed" to be part of the Mandelbrot Set and colored black.[^2] Of course, further iterations could prove otherwise, and near the edge of the Mandelbrot set, this is often the case. A trajectory which would escape the |Z|>2 boundary only after 100,000 iterations of slowly growing larger in its magnitude will be presumed part of the set and the point colored back if an algorithm's max iteration limit is 50K. A third consideration is what section of the complex plane to plot. Because of the fractal nature of the Mandelbrot Set, arbitrarily small sections of the complex plane surrounding its boundary can be calculated to produce images of great complexity. "How deep to zoom" is thus another consideration which bears on how long the algorithm iterates and the precision of the computer in dealing with arbitrarily small quantities. [^2]: There are other ways of terminating the Mandelbrot Set algorithm besides specifying a maximum iteration, such as checking for a periodic orbit, but we do not employ period checking here, for reasons discussed below. We define the **image parameters** of the Mandelbrot Set Algorithm to be the choices of what points to evaluate (what region of the complex plane, at what level of magnification), how to color them by value (the palette), and the max iterations before presuming a point is in the Mandelbrot Set. By contrast, we define the **floating point implementation** to refer to how non-integer complex numbers are handled in software and hardware, aside from the aforementioned image parameters, because we seek to isolate the effect that decisions about floating point implementation have on the resulting Mandelbrot Set Image. With these definitions, we may state our goal more exactly. ## Definition of Our Investigation This program seeks to investigate how different floating point implementations may lead to different Mandelbrot Set Images for the same image parameters. How does floating point implementation affect both the shape of the Mandelbrot Set (i.e., the black points) *and* the shape of the colored points outside the set (where there is also considerable visual complexity), when we calculate the same points in the same region of the complex plane, with the same boundary check, with the same palette, and the same maximum iterations, but using different floating point implementations? I have yet to see a detailed treatment of this question from the perspective of [numerical analysis](https://en.wikipedia.org/wiki/Numerical_analysis), but several parts of the Mandelbrot Set algorithm are identified in numerical analysis literature as potentially problematic. I am not a professional mathematician or numerical analyst. So therefore I must take an empirical approach to the problem to see how extensive an effect floating point implementations may have on Mandelbrot Set Images. The program presented here is my humble tool for this investigation. It can benefit from the wisdom of more learned programmers. If you know of numerical analysis literature which discusses the computation of Mandelbrot Set Images, please let me know! It surprises me that information is not readily available online, given the fame of the Mandelbrot set, the ubiquity of programs calculating it, and the fact that from its first image, it has been generated on a wide variety of computers. # Sources of Floating Point Variance in the Mandelbrot Algorithm ## Initial Round-Off Error: Assignment of C Floating point implementations can only represent exactly those rational numbers with a denominator that is a power of two (dyadic rationals). Rational numbers with other denominators result in non-terminating binary representation (similar to how 1/3 in decimal is 0.3333 with three repeating indefinitely). Moreover, not every dyadic rational can be exactly represented in binary floating point, but only those within certain limits determined by the size of the rational's numerator and denominator and the available number of bits of the floating point representation. Attempting to evaluate whether point C is in the Mandlebrot set when C cannot be represented exactly in the floating point implementation introduces round-off error from the very first iteration of F(Z), and this error contributes to every subsequent iteration. ## Accumulated Round-Off Error Even with initial values of C that can be exactly represented in floating point form, the problem of round-off error can only be postponed so long for most values of C. Consider, by analogy, the operation of repeatedly squaring a decimal number like 0.5. The trajectory of such an operation doubles the number of digits to the right of the decimal point each time: 0.5, 0.25, 0.0625, 0.00390625, etc. Similarly for the multiply-then-add operation of Z=Z^2+C. Eventually the number of binary digits which a floating point type can retain is exceeded and round-off error accumulates with every subsequent iteration. Higher precision (more bits) only postpones this eventuality. One could attempt to avoid the problem by using arbitrary-precision floating point representation, or rational representation (using two integers, for numerator and denominator, i.e., keep everything as fractions), but that quickly leads to so many significant digits to multiply in every iteration that calculations become enormously slow. For many points in a Mandelbrot Set Image, the number of significant digits in a trajectory tends to double with each iteration, leading to O(n^2) time complexity for evaluating one point with n iterations. Iterations must then be kept very low (e.g., 20-30 on a modern PC!), which means that many higher-iteration points cannot be evaluated. So accumulated round-off error is hard to avoid. Volker Schatz [^11] makes the following observation which directly applies to Mandelbrot set trajectories: "Careful with iterations. In many if not most cases numerical computations involve iteration rather than just the evaluation of a single formula. This can cause errors to accumulate, as the chance of an intermediate result not being exactly representable rises. Even if the target solution is an attractive fixed point of your iteration formula, numerical errors may catapult you out of its domain of attraction." ## "Catastrophic Cancellation" Subtracting two values that are close to each other leads to a large loss in bits of precision called "catastrophic cancellation" in numerical analysis. See [^3] and [^9] for discussion. A subtraction is always involved in every iteration of F(Z), since the real component of Z^2 = (a^2-b^2) if we represent Z as (a+bi). Moreover, depending on the signs of Z's components and C's components, another subtraction may be involved in both the real and imaginary parts of every iteration when C is added to Z^2, since the addition of numbers with opposite signs has the same potentially catastrophic effect as a subtraction. For a point that iterates thousands of times, how likely is a catastrophic cancellation to happen during the whole trajectory? (Using the grid overlay on display mode 8 may give some visual indication, since it will happen when the trajectory's points are very close to the diagonal lines of the grid overlay that appears when `Key ` is pressed.) ## Floating-point math is not always associative Depending on the magnitude of the quantities involved, `(a+b)+c` may not equal `a+(b+c)` or `a*(b+c)` may not equal `(a*b)+(a*c)`. Moreover, the order of operations can affect the loss of precision. David Goldberg [^3] explicitly notes that the expression `(x^2 - y^2)` typically results in more loss of precision than if it were calculated as `(x+y)*(x-y)` (except when x>>y or y<