Simplest way to determine if a number is a member of the Mandelbrot set?

I'm writing JavaScript code to plot the Mandelbrot set on an HTML5 Canvas element. (That's probably not relevant to the answer to this question).

A core part of the problem is to write a simple function that returns true if a number is a member of the Mandelbrot set and false otherwise. Since JavaScript has no complex numbers in its built-in libraries, I simply represent a complex number as a two-element array with the first element being the real part and the second element being the imaginary part.

I know that if any iteration of the function z^2 + c returns a value with absolute value greater than two, then z is definitely not a member of the Mandelbrot set. If no iteration of z^2 + c returns a value greater than two, then z is a member of the Mandelbrot set, but it's impossible to iterate the function to infinity.

Therefore, I tried iterating the function 1000 times and assuming that if it takes more than 1000 iterations, the function doesn't diverge to infinity. This is a disaster. The plot produced contains many points that are definitely not in the Mandelbrot set by comparison to references on the internet.bad Mandelbrot plot

        function isInMandelbrot(z) {
            var i, a;
            a = z;
            for (i = 0; i < 1000; i++) {
                a = helper(a);                    
                if (a[0] > 2 || a[0] < -2 || a[1] > 2 || a[1] < -2)
                    return false;
            }
            return true;

            // Compute z^2 + c
            function helper(a) {
                var raisedToPower, sum;
                raisedToPower = square(a);
                sum = [raisedToPower[0] + z[0], raisedToPower[1] + z[1]];
                return sum;
            }
        }

        function square(z) {
            var rResult, iResult;
            rResult = z[0] * z[0] - z[1] * z[1];
            iResult = 2 * z[0] * z[1];
            return [rResult, iResult];
        }

Increasing the limit to 10,000 instead of 1000 produces almost exactly the same plot and takes lots longer. This makes me wonder if I could be running up against the precision limits of how JavaScript computes calculations. There's an explanation here: http://www.yuiblog.com/blog/2009/03/10/when-you-cant-count-on-your-numbers/

I think that in order to plot the Mandelbrot set, I need a better way of determining set membership. How might I do this?

The answer should not depend on what language the computation is done in unless floating-point precision is the issue.

Edit: I tried rendering the image at 16000*16000 and I noticed a fascinating result: The points outside the Mandelbrot set that are wrongly identified as points inside the Mandelbrot set... clump together into clumps shaped like the Mandelbrot set! You can't make this stuff up!

Edit again: Okay, I think I see what the problem is! I think that the darkened points are actually in the Mandelbrot set. I erroneously assumed that they were too far from the main "blob" to be part of the set, but after looking at some other plots, I think that there is a connection that is too small to render, as in this plot: http://en.wikipedia.org/wiki/File:Mandel_zoom_01_head_and_shoulder.jpg


Solution 1:

Your plot looks great. I don't know any better way than what you are doing. As you zoom in deeper, it takes more and more iterations to get a reasonable picture. To some extent, you can use fixed point instead of floating-define maxint as $4$ and do fixed point multiplies and bit shifts to rescale, then add. You can also do your compares to $2$ in each direction instead of squaring. If the value is greater than $2$ in magnitude, it will be greater than $2$ in one axis soon.

Solution 2:

I think that in order to plot the Mandelbrot set, I need a better way of determining set membership. How might I do this ?

  1. You can use different version of algorithm. Now you use boolean version of escape time algorithm. If you change to integer or real version and use grey colour gradient then even with the same number of iterations, precision of numbers and zoom the filaments will be better visualised. enter image description here
  2. you can also use different algorithm like DEM/Menter image description here

If you change the algorithm, also change the bailout test.