aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJP Appel <jeanpierre.appel01@gmail.com>2024-04-26 14:47:56 -0400
committerJP Appel <jeanpierre.appel01@gmail.com>2024-04-26 14:47:56 -0400
commitaaa64e36cd5ac1cc6077d38505c645f4c316b78e (patch)
tree0cc440909bfecca7dd53598c9c30b3de06e3c891
parent22141040a52c362a60f4feb7d03e4f7d346dcae3 (diff)
add cli args for degree, constant, radius
-rw-r--r--README.md21
-rw-r--r--src/fractals.c134
-rw-r--r--src/grids.c1
3 files changed, 123 insertions, 33 deletions
diff --git a/README.md b/README.md
index 5a2f369..1f30b0e 100644
--- a/README.md
+++ b/README.md
@@ -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, &degree) != 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++){