Skip to main content
replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link

I have rewritten my C Mandelbrot set image generator, including many suggestions given in my previous question (see: Mandelbrot image generatorMandelbrot image generator), as well as some recomendations by a friend.

I have rewritten my C Mandelbrot set image generator, including many suggestions given in my previous question (see: Mandelbrot image generator), as well as some recomendations by a friend.

I have rewritten my C Mandelbrot set image generator, including many suggestions given in my previous question (see: Mandelbrot image generator), as well as some recomendations by a friend.

Minor wording changes
Source Link
jess
  • 1.4k
  • 11
  • 27

I have rewritten my C Mandelbrot set image generator, including many suggestionssuggestions given in my previous question (see: Mandelbrot image generator), as well as some recomendations by a friend.

  • Parallelisation (omp.h)
  • typedef-ing of structures
  • Implementing a better file-type (P6 PPM instead of P3 PPM)
  • Extensive use of command line options and arguments (getopt)
  • testingTesting of user-defined regions of the complex plane
  • Various bug fixes (possible data leak, weird image dimensions, etc.)
  • Generally better coding and layout (more concise and easier to read/understand)

I have rewritten my C Mandelbrot set image generator, including many suggestions given in my previous question (see: Mandelbrot image generator), as well as some recomendations by a friend.

  • Parallelisation
  • typedef-ing of structures
  • Implementing a better file-type (P6 PPM instead of P3 PPM)
  • Extensive use of command line options and arguments (getopt)
  • testing user-defined regions of the complex plane
  • Various bug fixes (possible data leak, weird image dimensions, etc.)
  • Generally better coding and layout (more concise and easier to read/understand)

I have rewritten my C Mandelbrot set image generator, including many suggestions given in my previous question (see: Mandelbrot image generator), as well as some recomendations by a friend.

  • Parallelisation (omp.h)
  • typedef-ing of structures
  • Implementing a better file-type (P6 PPM instead of P3 PPM)
  • Extensive use of command line options and arguments (getopt)
  • Testing of user-defined regions of the complex plane
  • Various bug fixes (possible data leak, weird image dimensions, etc.)
  • Generally better coding and layout (more concise and easier to read/understand)
Source Link
jess
  • 1.4k
  • 11
  • 27

Mandelbrot image generator 2.0

I have rewritten my C Mandelbrot set image generator, including many suggestions given in my previous question (see: Mandelbrot image generator), as well as some recomendations by a friend.

The total list of additions is as follows:

  • Parallelisation
  • typedef-ing of structures
  • Implementing a better file-type (P6 PPM instead of P3 PPM)
  • Extensive use of command line options and arguments (getopt)
  • testing user-defined regions of the complex plane
  • Various bug fixes (possible data leak, weird image dimensions, etc.)
  • Generally better coding and layout (more concise and easier to read/understand)

My question is the same as in my last post, what things have I done well here, what things have I done badly, and how can I improve in the future? I would appreciate all and any feedback on both my use of C, and my implementation of the algorithm itself.

Note: for anyone who compiles this code, I have had best results using gcc's -O3 and -fopenmp flags

//  mandelbrot.c - generates a .PPM (Portable Pixmap format, P6) file of the mandelbrot set with shading

//  Options:
//  -f [output file name] (required)
//  -h [image height in px] (required)
//  -t [max imaginary component]
//  -b [min imaginary component]
//  -v [max real component]
//  -n [min real component]

//  Return/exit codes:
//   0 - successful execution
//  -1 - argument error
//  -2 - file access error
//  -3 - image height error

#include <stdio.h>
#include <complex.h>
#include <math.h>
#include <stdlib.h>
#include <omp.h>
#include <ctype.h>
#include <unistd.h>
#define MAX_TESTS 2000

typedef struct
{
    unsigned int height;
    unsigned int width;
    double ymax, ymin;
    double xmax, xmin;
    char *file_name;
} image_meta;

typedef struct
{
    unsigned char red;
    unsigned char green;
    unsigned char blue;
} colour;

short mandelbrot_test(double complex c); //Calculates the number of iterations of the algorithm required for a given complex number to reach a magnitude >= 2
colour rgb_gen(short iterations); //Generates an RGB value based on the rate of divergence
image_meta image_meta_gen(int argc, char *argv[]); //Generates the meta data for the image by parsing the input arguments

int main(int argc, char *argv[])
{
    image_meta image;
    image = image_meta_gen(argc, argv);
    printf("Image dimensions: %dx%d\n", image.width, image.height);
    
    int xpx, ypx;
    double a, b, xdiff, ydiff;
    double complex num;
    FILE *file;
    
    xdiff = image.xmax - image.xmin;
    ydiff = image.ymax - image.ymin;
    
    if((file = fopen(image.file_name, "w")) != NULL)
    {
        fprintf(file, "P6 %d %d 255\n", image.width, image.height);
        colour rgb[image.width];

        #pragma omp parallel
        for(ypx = 0; ypx < image.height; ypx++)
        {
            for(xpx = 0; xpx < image.width; xpx++)
            {
                a   = image.xmin + xpx * xdiff / image.width;
                b   = image.ymax - ypx * ydiff / image.height;
                num = a + b * I;
                rgb[xpx] = rgb_gen(mandelbrot_test(num));
            }
            fwrite(rgb, sizeof(colour), image.width, file);
        }
        fclose(file);
    }
    else
    {
        fprintf(stderr, "Unable to access file!\n");
        exit(-2);
    }
    exit(0);
}

short mandelbrot_test(double complex c)
{
    double complex x = 0;
    double abs       = c * conj(c);

    if(abs * (8.0 * abs - 3.0) < 3.0 / 32.0 - creal(c)) //Quick test to see if we can bail out early by checking if the number lies within the main cardioid
    {
        return MAX_TESTS;
    }
    
    for(int i = 1; i < MAX_TESTS; i++)
    {
        x *= x;
        x += c;

        if(cabs(x) >= 2)
        {
            return i;
        }
    }
    return MAX_TESTS;
}

colour rgb_gen(short iterations)
{
    colour rgb;
    int brightness;
    
    if(iterations == MAX_TESTS)
    {
        rgb.red     = 255;
        rgb.green   = 255;
        rgb.blue    = 255;
    }
    else
    {
        brightness  = 256.0 * log2(iterations) / log2(MAX_TESTS - 1);
        rgb.red     = brightness;
        rgb.green   = brightness;
        rgb.blue    = 255;
    }
    return rgb;
}

image_meta image_meta_gen(int argc, char *argv[])
{
    int c;
    image_meta image;
    
    image.file_name = NULL;
    opterr = 0;
    image.xmax = image.ymax = image.xmin = image.ymin = -1;
    image.height = 0;

    while((c = getopt(argc, argv, "h:f:t:b:v:n:")) != -1)
    {
        switch(c)
        {
            case 'h':
                image.height = atoi(optarg);
                break;
            case 't':
                image.ymax = atof(optarg);
                break;
            case 'b':
                image.ymin = atof(optarg);
                break;
            case 'v':
                image.xmax = atof(optarg);
                break;
            case 'n':
                image.xmin = atof(optarg);
                break;
            case 'f':
                image.file_name = optarg;
                break;
            case '?':
                if(optopt == 'f' || optopt == 'h')
                {
                    fprintf(stderr, "Option -%c requires an argument.\n", optopt);
                }
                else if(isprint(optopt))
                {
                    fprintf(stderr, "Unknown option `-%c'.\n", optopt);
                }
                else
                {
                    fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
                }
                fprintf(stderr, "Usage: ./mandelbrot -f file_name -h height [options]\nOptional: -t y-max -b y-min -v x-min -n x-max\n");
                exit(-1);
        }
    }
    
    if(argc < 4)
    {
        fprintf(stderr, "Error: too few args\nUsage: ./mandelbrot -f file_name -h height [options]\nOptional: -t y-max -b y-min -v x-min -n x-max\n");
        exit(-1);
    }
    
    if(image.height < 30)
    {
        fprintf(stderr, "Height can't be less than 30!\n");
        exit(-3);
    }
    
    if(image.xmax == image.xmin) 
    {
        image.xmax = 0.8;
        image.xmin = -2.0;
        printf("Using default x values...\n");
    }
    
    if(image.ymax == image.ymin) 
    {
        image.ymax = 1.2;
        image.ymin = -1.2;
        printf("Using default y values...\n");
    }
    
    if(image.xmin > image.xmax)
    {
        double temp = image.xmin;
        image.xmin  = image.xmax;
        image.xmax  = temp;
    }
    
    if(image.ymin > image.ymax)
    {
        double temp = image.ymin;
        image.ymin  = image.ymax;
        image.ymax  = temp;
    }
    
    image.width = image.height * (image.xmax - image.xmin) / (image.ymax - image.ymin);
    
    return image;
}