Improvement to my Mandelbrot set code

user1726549 picture user1726549 · Apr 20, 2013 · Viewed 13.7k times · Source

I have the following Mandelbrot set code in C. I am doing the calculation and creating a .ppm file for the final fractal image. The point is that my fractal image is upside down, meaning it is rotated by 90 degrees. You can check it by executing my code: ./mandel > test.ppm

On the other hand, I also want to change the colours. I want to achieve this fractal image:

enter image description here

My final issue is that my code doesn't check the running time of my code. I have the code for this part too, but when code execution finishes it doesn't print the running time. If someone can make the appropriate changes to my code and help me achieve this fractal image, and make elapsed time displayed I would be glad.

#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>

void color(int red, int green, int blue)
{
    fputc((char)red, stdout);
    fputc((char)green, stdout);
    fputc((char)blue, stdout);
}

int main(int argc, char *argv[])
{
    int w = 600, h = 400, x, y; 
    //each iteration, it calculates: newz = oldz*oldz + p, where p is the current pixel, and oldz stars at the origin
    double pr, pi;                   //real and imaginary part of the pixel p
    double newRe, newIm, oldRe, oldIm;   //real and imaginary parts of new and old z
    double zoom = 1, moveX = -0.5, moveY = 0; //you can change these to zoom and change position
    int maxIterations = 1000;//after how much iterations the function should stop

    clock_t begin, end;
    double time_spent;

    printf("P6\n# CREATOR: E.T / mandel program\n");
    printf("%d %d\n255\n",w,h);

    begin = clock();

    //loop through every pixel
    for(x = 0; x < w; x++) 
    for(y = 0; y < h; y++)
    {
        //calculate the initial real and imaginary part of z, based on the pixel location and zoom and position values
    pr = 1.5 * (x - w / 2) / (0.5 * zoom * w) + moveX;
        pi = (y - h / 2) / (0.5 * zoom * h) + moveY;
        newRe = newIm = oldRe = oldIm = 0; //these should start at 0,0
        //"i" will represent the number of iterations
        int i;
        //start the iteration process
        for(i = 0; i < maxIterations; i++)
        {
            //remember value of previous iteration
            oldRe = newRe;
            oldIm = newIm;
            //the actual iteration, the real and imaginary part are calculated
            newRe = oldRe * oldRe - oldIm * oldIm + pr;
            newIm = 2 * oldRe * oldIm + pi;
            //if the point is outside the circle with radius 2: stop
            if((newRe * newRe + newIm * newIm) > 4) break;
        }

        color(i % 256, 255, 255 * (i < maxIterations));

    }

    end = clock();

    time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
    printf("Elapsed time: %.2lf seconds.\n", time_spent);

    return 0;
}

Answer

Justin Peel picture Justin Peel · Apr 20, 2013

Part 1: You need to swap the order of your loops to:

for(y = 0; y < h; y++)
for(x = 0; x < w; x++)

That will give you the correctly oriented fractal.

Part 2: To get the time to print out, you should print it to stderr since you are printing the ppm output to stdout:

fprintf(stderr, "Elapsed time: %.2lf seconds.\n", time_spent);

Part 3: To get a continuous smooth coloring, you need to use the Normalized Iteration Count method or something similar. Here is a replacement for your coloring section that gives you something similar to what you desire:

    if(i == maxIterations)
        color(0, 0, 0); // black
    else
    {
        double z = sqrt(newRe * newRe + newIm * newIm);
        int brightness = 256. * log2(1.75 + i - log2(log2(z))) / log2(double(maxIterations));
        color(brightness, brightness, 255);
    }

It isn't quite there because I kind of did a simple approximate implementation of the Normalized Iteration Count method.

Mandelbrot using some semi-continuous coloring

It isn't a fully continuous coloring, but it is kind of close.