[comp.sources.misc] config

timborn@ihlpg.UUCP (08/07/87)

From: ihlpg!timborn
Postmark: Pony Express
Date: Thu Aug 6 03:19:59 1987 IH
To: ihnp4!ptsfa!ames!ll-xn!husc6!necntc!ncoast!allbery
Subject: config

Here are some changes for UNIX System V systems.
They are enclosed in #ifdef SYSV/#endif.

tim
...ihnp4!hvlpb!tborn
Hilversum, Netherlands
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
/* Determine some properties of C types on your machine/compiler
   Author: Steven Pemberton, CWI, Amsterdam; steven@cwi.nl
   Bugfixes and upgrades gratefully received.

   The program only works if overflows are ignored by the C system or are
   catchable by signal().

   If your C system is not unix but does have signal/setjmp, compile with
	cc -DSIGNAL config.c
   otherwise with
	cc config.c
   Don't use any optimisation flags: the program won't work if you do.
   Some compilers need a -f flag for floating point.

   You may need to add some calls to signal() for other sorts of exception
   on your machine than SIGFPE, and SIGOVER. See lines beginning #ifdef
   SIGNAL later in the program.

   Output is produced as C style comments so that the program can be used to
   produce a .h file with minimum upheaval.

   I apologise unreservedly for the contorted use of the preprocessor...

   If your C preprocessor doesn't have the predefined __FILE__ macro, and
   you want to call this file anything other than config.c, change the
   following #define command accordingly.
*/

#ifndef __FILE__
#define __FILE__ "config.c"
#endif

#ifndef PASS
#define PASS 1

#include <stdio.h>

#ifdef SYSV
#include	<sys/utsname.h>
#include	<time.h>
#endif

#ifndef SIGNAL
#ifdef unix
#define SIGNAL
#endif /*unix*/
#endif /*SIGNAL*/

#ifdef SIGNAL

#include <signal.h>
#include <setjmp.h>

	jmp_buf lab;
	overflow(sig) int sig; { /* what to do on overflow/underflow */
		(void) signal(sig, overflow);
		longjmp(lab, 1);
	}

#else /*!SIGNAL*/
	/* Dummy routines instead */
	int lab=1;
	int setjmp(lab) int lab; { return(0); }

#endif /*SIGNAL*/

main() {
	int bits; /* the number of bits per unit returned by sizeof() */
	int dprec, eprec, basic(), fprop(), dprop(), eprop();
	char *malloc();
	unsigned int size;
	long total;

#ifdef SYSV
	struct utsname name;
	long	tloc;
#endif

#ifdef SIGNAL
#ifdef SIGFPE
	(void) signal(SIGFPE, overflow);
#endif
#ifdef SIGOVER
	(void) signal(SIGOVER, overflow);
#endif
/* Add more calls as necessary */
#endif /* SIGNAL */

	if (setjmp(lab)!=0) { printf("Unexpected over/underflow\n"); exit(1); }

#ifdef SYSV
	/* show the machine name and date at the top of the output for reference */
	printf("/\* Machine: ");
	uname(&name);
	printf("%s %s %s %s %s *\/\n",
		name.sysname, 
		name.nodename, 
		name.release, 
		name.version, 
		name.machine);
	tloc = time( (long *) 0);
	/* precision for date string required to avoid \n returned from asctime() */
	printf("/\* Date: %.24s *\/\n", asctime(localtime(&tloc)) );
#endif

	bits=  basic();
	(void) fprop(bits);
	dprec= dprop(bits);
	eprec= eprop();
	printf("\n");
	if (eprec!=dprec)
		printf("/\* Expressions are evaluated in a %s %s %d %s *\/\n",
			eprec>dprec ? "higher" : "lower (tut!)",
			"precision than double, using", eprec, "base digits");
	else printf("/\* Expressions are evaluated in double precision *\/\n");

	/* An extra goody: the approximate amount of data-space */
	/* Allocate store until no more available */
	size=1<<((bits*sizeof(int))-2);
	total=0;
	while (size!=0) {
		while (malloc(size)!=(char *)NULL) total+=(size/2);
		size/=2;
	}

	printf("\n/\* Memory mallocatable ~= %ld Kbytes *\/\n",
						(total+511)/512);
}

int basic() {
	/* The properties of the basic types.
	   Returns number of bits per sizeof unit */

	char c; int bits;

	if (setjmp(lab)!=0) { printf("\nUnexpected under/overflow\n"); exit(1); }

	/* Calculate number of bits per character *************************/
	c=1; bits=0;
	do { c=c<<1; bits++; } while(c!=0);
	c= (char)(-1);
	printf("/\* Char = %d bits, %ssigned *\/\n", sizeof(c)*bits,
			((int)c)<0?"":"un");

	/* Shorts, ints and longs *****************************************/
	sprop();
	iprop();
	lprop();

	if (setjmp(lab)!=0) { printf("\nUnexpected under/overflow\n"); exit(1); }

	/* Alignment constants ********************************************/
	printf("/\* Alignments for char=%d short=%d int=%d long=%d *\/\n",
		sizeof(struct{char i; char c;})-sizeof(char),
		sizeof(struct{short i; char c;})-sizeof(short),
		sizeof(struct{int i; char c;})-sizeof(int),
		sizeof(struct{long i; char c;})-sizeof(long));

	/* Pointers *******************************************************/
	printf("/\* Char pointers = %d bits%s *\/\n", sizeof(char *)*bits,
		sizeof(char *)>sizeof(int)?" BEWARE! larger than int!":"");
	printf("/\* Int pointers = %d bits%s *\/\n", sizeof(int *)*bits,
		sizeof(int *)>sizeof(int)?" BEWARE! larger than int!":"");

	return bits;
}

int log(base, x) int base; double x; {
	int r=0;
	while (x>=base) { r++; x/=base; }
	return r;
}

int eprop() { /* See if expressions are evaluated in extended precision */
	int imant;
	double a, b, base;

	if (setjmp(lab)!=0) { printf("\nUnexpected under/overflow\n"); exit(1); }

	/* Size of mantissa **************************************/
	a=1.0;
	do { a=a+a; } while ((((a+1.0)-a)-1.0) == 0.0);
	b=1.0;
	do { b=b+b; } while ((base=((a+b)-a)) == 0.0);

	imant=0; b=1.0;
	do { imant++; b=b*base; }
	while ((((b+1.0)-b)-1.0) == 0.0);
	return imant;
}

#define fabs(x) (((x)<0.0)?(-x):(x))

#endif /* ifndef PASS */

/* As I said, I apologise for the contortions below. The procedures are
   expanded twice (for float and double) or three times (for short, int and
   long) by the preprocessor. That way, I never make a change to one that
   I forget to make to the other. #undef on an already undefined thing
   is (wrongly) flagged as an error by some compilers, therefore the #ifdef
   that follows: 
*/

#ifdef Number
#undef Number
#undef THING
#undef FPROP
#undef Store
#undef Sum
#undef Diff
#undef Mul
#undef Div
#endif

#ifdef Integer
#undef Integer
#undef INT
#undef IPROP
#endif

#if PASS == 1

#define Number float
#define THING "float"
#define FPROP fprop
#define Store fStore
#define Sum fSum
#define Diff fDiff
#define Mul fMul
#define Div fDiv

#define Integer short
#define INT "short"
#define IPROP sprop

#endif /* PASS == 1 */

#if PASS == 2

#define Number double
#define THING "double"
#define FPROP dprop
#define Store dStore
#define Sum dSum
#define Diff dDiff
#define Mul dMul
#define Div dDiv

#define Integer int
#define INT "int"
#define IPROP iprop

#endif /* if PASS == 2 */

#if PASS == 3

#define Integer long
#define INT "long"
#define IPROP lprop

#endif /* if PASS == 3 */

IPROP() {
	Integer newi, maxi, maxeri;
	int ibits, ipower, two=2;

	/* Calculate max short/int/long ***********************************/
	/* Calculate 2**n-1 until overflow - then use the previous value  */

	newi=1; maxi=0;

	if (setjmp(lab)==0)
		for(ipower=0; newi>maxi; ipower++) {
			maxi=newi;
			newi=newi*two+1;
		}

	/* Now for those daft Cybers: */

	maxeri=0; newi=maxi;

	if (setjmp(lab)==0)
		for(ibits=ipower; newi>maxeri; ibits++) {
			maxeri=newi;
			newi=newi+newi+1;
		}

	printf("/\* Maximum %s = %ld (= 2**%d-1) *\/\n",
				INT, (long)maxi, ipower);

	if (maxeri>maxi) {
		printf("/\* There is a larger %s, %ld (= 2**%d-1), %s *\/\n",
			INT, (long)maxeri, ibits, 
			"but only for addition, not multiplication");
	}
}

#ifdef Number

/* These routines are intended to defeat any attempt at optimisation */
Store(a, b) Number a, *b; { *b=a; }
Number Sum(a, b) Number a, b; { Number r; Store(a+b, &r); return (r); }
Number Diff(a, b) Number a, b; { Number r; Store(a-b, &r); return (r); }
Number Mul(a, b) Number a, b; { Number r; Store(a*b, &r); return (r); }
Number Div(a, b) Number a, b; { Number r; Store(a/b, &r); return (r); }

int FPROP(bits) int bits; {
	/* Properties of floating types, using algorithms by Cody and Waite
	   from MA Malcolm, as modified by WM Gentleman and SB Marovich.
	   Further extended by S Pemberton.

	   Returns the number of digits in the fraction.
	*/

	int i, ibase, iexp, irnd, imant, iz, k, machep, maxexp, minexp,
	    mx, negeps, mantbits;
	Number a, b, base, basein, basem1, eps, epsneg, xmax, newxmax,
	       xmin, xminner, y, y1, z, z1, z2;

	if (setjmp(lab)!=0) { printf("Unexpected over/underflow\n"); exit(1); }

	printf("\n/\* Properties of %s: *\/\n", THING);

	/* Base and size of mantissa **************************************/
	a=1.0;
	do { a=Sum(a, a); } while (Diff(Diff(Sum(a, 1.0), a), 1.0) == 0.0);
	b=1.0;
	do { b=Sum(b, b); } while ((base=Diff(Sum(a, b), a)) == 0.0);
	ibase=base;
	printf("/\* Base = %d *\/\n", ibase);

	imant=0; b=1.0;
	do { imant++; b=Mul(b, base); }
	while (Diff(Diff(Sum(b,1.0),b),1.0) == 0.0);
	printf("/\* Significant base digits = %d %s %d %s *\/\n",
			imant, "(= at least", log(10, (double)b),
			"decimal digits)");

	/* Various flavours of epsilon ************************************/
	basem1=Diff(base,1.0);
	if (Diff(Sum(a, basem1), a) != 0.0) irnd=1; 
	else irnd=0;

	negeps=imant+imant;
	basein=1.0/base;
	a=1.0;
	for(i=1; i<=negeps; i++) a*=basein;

	b=a;
	while (Diff(Diff(1.0, a), 1.0) == 0.0) {
		a*=base;
		negeps--;
	}
	negeps= -negeps;
	printf("/\* Smallest x such that 1.0-base**x != 1.0 = %d *\/\n", negeps);

	epsneg=a;
	if ((ibase!=2) && (irnd==1)) {
	/*	a=(a*(1.0+a))/(1.0+1.0); => */
		a=Div(Mul(a, Sum(1.0, a)), Sum(1.0, 1.0));
	/*	if ((1.0-a)-1.0 != 0.0) epsneg=a; => */
		if (Diff(Diff(1.0, a), 1.0) != 0.0) epsneg=a;
	}
	printf("/\* Small x such that 1.0-x != 1.0 = %g *\/\n", epsneg);
	/* it may not be the smallest */

	machep= -imant-imant;
	a=b;
	while (Diff(Sum(1.0, a), 1.0) == 0.0) { a*=base; machep++; }
	printf("/\* Smallest x such that 1.0+base**x != 1.0 = %d *\/\n", machep);

	eps=a;
	if ((ibase!=2) && (irnd==1)) {
	/*	a=(a*(1.0+a))/(1.0+1.0); => */
		a=Div(Mul(a, Sum(1.0, a)), Sum(1.0, 1.0));
	/*	if ((1.0+a)-1.0 != 0.0) eps=a; => */
		if (Diff(Sum(1.0, a), 1.0) != 0.0) eps=a;
	}
	printf("/\* Smallest x such that 1.0+x != 1.0 = %g *\/\n", eps);

	/* Round or chop **************************************************/
	if (irnd == 1) { printf("/\* Arithmetic rounds *\/\n"); }
	else { 
		printf("/\* Arithmetic chops");
		if (Diff(Mul(Sum(1.0,eps),1.0),1.0) !=  0.0) {
			printf(" but uses guard digits");
		}
		printf(" *\/\n");
	}

	/* Size of and minimum normalised exponent ************************/
	y=0; i=0; k=1; z=basein; z1=(1.0+eps)/base;

	/* Coarse search for the largest power of two */
	if (setjmp(lab)==0) /* in case of underflow trap */
		do {
			y=z; y1=z1;
			z=Mul(y,y); z1=Mul(z1, y);
			a=Mul(z,1.0);
			z2=Div(z1,y);
			if (z2 != y1) break;
			if ((Sum(a,a) == 0.0) || (fabs(z) >= y)) break;
			i++;
			k+=k;
		} while(1);

	if (ibase != 10) {
		iexp=i+1; /* for the sign */
		mx=k+k;
	} else {
		iexp=2;
		iz=ibase;
		while (k >= iz) { iz*=ibase; iexp++; }
		mx=iz+iz-1;
	}

	/* Fine tune starting with y and y1 */
	if (setjmp(lab)==0) /* in case of underflow trap */
		do {
			xmin=y; z1=y1;
			y=Div(y,base); y1=Div(y1,base);
			a=Mul(y,1.0);
			z2=Mul(y1,base);
			if (z2 != z1) break;
			if ((Sum(a,a) == 0.0) || (fabs(y) >= xmin)) break;
			k++;
		} while (1);

	if (setjmp(lab)!=0) { printf("Unexpected over/underflow\n"); exit(1); }

	minexp=(-k)+1;

	if ((mx <= k+k-3) && (ibase != 10)) { mx+=mx; iexp+=1; }
	printf("/\* Number of bits used for exponent = %d *\/\n", iexp);
	printf("/\* Minimum normalised exponent = %d *\/\n", minexp);
	printf("/\* Minimum normalised positive number = %g *\/\n", xmin);

	/* Minimum exponent ************************************************/
	if (setjmp(lab)==0) /* in case of underflow trap */
		do {
			xminner=y;
			y=Div(y,base);
			a=Mul(y,1.0);
			if ((Sum(a,a) == 0.0) || (fabs(y) >= xminner)) break;
		} while (1);

	if (setjmp(lab)!=0) { printf("Unexpected over/underflow\n"); exit(1); }

	if (xminner != 0.0 && xminner != xmin) {
		printf("/\* The smallest numbers are not kept normalised *\/\n");
		printf("/\* Smallest unnormalised positive number = %g *\/\n",
			xminner);
	} else printf("/\* The smallest numbers are normalised *\/\n");

	/* Maximum exponent ************************************************/
	maxexp=2; xmax=1.0; newxmax=base+1.0;
	if (setjmp(lab) == 0) {
		while (xmax<newxmax) {
			xmax=newxmax;
			newxmax=Mul(newxmax, base);
			if (Div(newxmax, base) != xmax) break; /* ieee infinity */
			maxexp++;
		}
	}
	if (setjmp(lab)!=0) { printf("Unexpected over/underflow\n"); exit(1); }

	printf("/\* Maximum exponent = %d *\/\n", maxexp);

	/* Largest number ***************************************************/
	xmax=Diff(1.0, epsneg);
	if (Mul(xmax,1.0) != xmax) xmax=Diff(1.0, Mul(base,epsneg));
	for (i=1; i<=maxexp; i++) xmax=Mul(xmax, base);
	printf("/\* Maximum number = %g *\/\n", xmax);

	/* Hidden bit + sanity check ****************************************/
	if (ibase != 10) {
		mantbits=log(2, (double)ibase)*imant;
		if (mantbits+iexp+1 == sizeof(Number)*bits+1) {
			printf("/\* Arithmetic uses a hidden bit *\/\n");
		} else if (mantbits+iexp+1 == sizeof(Number)*bits) {
			printf("/\* Arithmetic doesn't use a hidden bit *\/\n");
		} else {
			printf("/\* Something fishy here! %s %s %s *\/\n",
				"Exponent size + mantissa size doesn't match",
				"with the size of a", THING);
		}
	}
	return imant;
}

#endif /* ifdef Number */

#if PASS == 3
#undef PASS
#define PASS 4
#endif

#if PASS == 2
#undef PASS
#define PASS 3
#endif

#if PASS == 1
#undef PASS
#define PASS 2
#endif

#if PASS < 4
#include __FILE__
#endif