jnw@mcnc.UUCP (John White) (09/06/85)
[The above line was for the line-eater] This is a quickly hacked together version 0.0 of a program to plot the number of iterations of (z <- z*z+b) required for |z|>=2 starting at z=0. The plot is done on the complex plane of b. See the august 1985 issue of "Scientific American" for more info. The DeSmet C compiler is used and in-line assembler is used for the graphics (everything is done through BIOS) and for the critical inner loop. Note that integer arithmetic is used in the inner loop so no floating point processor is needed. Currently the limit of iterations is 255. If |z|<2 after that, then b is assumed to be in the Mandelbrot set which is plotted as black. Other colors are used when |z|>=2 for a smaller count. Alternation of colors is used to display the contors of increasing count. Since I don't have a floating point processor, I had to use integer arithmetic and fudge things a little. Because of this, the scale is specified by an integer. A value of 180 is used to display the whole set. The maximum magnification is with a value of 1. This is the scale on the real axis, the program multiplies this by 1.15 to get the scale on the imaginary axis but you can override this. The center of the plot can also be specified. Note, the displayed area is real=320*scale/16384, imaginary=200*scale/16384. The real and imaginary parts of z are represented with 16 bit integers with the value 2 being represented as 32k and -2 as -32k. Because of this, specifing a center for the plot with part of the real or imaginary axis less than -2 or greater than 2 will cause a repeated image to occur. This is an artifact. Note that with small values of scale the aspect ratio will be off. A typical plot might take ten minutes. Time taken is strongly dependant on the fraction of the points that are in the Mandelbrot set as these require the full number of iterations. This program was originaly written for a Tandy 2000 with high res color graphics (640 by 400 by 8 colors) and the plots on the Tandy are far better than those on the IBM. But the IBM plots are still interesting. Areas you might want to zoom in on (use scale=2): whorls, at -.72, .25 hooks, at -.915, .27 front, at -1.41, 0 miniature Mandelbrot, at -.16, 1.03 star, at -.55, .64 connection cusp, at -.76, .11 - John N. White <mcnc!jnw> ------------------------------------------------------- /* Program to compute the Mandelbrot set. * (convergence of z = z*z + b using complex numbers) * Arithmetic is done in ordinary integers with 32k corresponding to 2 * and -32k corresponding to -2. * Compile with the DeSmet compiler. * Originaly for a Tandy 2000 with color graphics (640 by 400 by 8 color). * Converted to run on the IBM in 320 by 200 by 4 color mode (mode 4). * Written by John N. White, 9/2/85 */ #define stdin 0 /* what DeSmet does in stdio.h */ #define XSIZE 320 /* number of horizontal pixels */ #define YSIZE 200 /* number of vertical pixels */ #define ASPECT 1.15 /* aspect ratio (adjust for your monitor) */ #define MAXCOUNT 255 /* max number of iterations */ #define SPLITCOUNT 127 /* count above which everything is a solid color */ int count; /* limiting number of iterations */ int zr, zi, br, bi, br2; /* real/imaginary parts of z/c */ double brd= -.24, bid; /* low/high limits of c */ int x_point, y_point, color;/* inputs to put_point() */ char buf[256], fname[256], fbuf[16000]; int xstep, ystep; /* increment for each pixel (1/16k units) */ int fn; /* holds number of open file for r/w display */ main(){ int i, j, k; printf("Mandelbrot set for the IBM with color graphics\n"); printf("Version 0.0, written by John N. White\n\n"); printf("After displaying something, press <ENTER> to continue.\n"); xstep=180, ystep=180*ASPECT; loop: printf("0 exit\n1 display file\n2 set display window\n"); printf("3 save last display\n4 calculate Mandelbrot set\ncommand: "); fgets(buf, 256, stdin); i= -1; sscanf(buf, "%d", &i); switch(i){ case 0: printf("ok, bye"); exit(0); case 1: /* display file */ printf("name of file to display: "); *fname=0; fgets(buf, 256, stdin); sscanf(buf, "%s", fname); if(*fname==0) break; if((fn=open(fname, 0)) <= 0){ printf("can't read file %s\n", fname); break; } read(fn, fbuf, 16000); close(fn); setup(); for(j=8, k= -1, y_point=0; y_point<YSIZE; y_point++){ for(x_point=0; x_point<XSIZE; x_point++){ if(j>6) j=0, k++; color= (fbuf[k]>>j) & 3; j+=2; put_point(); } } fgets(buf, 256, stdin); restore(); break; case 2: /* set display window */ printf("real step size (number of 1/16k units per step) [%d]: ", xstep); fgets(buf, 256, stdin); i= -1; sscanf(buf, "%d", &i); if(i!= -1){ xstep=i; ystep=xstep*ASPECT; } printf("imaginary step size (number of 1/16k units per step) [%d]: ", ystep); fgets(buf, 256, stdin); i= -1; sscanf(buf, "%d", &i); if(i!= -1) ystep=i; printf("enter real and imaginary coordinants of center [%f %f]\n: ", brd, bid); fgets(buf, 256, stdin); if(*buf<' ') break; sscanf(buf, "%lf%lf", &brd, &bid); printf("using center %f %f\n", brd, bid); break; case 3: /* save last display in a file */ gfnloop: printf("enter name of save file: "); fgets(buf, 256, stdin); if(*buf<' ') break; sscanf(buf, "%s", fname); if(*fname){ if(exists()){ printf("file %s already exists\n", fname); goto gfnloop; } if((fn=creat(fname)) <= 0){ printf("can't write file %s\n", fname); goto gfnloop; } } write(fn, fbuf, 16000); close(fn); break; case 4: /* calculate Mandelbrot set */ br2= round(brd*16384.-(double)xstep*(XSIZE/2)); bi= round(bid*16384.+(double)ystep*(YSIZE/2)); count= MAXCOUNT; setup(); for(j=8, k= -1, y_point=0; y_point<YSIZE; y_point++, bi-=ystep) for(x_point=0, br=br2; x_point<XSIZE; x_point++, br+=xstep){ i=do_point(); /* set color to 0-3 */ color= (i<SPLITCOUNT) ? (i&1)+1 : (i==MAXCOUNT ? 0 : 3); if(j>6) fbuf[++k]=j=0; fbuf[k]|= (color<<j); j+=2; put_point(); } fgets(buf, 256, stdin); /* wait for <enter> */ restore(); break; default: printf("try again\n"); } goto loop; } /* returns num of itterations before z = z*z + b exceeded |z|=2 */ dummy(){ #asm do_point_: push bp xor ax,ax mov word zr_,ax ;set zr,zi to 0 mov word zi_,ax mov bp,word count_ cloop_: mov ax,word zr_ imul ax xchg ax,si ;set si,di to be low,high part of zr*zr mov di,dx mov ax,word zi_ imul ax mov bx,ax ;set bx,cx to be low,high part of zi*zi mov cx,dx add ax,si adc dx,di test dh,0C0h jnz do_point_exit_ ;if |z|>=2, exit dec bp jz do_point_exit_ ;if count limit exeeded sub si,bx sbb di,cx shl si,1 rcl di,1 shl si,1 rcl di,1 jo do_point_ov1_ shl si,1 adc di,word br_ ;di= new zr = zr*zr-zi*zi+br jo do_point_exit_ ;if new zr>=2 do_point_cont1_: mov ax,word zr_ imul word zi_ shl ax,1 rcl dx,1 shl ax,1 rcl dx,1 shl ax,1 rcl dx,1 jo do_point_ov2_ shl ax,1 adc dx,word bi_ ;dx= new zi = 2*zr*zi+bi jo do_point_exit_ ;if new zi>=2 do_point_cont2_: mov word zr_,di mov word zi_,dx jmp cloop_ ;loop while <count iterations do_point_exit_: mov ax,word count_ sub ax,bp pop bp ret ;value in AX is value returned by routine do_point_ov1_: shl si,1 adc di,word br_ ;di= new zr = zr*zr-zi*zi+br jo do_point_cont1_ ;if new zr<2 jmp do_point_exit_ do_point_ov2_: shl ax,1 adc dx,word bi_ ;dx= new zi = 2*zr*zi+bi jo do_point_cont2_ ;if new zi<2 jmp do_point_exit_ # } /* setup display */ setup(){ #asm mov ax,4 ;put display in graphics mode 4 int 10h mov ah,1 ;turn off cursor mov cx,4000h int 10h mov ah,11 ;set up color palette mov bx,0 ;background color is black int 10h mov ah,11 mov bx,101h ;1=cyan, 2=magenta, 3=white int 10h mov ax,600h ;clear screen mov bh,0 mov cx,0 mov dx,1827h int 10h # } /* restore */ restore(){ #asm mov ax,2 ;reset display to mode 2 int 10h # } /* ipoint sets pixel x_point,y_point to color */ dummy2(){ #asm put_point_: mov ah,12 ;write dot mov al,byte color_ mov cx,word x_point_ mov dx,word y_point_ int 10h ret # } /* convert d to int with rounding */ round(d) double d;{ if(d>=0) d+=.5; else d-=.5; return((int)d); } /* check to see if filename in bi exists */ exists(){ static i; #asm mov dx, offset fname_ ;pointer to filename mov exists_i_,0 ;init to not exist mov ax,4300h ;get file mode (to see if exists) int 21h ;function call jc no_exists ;if file doesn't exist mov exists_i_,1 ;if file does exist no_exists: # return(i); }