diff options
| author | JP Appel <jeanpierre.appel01@gmail.com> | 2024-04-26 14:47:56 -0400 |
|---|---|---|
| committer | JP Appel <jeanpierre.appel01@gmail.com> | 2024-04-26 14:47:56 -0400 |
| commit | aaa64e36cd5ac1cc6077d38505c645f4c316b78e (patch) | |
| tree | 0cc440909bfecca7dd53598c9c30b3de06e3c891 | |
| parent | 22141040a52c362a60f4feb7d03e4f7d346dcae3 (diff) | |
add cli args for degree, constant, radius
| -rw-r--r-- | README.md | 21 | ||||
| -rw-r--r-- | src/fractals.c | 134 | ||||
| -rw-r--r-- | src/grids.c | 1 |
3 files changed, 123 insertions, 33 deletions
@@ -8,6 +8,8 @@ Each version of the complex fractal generator has its own dependencies. The serial version should compile on all systems that support complex arithmetic. The shared version requires a compiler with [OpenMP](https://www.openmp.org/) support. +The CUDA version requires the `nvcc` compiler and `thrust libraries`. +For better performance on your machine, change the flag `-arch=sm_86` in `NVCFLAGS` in the makefile to your gpu's compute capability. ### Building @@ -19,7 +21,7 @@ make If you wish to compile with additional floating point precision, add `-DEXTENDED_PRECISION` to `CPPFLAGS` in the makefile. -**NOTE:** extended precision is **NOT** supported in the cuda version. +**NOTE:** extended precision is **NOT** supported in the CUDA version. ### Running @@ -32,10 +34,10 @@ The performance flag outputs information in the format of: ``` Note that the runtime is an average runtime from multiple runs. -The number of runs can be adjusted directly in `src/fractals.c` in `NUM_RUNS` or passed set in `CPPFLAGS` by adding `-DNUM_RUNS=N` +The number of runs can be adjusted directly in `src/fractals.c` in `NUM_RUNS` or set in `CPPFLAGS` by adding `-DNUM_RUNS=N`. ``` -Usage: PROGRAM [-v] [-i iterations] [-x x_res] [-y y_res] [-z magnification] [-l lower_left] [-u upper_right] [-o output_grid] -f fractal +Usage: <PROGRAM> [-v] [-i iterations] [-x x_res] [-y y_res] [-z magnification] [-d degree] [-c constant] [-r radius] [-l lower_left] [-u upper_right] [-o output_grid] -f fractal Options: -i, --iterations <value> the number of iterations (default: 100) -x, --x-res <value> the horizontal resolution (default: terminal width) @@ -43,6 +45,9 @@ Options: -l, --lower-left <value> Set the lower left corner of the fractal area (default: -2-2i) -u, --upper-right <value> Set the upper right corner of the fractal area (default: 2+2i) -z, --magnification <value> Set the magnification factor (default: 1) + -d, --degree <value> Set the degree for fractals that use it (default: 1) + -c, --constant <value> Set the constant for fractals that use it (default: 0+0i) + -r, --radius <value> Set the radius for fractals that use it (default: 2) -o, --output <filename> the output filename (default: fractal.grid) -f, --fractal <type> the fractal type (default: mandelbrot) supported fractals: mandelbrot, tricorn, multibrot, multicorn, burning_ship, julia @@ -51,6 +56,16 @@ Options: -h, --help prints this help message ``` +#### Examples + +`build/shared-fractals -x2000 -y2000 -z 2 -o burning_ship.grid -f burning_ship` + +Generates a 2000x2000 burning ship fractal grid zoomed in 2x and saves it to burning_ship.grid + +`build/serial-fractals -x500 -y500 -i35 -c 0.285+0.01i -r 20 -o julia.grid -f julia` + +Generates a 500x500 julia fractal grid which has a maximum of 30 iterations for $c = 0.285 + 0.01i$ and a radius of 20 to julia.grid. + ## Visualizations ## Presentation diff --git a/src/fractals.c b/src/fractals.c index 395ccdb..f994265 100644 --- a/src/fractals.c +++ b/src/fractals.c @@ -10,12 +10,14 @@ #include "precision.h" #include "fractals.h" +#define EXIT_BAD_ARGUMENT 2 + #ifndef NUM_RUNS #define NUM_RUNS 5 #endif void print_usage(FILE* file, const char* program_name){ - fprintf(file, "Usage: %s [-v] [-i iterations] [-x x_res] [-y y_res] [-z magnification] [-l lower_left] [-u upper_right] [-o output_grid] -f fractal\n", program_name); + fprintf(file, "Usage: %s [-v] [-i iterations] [-x x_res] [-y y_res] [-z magnification] [-d degree] [-c constant] [-r radius] [-l lower_left] [-u upper_right] [-o output_grid] -f fractal\n", program_name); } void print_help(){ @@ -23,15 +25,20 @@ void print_help(){ " -i, --iterations <value> the number of iterations (default: 100)\n" " -x, --x-res <value> the horizontal resolution (default: terminal width)\n" " -y, --y-res <value> the vertical resolution (default: terminal height)\n" - " -l, --lower-left <value> Set the lower left corner of the fractal area (default: -2-2i)\n" - " -u, --upper-right <value> Set the upper right corner of the fractal area (default: 2+2i)\n" + " -l, --lower-left <value> Set the lower left corner of the fractal area (default: -2.0+-2.0i)\n" + " -u, --upper-right <value> Set the upper right corner of the fractal area (default: 2.0+2.0i)\n" " -z, --magnification <value> Set the magnification factor (default: 1)\n" + " -d, --degree <value> Set the degree for fractals that use it (default: 1)\n" + " -c, --constant <value> Set the constant for fractals that use it (default: 0+0i)\n" + " -r, --radius <value> Set the radius for fractals that use it (default: 2)\n" " -o, --output <filename> the output filename (default: fractal.grid)\n" " -f, --fractal <type> the fractal type (default: mandelbrot)\n" " supported fractals: mandelbrot, tricorn, multibrot, multicorn, burning_ship, julia\n" " -p, --performance print performance info\n" " -v, --verbose verbose output\n" - " -h, --help prints this help message\n"); + " -h, --help prints this help message\n" + "\ndegree is mutually exclusive with constant and radius\n" + "\nExits with a status code of 1 if the program encounters an error, exits with 2 if an argument is incorrect\n"); } void print_info(const char* program_name){ @@ -53,6 +60,13 @@ double time_fractal(fractal_generator generator, grid_t* grid, grid_gen_params* return (end.tv_sec - start.tv_sec + (end.tv_nsec - start.tv_nsec) * 1.0e-9) / NUM_RUNS; } +static inline void parse_complex(const char* string, complex_t* z){ + if(sscanf(string, CFORMAT "+" CFORMAT "i", &z->re, &z->im) != 2){ + fprintf(stderr, "Failed while parsing complex number: %s , is it formatted correctly?\n", string); + exit(EXIT_FAILURE); + }; +} + int main(const int argc, char *argv[]) { struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); @@ -66,11 +80,24 @@ int main(const int argc, char *argv[]) { CBASE magnification = 1; bool verbose = false; bool performance = false; - grid_gen_params* params = NULL; + + //degree is mutually exclusive with constant and radius + bool param_is_degree = false; + bool param_is_cr = false; + CBASE degree = 1; + complex_t constant = { .re = 0, .im = 0}; + double radius = 2; + char* fractal_name = "mandelbrot"; fractal_generator generator = mandelbrot_grid; char* output_filename = "fractal.grid"; + grid_gen_params* params = malloc(sizeof(grid_gen_params)); + if(!params){ + fprintf(stderr, "Failed to allocate memory: %zu bytes\n", sizeof(grid_gen_params)); + exit(EXIT_FAILURE); + } + static struct option long_options[] = { {"iterations", required_argument, NULL, 'i'}, {"x-res", required_argument, NULL, 'x'}, @@ -78,6 +105,9 @@ int main(const int argc, char *argv[]) { {"lower-left", required_argument, NULL, 'l'}, {"upper-right", required_argument, NULL, 'u'}, {"magnification", required_argument, NULL, 'z'}, + {"degree", required_argument, NULL, 'd'}, + {"constant", required_argument, NULL, 'c'}, + {"radius", required_argument, NULL, 'r'}, {"output", required_argument, NULL, 'o'}, {"verbose", no_argument, NULL, 'v'}, {"performance", no_argument, NULL, 'p'}, @@ -88,7 +118,7 @@ int main(const int argc, char *argv[]) { //parse command line arguments int opt; - while((opt = getopt_long(argc, argv, "i:x:y:l:u:z:o:vphf:", long_options, NULL)) != -1){ + while((opt = getopt_long(argc, argv, "i:x:y:l:u:z:d:c:r:o:vphf:", long_options, NULL)) != -1){ switch(opt){ case 'i': iterations = strtoull(optarg, NULL, 10); @@ -100,56 +130,94 @@ int main(const int argc, char *argv[]) { y_res = strtoull(optarg, NULL, 10); break; case 'l': - sscanf(optarg, CFORMAT"+"CFORMAT"i", &lower_left.re, &lower_left.im); + parse_complex(optarg, &lower_left); break; case 'u': - sscanf(optarg, CFORMAT"+"CFORMAT"i", &upper_right.re, &upper_right.im); + parse_complex(optarg, &upper_right); break; case 'o': output_filename = optarg; break; + case 'd': + param_is_degree = true; + if(param_is_cr){ + fprintf(stderr, "--degree and --constant --radius are mutually exclusive, exiting\n"); + exit(EXIT_BAD_ARGUMENT); + } + if(sscanf(optarg, CFORMAT, °ree) != 1){ + fprintf(stderr, "Failed to parse degree: %s, exitting\n", optarg); + exit(EXIT_BAD_ARGUMENT); + } + break; + case 'c': + if(param_is_degree){ + fprintf(stderr, "--degree and --constant --radius are mutually exclusive, exiting\n"); + exit(EXIT_BAD_ARGUMENT); + } + parse_complex(optarg, &constant); + param_is_cr = true; + break; + case 'r': + if(param_is_degree){ + fprintf(stderr, "--degree and --constant --radius are mutually exclusive, exiting\n"); + exit(EXIT_BAD_ARGUMENT); + } + if(sscanf(optarg, CFORMAT, &radius) != 1){ + fprintf(stderr, "Failed to parse radius: %s, exitting\n", optarg); + exit(EXIT_BAD_ARGUMENT); + } + param_is_cr = true; + break; case 'f': if(strncmp(optarg, "mandelbrot", strlen("mandelbrot")) == 0) { fractal_name = "mandelbrot"; generator = mandelbrot_grid; } else if(strncmp(optarg, "tricorn", strlen("tricorn")) == 0) { - fractal_name = "tricorn"; - generator = tricorn_grid; + fractal_name = "tricorn"; + generator = tricorn_grid; } else if(strncmp(optarg, "multibrot", strlen("multibrot")) == 0) { - fractal_name = "multibrot"; - generator = multibrot_grid; - params = malloc(sizeof(grid_gen_params)); - params->degree = 3; + if(param_is_cr){ + fprintf(stderr, "multibrot requires a degree, not constant and radius, exitting\n"); + exit(EXIT_BAD_ARGUMENT); + } + fractal_name = "multibrot"; + generator = multibrot_grid; } else if(strncmp(optarg, "multicorn", strlen("multicorn")) == 0) { - fractal_name = "multicorn"; - generator = multicorn_grid; - params = malloc(sizeof(grid_gen_params)); - params->degree = 3; + if(param_is_cr){ + fprintf(stderr, "multicorn requires a degree, not constant and radius, exitting\n"); + exit(EXIT_BAD_ARGUMENT); + } + fractal_name = "multicorn"; + generator = multicorn_grid; } else if(strncmp(optarg, "burning_ship", strlen("burning_ship")) == 0) { - fractal_name = "burning ship"; - generator = burning_ship_grid; + fractal_name = "burning ship"; + generator = burning_ship_grid; } else if(strncmp(optarg, "julia", strlen("julia")) == 0) { - fractal_name = "julia"; - generator = julia_grid; - params = malloc(sizeof(grid_gen_params)); - params->cr.radius = 100; - params->cr.constant = (complex_t){ .re = 0.285, .im = 0.01 }; + if(param_is_degree){ + fprintf(stderr, "julia requires a constant and a radius, not a degree, exitting\n"); + exit(EXIT_BAD_ARGUMENT); + } + fractal_name = "julia"; + generator = julia_grid; } else { fprintf(stderr, "Invalid fractal type: %s, see --help for a list of supported fractals\n", optarg); - return 1; + exit(EXIT_BAD_ARGUMENT); } break; case 'z': - sscanf(optarg, CFORMAT, &magnification); + if(sscanf(optarg, CFORMAT, &magnification) != 1){ + fprintf(stderr, "Failed to parse magnification: %s, exitting\n", optarg); + exit(EXIT_BAD_ARGUMENT); + } if(magnification <= 0){ fprintf(stderr, "Invalid magnification "CFORMAT", exitting\n", magnification); - return 1; + exit(EXIT_BAD_ARGUMENT); } break; case 'v': @@ -164,10 +232,18 @@ int main(const int argc, char *argv[]) { return 0; default: print_usage(stderr, argv[0]); - return 1; + return 2; } } + if(param_is_degree){ + params->degree = degree; + } + else { + params->cr.constant = constant; + params->cr.radius = radius; + } + grid_t* grid = create_grid(x_res, y_res, iterations, lower_left, upper_right); if(!grid) return 1; diff --git a/src/grids.c b/src/grids.c index 354189b..97bb894 100644 --- a/src/grids.c +++ b/src/grids.c @@ -252,7 +252,6 @@ void print_grid(FILE* file, const grid_t* grid){ const char point_types[] = { ' ', '.', '*', '%', '#'}; size_t bin_width = iterations/3; size_t last_bin = iterations - bin_width; - char* buffer_ptr = output_buffer; char point; for(size_t i = 0; i < size; i++){ |
