|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T m
Length: 9977 (0x26f9) Types: TextFile Names: »mancomp.c«
└─⟦87ddcff64⟧ Bits:30001253 CPHDIST85 Tape, 1985 Autumn Conference Copenhagen └─⟦this⟧ »cph85dist/mandelbrot/mancomp.c«
/* * Mandelzoom (from Scientific American, August 1985). * Recommended places for exploration (according to the article): * real imaginary side * -2.00 -1.25 2.50 Entire Mandelbrot set * .26 0.00 .01 * -.76 0.01 .02 * -1.26 0.01 .02 * * This program computes the Mandelbrot set, writing the pixels * to xxx.pix and the parameters (origin, size, and a pixel density * histogram to xxx.his). * * Option command line (for spawning): * mandel origin_real origin_imag size npixel niter filename * or mandel xxx.cmd read commands from a file. * or mandel interactive * * Values are: * orig_real (double) lower-left hand corner of the picture (real part) * orig_imag (double) lower-left hand corner of the picture (imag part) * size (double) size of a side (defines the view into the set * npixel (int) number of pixels on each side (max == 512) * default = 100 * niter (int) number of iterations per point. * default = 100 * file (string) name of output file (no type) * default = mandel * * In "mandel file" format, each line generates a separate picture. * * Each picture causes two files to be written: * file.his (readable text format) contains picture definition parameters * and a histogram of pixel values: * orig_real orig_imag side npixel niter \n * bottom top sum (first non-zero histogram, last non-zero, * sum of histogram values). * hist[bottom] (number of pixels with count == bottom) * ... (etc.) * hist[top] (number of pixels with specified count) * file.pix (binary format) contains npixel rows, each containing npixel * integers, defining the count at each pixel location. * * Note: this program is very cpu intensive. There are a maximum of * 4 * niter * (npixel**2) floating-point multiplies * 10 * niter * (npixel**2) other floating-point (add, compare, store) * per picture. * * Decus C bug note: * all printf's that format floats must have only one floating-point * parameter, and it must be the last parameter in the argument list. * Also, Decus C doesn't support (double) x++. */ #include <stdio.h> #include <ctype.h> #ifdef decus #define W_BIN_MODE "wn" /* Write binary file in Decus C */ #else #define W_BIN_MODE "w" #endif #ifdef vms #include errno #define IO_ERROR errno #define IO_SUCCESS 1 /* SS$_NORMAL */ #endif #define FALSE 0 #define TRUE 1 #define EOS '\0' #ifndef IO_ERROR #define IO_SUCCESS 0 /* Unix definitions */ #define IO_ERROR 1 #endif #ifdef decus int $$narg = 1; /* Don't prompt for commands */ #endif #define MAX_NPIXEL 400 /* Forced by display format */ #define MAX_NITER 1000 /* Max. number of iterations */ #define DEF_FILENAME "mandel" /* Default output filename */ #define DEF_NITER 100 /* Default number of iterations */ #define DEF_NPIXEL 100 /* Default number of pixels */ #define MAX_ARGS 8 /* Command line arguments */ /* * These values may be reset by the user. */ int niter = DEF_NITER; /* Number of iterations */ int npixel = DEF_NPIXEL; /* Number of pixels/side */ double orig_real = -2.0; /* South-West (i.e. lower-left) */ double orig_imag = -1.25; /* corner of the picture */ double side = 2.5; int pixel[MAX_NPIXEL]; /* Stores one pixel row */ double gap[MAX_NPIXEL]; /* Real axis position */ double hist[MAX_NITER]; /* Pixel density histogram */ char line[256]; /* General text work area */ char filename[81]; /* Output file name work area */ char *myargv[MAX_ARGS]; /* To build command arguments */ int myargc; /* Index into myargv[] */ FILE *pixfd; /* Pixel file (binary) */ FILE *hisfd; /* Pixel histogram (text) */ extern double atof(); extern char *strchr(); \f main(argc, argv) int argc; char *argv[]; { if (argc <= 1) { while (interactive()) { doit(); } } else if (argc == 2 && !isdigit(argv[1][0])) { if (freopen(argv[1], "r", stdin) == NULL) { perror(argv[1]); exit(IO_ERROR); } while (comfile()) { getarguments(myargc, myargv); doit(); } } else { getarguments(argc, argv); doit(); } exit(IO_SUCCESS); } doit() { if (setup()) { process(); finish(); } } \f process() /* * Compute the Mandelbrot set. */ { register double z_real, z_imag; /* Pixel accumulator */ register double z2_real; /* z_real ** 2 */ register double z2_imag; /* z_imag ** 2 */ register int count; /* Inner-loop counter */ register int j; /* Column counter */ register int i; /* Row counter */ register double c_real, c_imag; /* Pixel position (constant) */ register double float_pixels; /* To computer pixel position */ register double total; /* For progress log */ /* * Precompute the position of each pixel on the real axis. * This loop should not be "unrolled" to a succession of * additions as that would lose accuracy. Given what * follows, the cost isn't excessive. */ total = 0.0; /* Progress log counter */ float_pixels = npixel; for (j = 0; j < npixel; j++) /* Precompute column (real) gap */ gap[j] = orig_real + (side * ((double) j) / float_pixels); for (i = 0; i < npixel; i++) { c_imag = orig_imag + (side * ((double) i) / float_pixels); for (j = 0; j < npixel; j++) { /* * Compute one point (pixel) of the Mandelbrot set: * 1. Set z to 0 + 0i and * set c to the pixel location (real, imag) * 2. Perform step 3 until either * 1. count reaches the selected number of iterations or * 2. the "size" of z exceeds 2.0, where size is * defined as sqrt(z_real**2 + z_imag**2) * (we don't bother with the square root.) * 3. z = z**2 + c; * count = count + 1; * size = size of z as defined above. * 4. Set pixel[i,j] to the number of iterations (count). */ c_real = gap[j]; z_real = c_real; z_imag = c_imag; for (count = 0; count < niter; count++) { if (((z2_real = (z_real * z_real)) + (z2_imag = (z_imag * z_imag))) > 4.0) break; z_imag = (z_real * z_imag * 2.0) + c_imag; z_real = z2_real - z2_imag + c_real; } pixel[j] = count; /* Store the pixel */ hist[count] += 1.0; /* Gray-scale histogram */ total += (double) count; /* For progress log */ if (i == j && isatty(fileno(stdout))) { scr_move(7, 1); /* Log progress @ diag. */ printf("%3d %3d %4d %8.0f", i, j, count, total); scr_eol(); fflush(stdout); } } /* All columns this row */ fwrite(pixel, npixel * sizeof (pixel[0]), 1, pixfd); if (ferror(pixfd)) { perror("pixel file write error"); return; } } /* All rows in picture */ } \f int setup() /* * Open the .pix and .his files. Zero the vectors. */ { register int i; extern FILE *fcreate(); sprintf(line, "%s.pix", filename); if ((pixfd = fopen(line, W_BIN_MODE)) == NULL) { perror(line); sleep(2); return (FALSE); } sprintf(line, "%s.his", filename); if ((hisfd = fcreate(line)) == NULL) { perror(line); sleep(2); fclose(pixfd); return (FALSE); } fprintf(hisfd, "%f", orig_real); fprintf(hisfd, " %f", orig_imag); fprintf(hisfd, " %f", side); fprintf(hisfd, " %d", npixel); fprintf(hisfd, " %d\n", niter); for (i = 0; i < niter; i++) hist[i] = 0.0; return (TRUE); } \f finish() /* * Compute a histogram of the counts. */ { register int bottom, top, i; register double sum; fclose(pixfd); for (bottom = 0; bottom < niter && hist[bottom] == 0.0; bottom++) ; for (top = niter - 1; top > bottom && hist[top] == 0.0; top--) ; for (sum = 0.0, i = bottom; i <= top; i++) sum = sum + hist[i]; fprintf(hisfd, "%d %d %f\n", bottom, top, sum); for (i = bottom; i <= top; i++) fprintf(hisfd, "%10.2f\n", hist[i]); fclose(hisfd); } \f getarguments(argcount, argstring) int argcount; char *argstring[]; /* * Process argv[] from command line or pseudo argv[] from a file. */ { register int i; if (argcount < 5) { printf("Missing arguments, need at least\n"); printf("orig_real, orig_imaginary, side\n"); } else { orig_real = atof(argstring[1]); orig_imag = atof(argstring[2]); side = atof(argstring[3]); strcpy(filename, DEF_FILENAME); niter = DEF_NITER; npixel = DEF_NPIXEL; switch (argcount) { default: printf("Extra arguments ignored:\n"); for (i = 7; i < argcount; i++) printf(" arg[%d] = \"%s\"\n", i, argstring[i]); case 7: strcpy(filename, argstring[6]); case 6: if ((niter = atoi(argstring[5])) > MAX_NITER) { printf("%d iterations max.\n", MAX_NITER); niter = MAX_NITER; } case 5: npixel = atoi(argstring[4]); } if (npixel > MAX_NPIXEL) npixel = MAX_NPIXEL; printf("corner = [%f,", orig_real); printf("%f], ", orig_imag); printf("side = %f, ", side); printf("%d pixels, %d iterations\n", npixel, niter); } } \f int interactive() /* * Read commands from the terminal -- assumed to be a VT100 or similar. */ { if (isatty(fileno(stdin))) scr_clear(); if (!getcomplex(1, "Lower-left Corner (real, imaginary)", &orig_real, &orig_imag) || !getdouble(2, "Side Length", &side) || !getint(3,"Number of pixels on a side", &npixel, DEF_NPIXEL, MAX_NPIXEL) || !getint(4, "Iterations", &niter, DEF_NITER, MAX_NITER) || !getstring(5, "Output filename", filename, DEF_FILENAME)) return (FALSE); #if 0 /* Debug */ scr_move(2, 1); printf("corner = [%f,", orig_real); printf("%f], ", orig_imag); printf("side = %f, ", side); printf("%d pixels, %d iterations\n", npixel, niter); scr_eol(); sleep(2); #endif return (TRUE); } \f int comfile() /* * Read commands from an indirect command file. */ { register char *lp; if (gets(line) == NULL) return (FALSE); myargv[0] = ""; for (myargc = 1, lp = line; *lp != EOS && myargc < MAX_ARGS;) { while (isspace(*lp)) lp++; myargv[myargc++] = lp; while(!isspace(*lp)) lp++; if (*lp != EOS) *lp++ = EOS; } return (TRUE); }