\Fractals
FD3.CPP
From: MX%"BJ06@C53000.PETROBRAS.ANRJ.BR" 29-SEP-1994 16:43:48.79 To: MX%"noel@erich.triumf.ca" CC: Subj: FD3 for DOS (FD3DOS.CPP) - Source code Return-Path:Received: from fpsp.fapesp.br by Erich.Triumf.CA (MX V4.0-1 VAX) with SMTP; Thu, 29 Sep 1994 16:42:40 PST Received: from DECNET-MAIL by fpsp.fapesp.br with PMDF#10108; Thu, 29 Sep 1994 09:26 BSC (-0300 C) Date: Thu, 29 Sep 1994 09:26 BSC (-0300 C) From: "FAUSTO Arinos de Almeida Barbuto (Totxo)" Subject: FD3 for DOS (FD3DOS.CPP) - Source code To: noel@erich.triumf.ca Message-ID: <04B80DB3A0009621@fpsp.fapesp.br> X-Envelope-to: noel@erich.triumf.ca X-VMS-To: @NOEL References: ANSP network HEPnet SPAN Bitnet Internet gateway Comments: @FPSP.FAPESP.BR - @FPSP.HEPNET - @BRFAPESP.BITNET - .BR gateway /* BEGIN NOTICE Copyright (c) 1992 by John Sarraille and Peter DiFalco (john@ishi.csustan.edu) Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The algorithm used in this program was inspired by the paper entitled "A Fast Algorithm To Determine Fractal Dimensions By Box Counting", which was written by Liebovitch and Toth, and which appeared in the journal "Physics Letters A", volume 141, pp 386-390, (1989). This program is not warranteed: use at your own risk. ------------------------------------------------------- DOS Version created by Fausto Arinos de Almeida Barbuto (BJ06@C53000.PETROBRAS.ANRJ.BR), September 23, 1994 (Rio de Janeiro, Federal Republic of BRAZIL) ------------------------------------------------------- END NOTICE */ #include #include #include "fd.h" #include int empty_Av(long int); void push_Av(long int *, long int); void pop_Av(long int *, long int*); void create_Av(long int *); void print_Av(long int); int get_e_dim(char *); void max_min(char*, double *, double *); void rad_pass(int, int); void radixsort(void); void sweep(ulong[], double[], double[], double[]); float fracdim(); int empty_Q(QHeader); void en_Q(QHeader *, long int); void de_Q(QHeader *, long int *); void create_Q(QHeader *); void transf_Q(QHeader *, QHeader *); void print_Q(QHeader *); void GetDims(double[], double[], double[], ulong, double*, double*, double*); void findMark(ulong *, ulong[]); void fitLSqrLine (long, long, double[], double[], double *, double *); int empty_Av(long int avail) // long int avail; { return (avail == -1); } /* Puts the info pointed to by "pointer" into the avail list. Use this after dequeuing an element if you want to recycle it. Note the need to access the global array "next_after", which holds all the pointers. */ void push_Av(long int *p_avail, long int pointer) // long int *p_avail, pointer ; { extern long int *next_after; /* array for pointers to data. */ next_after[pointer] = *p_avail; *p_avail = pointer; } /* Pops the info pointed to by "p_pointer" from the avail list. Use this if you need an element to place on a queue. */ void pop_Av(long int *p_avail, long int *p_pointer) // long int *p_avail, *p_pointer; { extern long int *next_after; /* array for pointers to data. */ *p_pointer = *p_avail; *p_avail = next_after[*p_avail]; } /* Creates an avail list with room for all the data, plus two more elements to be used as markers. */ void create_Av(long int *p_avail) // long int *p_avail; { extern long int *next_after; /* array for pointers to data. */ extern ulong dataLines; /* number of data points in input file */ unsigned long int i; for (i=0;i Qfront = pointer; else next_after[p_QHeader->Qrear] = pointer; p_QHeader->Qrear = pointer; } /* This Dequeuing function does NOT check to see if the queue is empty first, nor does it return the dequeued info to the avail list. The caller MUST take care of these things! Note also that the function needs to access the array called "next_after" globally. */ void de_Q(QHeader *p_QHeader,long int *p_pointer) // QHeader *p_QHeader; /* Queue to be dequeued. */ // long int *p_pointer; /* Pointer to the data to be returned */ /* to the calling function. */ { extern long int *next_after; /* array for pointers to data. */ *p_pointer = p_QHeader->Qfront; if ((p_QHeader->Qfront) == (p_QHeader->Qrear)) p_QHeader->Qrear = -1 ; p_QHeader->Qfront = next_after[p_QHeader->Qfront]; } void create_Q (QHeader *p_QHeader) // QHeader *p_QHeader; /* Queue to be created. */ { p_QHeader->Qfront = -1; p_QHeader->Qrear = -1; } /* This is a function to rapidly move an "element" from the source to the target queue. It bypasses the actions of placing the info into the avail list, and taking it back out again. It also avoids testing to see if the source queue is being emptied, and testing to see if the target queue is empty before the enqueue is done. Such a function is useful because there will be a great many of these operations done in the radix sort of a large set. For further time-savings, one should think about putting this code in-line, so that the overhead of function-calling can be saved. USE with EXTREME CAUTION. The effect of the function will be INCORRECT if the source has one element left, or the target is empty! Note the reliance on the global array "next_after". */ void transf_Q(QHeader *p_Q1, QHeader *p_Q2) // QHeader *p_Q1, *p_Q2; /* source and target queues */ { extern long int *next_after; /* array for pointers to data. */ long int temp; temp = p_Q1->Qfront; /* save front of Q1 */ p_Q1->Qfront = next_after[p_Q1->Qfront]; /* fast dequeue */ next_after[temp] = -1; /* fast enqueue */ next_after[p_Q2->Qrear] = temp; /* fast enqueue */ p_Q2->Qrear = temp; /* fast enqueue */ } /* This may come in handy when de-bugging. Note the reliance on the global arrays "next_after" and "data". */ void print_Q(QHeader *p_Q) // QHeader *p_Q; { extern long int *next_after; /* array for pointers to data. */ extern int *marker; /* To mark queues during radix sort */ extern int embed_dim; /* How many coordinates points have. */ extern ulong **data; /* array of data points */ long int temp; int coord; printf("Starting to print the queue:\n\n"); printf("Index\tNextField\tMarker?\t\tCoords\n\n"); temp = p_Q->Qfront; while (temp != -1) { printf("%ld\t%ld\t\t%d\t", temp, next_after[temp], marker[temp]); for (coord=0;coord *pmax) *pmax = temp; else if(temp < *pmin) *pmin = temp; if (debugging) printf ("Pmin is now: %lf, Pmax is now: %lf\n", *pmin, *pmax); } /* check to see if the maximum equals the minimum -- this is a degenerate case -- or it might mean that the input file is } faulty. */ if(*pmax == *pmin) { printf ("The input file, %s, is confusing!\n\n", userinputfile); printf ("Either all the points in %s have the same ", userinputfile); printf ("coordinates,\n"); printf ("(THE FRACTAL DIMENSION IS ZERO IN THIS CASE.)\n\n"); printf ("or %s is simply of the wrong form for an\n",userinputfile); printf ("input file to this program -- please check.\n"); exit(-1); } /* close the input file */ fclose(infile); } /* ################################################################## */ /* ################################################################## */ /* This procedure performs one pass of the radix sort. It assumes that the queues each have a marker in front at the time of the call, and this is the condition the procedure LEAVES the queues in when it terminates. */ void rad_pass(int coord, int bitpos) // int coord, /* The coordinate we are doing this pass on */ // bitpos; /* The bit position we are doing this pass on */ { extern int *marker; /* To mark queues during radix sort */ extern QHeader Q[2]; /* array of two queues for the radix sort */ extern ulong **data; /* initial array of data points */ int queue_num; long int index ; /* Move the markers to the rear of the queues */ if (debugging) printf ("Starting pass on bit %d of coord %d.\n",bitpos,coord); if (debugging) printf ("Moving markers to the rear of queues.\n"); for (queue_num=0;queue_num<2;queue_num++) { de_Q(&(Q[queue_num]),&index); en_Q(&(Q[queue_num]),index); } if (debugging) print_Q(&Q[0]); if (debugging) print_Q(&Q[1]); /* Move all non-marker elements to the appropriate queue. */ if (debugging) printf ("Starting main part of pass.\n"); for (queue_num=0;queue_num<2;queue_num++) { /* Peek first to see if Qfront is a marker -- this violates information hiding, and would be "cleaner" if done with a procedure in the queue package. */ while ( marker[Q[queue_num].Qfront] == 0 ) { /* Peeking again! */ if (IS_A_ONE(data[coord][Q[queue_num].Qfront],bitpos)) /* Directly transfer from the source to target queue */ transf_Q( &(Q[queue_num]),&(Q[1]) ); else transf_Q( &(Q[queue_num]),&(Q[0]) ) ; if (debugging) printf("A queue transfer is done. \n"); if (debugging) print_Q(&Q[0]); if (debugging) print_Q(&Q[1]); } } } /* ################################################################## */ /* ################################################################## */ /* THIS SORT IS TO BE USED DIRECTLY AFTER FDDRIVER DOES THE INITIAL LOADING OF THE DATA INTO THE QUEUES. IT LEAVES THE DATA ESSENTIALLY SORTED, WITH ALL THE DATA WHOSE X-COORD STARTS WITH 0 IN Q[0], IN ORDER, AND ALL THE DATA WHOSE X-COORD STARTS WITH 1 IN Q[1], IN ORDER. THUS THE SWEEP THAT COMES NEXT MUST TRAVERSE Q[0], AND THEN Q [1]. */ void radixsort() { extern QHeader Q[2]; /* ARRAY OF TWO QUEUES FOR THE RADIX SORT */ extern int embed_dim; /* HOW MANY COORDINATES POINTS HAVE. */ extern long int avail; /* AVAIL LIST POINTER */ int bitpos, coord, queue_num; long int index; /* FINISH UP ON THE ZERO-BIT -- LOADING DATA TOOK CARE OF FIRST PASS. */ for (coord=embed_dim-2;coord>=0;coord--) rad_pass(coord,0); /* NOW SORT ON THE REST OF THE BITS. */ for (bitpos=1;bitpos =0;coord--) rad_pass(coord,bitpos); /* LASTLY, GET THE MARKERS OUT OF THE QUEUES. */ for (queue_num=0;queue_num<2;queue_num++) { de_Q(&(Q[queue_num]),&index); push_Av(&avail,index); }} /* ################################################################## */ /* ################################################################## */ /* THIS PROCEDURE TRAVERSES THE SORTED DATA POINT LIST, AND EXTRACTS THE INFORMATION NEEDED TO COMPUTE THE CAPACITY, INFORMATION, AND CORRELATION DIMENSIONS OF THE DATA. DATA IS CORRECTED ON THE FLY DURING THE TRAVERSAL, AND THEN "MASSAGED". AFTER "SWEEP" RUNS, WE NEED ONLY FIT A SLOPE TO THE DATA TO OBTAIN THE FRACTAL DIMENSIONS. */ void sweep(ulong boxCountS[], double negLogBoxCountS[], double logSumSqrFreqS[], double informationS[]) // ulong boxCountS[numbits+1]; /* COUNT BOXES OF EACH SIZE */ // double /* FOR EACH BOX SIZE #s, negLogBoxCountS[s] WILL EVENTUALLY BE SET TO THE NEGATIVE OF THE LOG (BASE TWO) OF THE NUMBER OF BOXES OF SIZE #s THAT ARE OCCUPIED BY ONE OR MORE DATA POINTS. */ // negLogBoxCountS[numbits+1], /* FOR EACH BOX SIZE #s, logSumSqrFreqS[s] WILL EVENTUALLY BE SET TO THE LOG (BASE TWO) OF THE PROBABILITY THAT TWO RANDOMLY CHOSEN DATA POINTS ARE IN THE SAME BOX OF SIZE #s. */ // logSumSqrFreqS[numbits+1], /* FOR EACH BOX SIZE #s, informationS[s] WILL EVENTUALLY BE SET TO THE INFORMATION (BASE TWO) IN THE DISTRIBUTION OF DATA POINTS IN THE BOXES OF SIZE #s. */ // informationS[numbits+1] ; { extern int embed_dim; /* HOW MANY COORDINATES POINTS HAVE. */ extern ulong **data, /* INITIAL ARRAY OF DATA POINTS */ dataLines ; extern QHeader Q[2]; /* ARRAY OF TWO QUEUES FOR THE RADIX SORT */ extern ulong *diff_test; /* XOR'S OF PAIRS OF COORDINATES */ extern long int *next_after; /* ARRAY FOR POINTERS TO DATA. */ int bitpos, countpos, coord, queue_num, found; ulong pointCount[numbits+1] ; long int current, previous; double sumSqrFreq[numbits+1], freq, log2=log(2.0) ; /* GET A POINTER TO THE FIRST DATA VALUE */ if (Q[0].Qfront != -1) previous = Q[0].Qfront; else previous = Q[1].Qfront; /* INIT boxCountS, pointCountS, sumSqrFreq, AND informationS.*/ for(countpos=0;countpos<=numbits;countpos++) { boxCountS[countpos]=1; sumSqrFreq[countpos]=0.0; pointCount[countpos]=1; informationS[countpos]=0.0; } for (queue_num=0;queue_num<2;queue_num++) { current = Q[queue_num].Qfront; while (current != -1) { found = 0 ; /* START BY LOOKING AT THE BIGGEST BOX SIZE */ bitpos=numbits-1; for (coord=embed_dim-1;coord>=0;coord--) diff_test[coord] = data[coord][previous]^ data[coord][current]; do {coord = embed_dim - 1; do {/* IF THE CURRENT POINT AND PREVIOUS POINTS ARE IN DIFFERENT BOXES OF THIS SIZE, */ if ( IS_A_ONE(diff_test[coord],bitpos) ) {/* THEN THE CURRENT POINT IS IN NEW BOXES OF ALL SMALLER SIZES TOO, AND STILL IN THE SAME BOXES OF LARGER SIZES, SO ... */ for (countpos=bitpos;countpos>=0;countpos--) {/* CALCULATE FREQUENCY OF POINTS IN THE BOX, ASSUMING FOR NOW THAT THE NUMBER OF DATA LINES IN THE INPUT FILE IS THE NUMBER OF DISTINCT POINTS IN THE DATA SET. WE ADJUST THIS AT THE END OF THIS FUNCTION. */ if (debugging) printf("pointCount[%d] is %d...\n", countpos, pointCount[countpos]); freq = pointCount[countpos]/(double)dataLines ; /* WE WILL ENCOUNTER NO MORE OF THE POINTS IN THE BOX WE JUST LEFT (THE SPECIAL ORDERING OF THE SORT WE USED ABOVE GUARANTEES THIS!), SO WE COMPUTE WHAT THIS BOX CONTRIBUTES TO THE RUNNING SUMS. */ sumSqrFreq[countpos] += (freq * freq) ; informationS[countpos] += ( freq*log(freq)/log2 ) ; /* WE HAVE GOTTEN INTO A NEW BOX AT THIS LEVEL, SO WE REFLECT THE NEW BOX IN THE COUNT */ boxCountS[countpos]++ ; /* SINCE WE HAVE A NEW BOX AT THIS LEVEL, THERE IS ONLY ONE KNOWN POINT IN IT SO FAR -- THE CURRENT POINT */ pointCount[countpos]=1; } for (countpos=bitpos+1;countpos<=numbits;countpos++) /* THE CURRENT POINT IS IN THE BOXES AT THESE LEVELS, SO JUST INCREMENT THE POINT COUNTER. */ pointCount[countpos]++ ; found = 1; } else coord-- ; } while ( (found == 0) && (coord > -1) ); bitpos-- ; } while ( (found == 0) && (bitpos > -1) ); previous = current; current = next_after[current]; } } /* NOW ADD IN THE CONTRIBUTION DUE TO THE COUNTS REMAINING AFTER THE LAST POINT HAS BEEN FOUND, RENORMALIZE WITH BOXCOUNT[0], AND MASSAGE THE RAW DATA FROM THE TRAVERSAL SO THAT IS IS READY FOR THE LEAST SQUARES FITTING. */ for (countpos=numbits;countpos>=0;countpos--) { negLogBoxCountS[countpos] = -log((double)boxCountS[countpos])/log(2.0); if (debugging) printf("pointCount[%d] is %d...\n", countpos, pointCount[countpos]); freq = pointCount[countpos]/(double)dataLines ; sumSqrFreq[countpos] += (freq * freq) ; sumSqrFreq[countpos] *= (dataLines/(double) boxCountS[0]) ; sumSqrFreq[countpos] *= (dataLines/(double) boxCountS[0]) ; /* sumSqrFreq[countpos] NOW CONTAINS THE SUM OF THE SQUARES OF THE FREQUENCIES OF POINTS IN ALL OCCUPIED BOXES OF THE SIZE CORRESPONDING TO countpos. */ logSumSqrFreqS[countpos] = log(sumSqrFreq[countpos])/log(2.0) ; informationS[countpos] += ( freq*log(freq)/log(2.0) ) ; informationS[countpos] *= (dataLines/(double)boxCountS[0]) ; informationS[countpos] += ( log((double)dataLines)-log((double)boxCountS[0]) ) / log(2.0) ; /* information[countpos] NOW CONTAINS THE INFORMATION SUM FOR ALL THE OCCUPIED BOXES OF THIS SIZE. */ } } /* ################################################################## */ /* ################################################################## */ /* FIT LEAST SQUARE LINE TO DATA IN X,Y. NO PROTECTION AGAINST OVERFLOW HERE. IT IS ASSUMED THAT LAST > FIRST AND THAT THE X'S ARE NOT ALL THE SAME -- ELSE DIVISION BY ZERO WILL OCCUR. */ void fitLSqrLine (long first, long last, double X[], double Y[], double *slopePtr, double *interceptPtr) // long first, last ; // double X[], Y[], *slopePtr, *interceptPtr ; { int index , pointCount ; double Xsum=0, Ysum=0, XYsum=0, XXsum=0, Xmean=0, Ymean=0, Xtemp, Ytemp; for (index=first; index<=last; index++) { Xtemp = X[index]; Ytemp = Y[index]; Xsum += Xtemp; Ysum += Ytemp; XYsum += (Xtemp * Ytemp); XXsum += (Xtemp * Xtemp); } pointCount = last - first + 1 ; Xmean = Xsum/pointCount; Ymean = Ysum/pointCount; *slopePtr = (XYsum - Xsum * Ymean)/(XXsum - Xsum * Xmean) ; *interceptPtr = Ymean - *slopePtr * Xmean ; } /* ################################################################## */ /* ################################################################## */ /* MARK GREATEST INDEX WHERE COUNT > boxCountF[0]/cutOff_factor. COUNTS AT LESSER INDEXES WILL NOT BE USED IN THE ESTIMATE OF FRACTAL DIMENSION -- DISTORTION DUE TO SATURATION IS THE CONCERN. NOTE THAT boxCountF[0] IS THE NUMBER OF BOXES OF SIZE 1 (THE SMALLEST SIZE) THAT CONTAIN A POINT OF THE SET. FOR ALL PRACTICAL PURPOSES, boxCountF[0] WILL EQUAL THE NUMBER OF DISTINCT POINTS IN THE INPUT FILE, BECAUSE THESE BOXES ARE REALLY SMALL COMPARED TO THE SIZE OF THE BIGGEST BOX (ABOUT 4 BILLION IF AN UNSIGNED LONG INT IS 32 BITS TO THE PLATFORM COMPILER. THE POINTS ARE SCALED BY THE PROGRAM SO THAT THE SET IS TOO "LARGE" TO FIT IN THE NEXT SMALLEST BOX SIZE, SO THAT "1" IS THE SMALLEST DIFFERENCE IN VALUE THAT CAN BE RESOLVED.) ONE BOX, IN EFFECT, COVERS ONLY A SINGLE POINT OF THE INPUT SET BECAUSE THE PROGRAM CAN'T RESOLVE POINTS WITH A SMALLER DIFFERENCE. WE THINK IT WOULD BE A BAD IDEA TO USE dataLines/cutOff_factor AS THE LIMIT BECAUSE IN CASES WHERE THERE WERE MANY DUPLICATE POINTS, WE WOULD SERIOUSLY OVER-ESTIMATE THE NUMBER OF DISTINCT POINTS, AND THUS USE SATURATED DATA TO BASE THE ESTIMATE OF FRACTAL DIMENSION UPON. WHEN TESTING THE PROGRAM WITH RANDOM DATA SAMPLED WITH REPLACEMENT, THIS COULD THROW THE RESULTS WAY OFF. (THIS HAPPENED TO US, AND IT TOOK US A WHILE TO FIGURE OUT WHY. AFTERWARDS, WE STOPPED USING dataLines/cutOff_factor, AND CHANGED TO boxCountF[0]/cutOff_factor.) */ void findMark(ulong *markPtr, ulong boxCountM[]) // ulong *markPtr, boxCountM[numbits+1] ; { int i, cutOff_factor=1; /* Calculate cutOff_factor = 2^(embed_dim) + 1 */ for (i=1;i<=embed_dim;i++) cutOff_factor = cutOff_factor * 2; cutOff_factor++; *markPtr=0; for(i=0;i boxCountM[0]/cutOff_factor) *markPtr=i; } } /* ################################################################## */ /* ################################################################## */ void GetDims(double negLogBoxCountF[], double logSumSqrFreqF[], double informationF[], ulong markF, double *capDimPtr, double *infDimPtr, double *corrDimPtr) // ulong markF ; // double negLogBoxCountF[numbits+1], informationF[numbits+1], // logSumSqrFreqF[numbits+1], // *capDimPtr, *infDimPtr, *corrDimPtr; { int i; double logEps[numbits+1], slope, intercept; /* GET LOG (BASE 2) OF THE DIAMETER OF THE I'TH SIZE OF BOX. */ for(i=numbits; i>=0; i--) logEps[i] = i; /* fitLSqrLine (markF, numbits-4, logEps, negLogBoxCountF, &slope,&intercept);*/ fitLSqrLine (markF, numbits-2, logEps, negLogBoxCountF, &slope, &intercept); *capDimPtr = slope ; /*fitLSqrLine(markF, numbits-4, logEps, informationF, &slope, &intercept);*/ fitLSqrLine(markF, numbits-2, logEps, informationF, &slope, &intercept); *infDimPtr = slope ; /*fitLSqrLine(markF,numbits-4, logEps, logSumSqrFreqF, &slope, &intercept);*/ fitLSqrLine(markF,numbits-2, logEps, logSumSqrFreqF, &slope, &intercept); *corrDimPtr = slope ; } /* ################################################################## */ /* ################################################################## */ void main(int argc, char *argv[]) // int argc; // char *argv[]; { extern FILE *infile; extern int embed_dim, /* How many coordinates points have. */ *marker; /* To mark queues during radix sort */ extern ulong **data, /* initial array of data points */ dataLines, /* number of data points in input file */ *diff_test; /* XOR's of pairs of coordinates */ extern long int *next_after, /* array for pointers to data. */ avail; /* avail list pointer */ extern QHeader Q[2]; /* array of two queues for the radix sort */ int i,j,m; ulong maxdiam=0, /* 2^numbits - 1: determines the scaling. */ boxCount[numbits+1], /* Array to keep track of the box counts of each size. Each index is the base-2 log of the corresponding box size. */ pointCount[numbits+1], /* Array to keep track of how many points of the data set are contained in each box */ mark; /* Marks smallest usable box count */ double max, min, /* Maximum and minimum values in input file-- we need to know these in order to scale the input points. */ buf, /* A buffer for inputs to stay in until they are scaled and converted to integers. */ negLogBoxCount[numbits+1], logSumSqrFreq[numbits+1], information[numbits+1], capDim, infDim, corrDim; long int pointer; /* holds indexes used as pointers to records */ printf("\n\n") ; printf("******************************************************************\n"); printf(" FRACTAL DIMENSION REPORT -- by fd software (DiFalco/Sarraille)\n"); printf("******************************************************************\n"); printf("\n") ; /* IDENTIFY THE INPUT FILE */ printf ("\nReporting on file named: %s.\n\n", argv[1]) ; /* FIND OUT HOW MANY COORDINATES POINTS HAVE -- 1?, 2?, 3?, MORE? */ printf("Getting the embedding dimension ...\n"); embed_dim = get_e_dim(argv[1]); printf("Embedding Dimension taken to be: %d\n\n",embed_dim); /* find max and min in input file. This function should open the input file for reading, scan it to get the maximum and minimum data values it contains, and then seek to the beginning of the input file so that the code below can proceed to read the data sequentially from the beginning. We are having trouble getting that to work, so we have temporarily taken the expedient of closing the file in the function max_min, and opening it again below. */ printf("Finding max and min values in data ..."); fflush(stdout); max_min (argv[1], &max, &min) ; printf ("\n\nMinimum value in input file is: %lf ...\n", min) ; printf ("Maximum value in input file is: %lf ...\n\n", max) ; /* set maxdiam=2^numbits-1 -- this is the largest value that an unsigned integer can have with the host compiler. (I checked the value obtained in this manner, and it is correct -- j.s.) */ if (debugging || checking) printf("numbits is: %d\n",numbits); printf("%d different cell sizes will be used ...\n",numbits); for (m=0;m = numbits-2) { printf("\nInsufficient Data. More points are needed.\n") ; printf("Cannot assign a Fractal Dimension to this set.\n"); printf("Examine the data above to make your own conjecture.\n"); exit(-1) ; } printf ("\n\n\n%d is the smallest cell size used in ", mark); printf ("the overall dimension estimates\n"); printf ("below. The largest cell size is "); printf ("%d. Data above corresponding to\n", numbits-2); printf ("this range is between rows of asterisks.\n\n"); GetDims(negLogBoxCount, logSumSqrFreq, information, mark, &capDim, &infDim, &corrDim) ; printf("\n\nLeast-Square Estimates based on Indicated Cell Range:\n\n"); printf("Fractal Dimension (Capacity) = %.5f\n", capDim ); printf("Fractal Dimension (Information) = %.5f\n", infDim ); printf("Fractal Dimension (Correlation) = %.5f\n", corrDim); printf("\n\n****************************************\n"); }