patterncMinorCanonical
Mandelbrot image generator 2.0
Viewed 0 times
imagemandelbrotgenerator
Problem
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:
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
#include
#include
#include
#include
#include
#include
#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 b
The total list of additions is as follows:
- 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)
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
#include
#include
#include
#include
#include
#include
#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 b
Solution
This looks pretty good! I've never used OpenMP, so I can't comment on that, and I have to admit this is the first time I've seen the use of complex numbers in C. Very cool!
I don't have a lot to add to the discussion except for this:
If the output image is n x m pixels, then you're currently generating the coordinates (
Then, in the inner loop, calculate num like this:
It's a small win, but it's something.
You could also do something similar for the coloring. You could generate a table of
If you really want to make things even more parallel, you also have the option of using SIMD instructions for your target CPU. On Intel, that would be MMX/SSE/AVX instructions. On ARM I think it would be NEON. And if you want to go even further you could write OpenCL, CUDA, or OpenGL Computation shaders and do the calculations on the GPU.
I don't have a lot to add to the discussion except for this:
If the output image is n x m pixels, then you're currently generating the coordinates (
a and b) n*m times. You could calculate them n + m times by calculating all the as outside the loop, and all the bs outside the loop like this:for(xpx = 0; xpx < image.width; xpx++)
{
as[xpx] = image.xmin + xpx * xdiff / image.width;
}
for(ypy = 0; ypy < image.height; ypy++)
{
bs[ypy] = image.ymin + ypy * ydiff / image.height;
}Then, in the inner loop, calculate num like this:
num = as[xpx] + I * bs[ypy];It's a small win, but it's something.
You could also do something similar for the coloring. You could generate a table of
MAX_TESTS RGB values and just return the appropriate one in rgb_gen().If you really want to make things even more parallel, you also have the option of using SIMD instructions for your target CPU. On Intel, that would be MMX/SSE/AVX instructions. On ARM I think it would be NEON. And if you want to go even further you could write OpenCL, CUDA, or OpenGL Computation shaders and do the calculations on the GPU.
Code Snippets
for(xpx = 0; xpx < image.width; xpx++)
{
as[xpx] = image.xmin + xpx * xdiff / image.width;
}
for(ypy = 0; ypy < image.height; ypy++)
{
bs[ypy] = image.ymin + ypy * ydiff / image.height;
}num = as[xpx] + I * bs[ypy];Context
StackExchange Code Review Q#92411, answer score: 3
Revisions (0)
No revisions yet.