home *** CD-ROM | disk | FTP | other *** search
- From: steven@cwi.nl.UUCP (Steven Pemberton)
- Newsgroups: comp.sources.misc
- Subject: A C configuration enquirer
- Message-ID: <3748@ncoast.UUCP>
- Date: 5 Aug 87 00:29:07 GMT
- Sender: allbery@ncoast.UUCP
- Organization: CWI, Amsterdam
- Lines: 621
- Approved: allbery@ncoast.UUCP
- X-Archive: comp.sources.misc/8708/3
-
- config.c - a C configuration enquirer
- Author: Steven Pemberton, CWI, Amsterdam
-
- This program determines properties of your machine and C compiler, such as
- the number of bits used for certain data-types, the accuracy of float and
- double, and so on.
-
- The original purpose of the program was to generate a header-file for a
- large piece of software that must be as portable as possible. However, it is
- also a good check for a new compiler. It is the descendent of a similar
- program I posted a year or so ago. However it is completely rewritten, and
- incorporates much experience with the use of that program, and ideas from
- users of it.
-
- Output is produced as C style comments so that the program can be used to
- produce a .h file with minimum upheaval.
-
- Any ideas for future enhancements, and all fixes to make it run on machines
- where it doesn't currently run, will be gratefully received. Please mail me
- at
- steven@cwi.nl (new style) or seismo!mcvax!steven (old style)
-
- Steven Pemberton, Centre for Mathematics and Computer Science
- Amsterdam, The Netherlands
-
- : This is a shell archive.
- : Extract with 'sh this_file'.
- echo 'Start of pack.out, part 01 out of 01:'
- echo 'x - Makefile'
- sed 's/^X//' > 'Makefile' << 'EOF'
- Xconfig:
- X cc config.c -o config
- EOF
- echo 'x - READ.ME'
- sed 's/^X//' > 'READ.ME' << 'EOF'
- X config.c - a C configuration enquirer
- X Author: Steven Pemberton, CWI, Amsterdam
- X
- XThis program determines properties of your machine and C compiler, such as
- Xthe number of bits used for certain data-types, the accuracy of float and
- Xdouble, and so on.
- X
- XThe original purpose of the program was to generate a header-file for a
- Xlarge piece of software that must be as portable as possible. However, it is
- Xalso a good check for a new compiler. It is the descendent of a similar
- Xprogram I posted a year or so ago. However it is completely rewritten, and
- Xincorporates much experience with the use of that program, and ideas from
- Xusers of it.
- X
- XThe program only works if overflows are ignored by the C system or are
- Xcatchable by signal().
- X
- XIf your C system is not unix but does have signal/setjmp, compile with
- X cc -DSIGNAL config.c
- Xotherwise with
- X cc config.c
- XDon't use any optimisation flags.
- XSome compilers need a -f flag for floating point.
- X
- XYou may need to add some calls to signal() for other sorts of exception on
- Xyour machine than SIGFPE, and SIGOVER. See lines beginning #ifdef SIGNAL
- Xlater in the program.
- X
- XOutput is produced as C style comments so that the program can be used to
- Xproduce a .h file with minimum upheaval.
- X
- XI apologise unreservedly for the contorted use of the preprocessor...
- X
- XIf your C preprocessor doesn't have the predefined __FILE__ macro, and you
- Xwant to call the file anything other than config.c, change the first
- X#define command accordingly.
- X
- XAny ideas for future enhancements, and all fixes to make it run on machines
- Xwhere it doesn't currently run, will be gratefully received. Please mail me
- Xat
- X steven@cwi.nl (new style) or seismo!mcvax!steven (old style)
- X
- XSteven Pemberton, Centre for Mathematics and Computer Science
- XAmsterdam, The Netherlands
- EOF
- echo 'x - config.1'
- sed 's/^X//' > 'config.1' << 'EOF'
- X.TH config 8 local
- X.SH NAME
- Xconfig \(em print details of your machine and C compiler configuration
- X.SH SYNOPSIS
- Xconfig
- X.SH DESCRIPTION
- XConfig determines and prints out several properties of the C compiler it is
- Xcompiled with and the machine it is run on.
- XAmong the properties it gives are
- X.br
- X.in +1c
- X\(em the number of bits in a char, and whether chars are signed or not;
- X.br
- X\(em the maximum short, int, and long;
- X.br
- X\(em alignment values for char, short, int and long;
- X.br
- X\(em number of bits for char and int pointers, with a warning if they are longer
- Xthan int;
- X.in -1c
- X.sp
- Xand then for float and double:
- X.br
- X.in +1c
- X\(em the base used;
- X.br
- X\(em number of significant digits;
- X.br
- X\(em certain minumum and maximum values;
- X.br
- X\(em whether arithmetic rounds or chops;
- X.br
- X\(em whether a hidden bit is used or not;
- X.br
- X\(em etc.
- X.in -1c
- X.sp
- XFinally the total amount of memory that can be allocated by malloc(3) is
- Xprinted.
- X.SH DIAGNOSTICS
- XThe output is printed as a series of C comments, so that the program can be
- Xused to produce header files for C programs without too much upheaval.
- X.SH BUGS
- XThe program won't work if overflow causes a trap,
- Xand the trap can't be caught by signal(2).
- EOF
- echo 'x - config.c'
- sed 's/^X//' > 'config.c' << 'EOF'
- X/* Determine some properties of C types on your machine/compiler
- X Author: Steven Pemberton, CWI, Amsterdam; steven@cwi.nl
- X Bugfixes and upgrades gratefully received.
- X
- X The program only works if overflows are ignored by the C system or are
- X catchable by signal().
- X
- X If your C system is not unix but does have signal/setjmp, compile with
- X cc -DSIGNAL config.c
- X otherwise with
- X cc config.c
- X Don't use any optimisation flags: the program won't work if you do.
- X Some compilers need a -f flag for floating point.
- X
- X You may need to add some calls to signal() for other sorts of exception
- X on your machine than SIGFPE, and SIGOVER. See lines beginning #ifdef
- X SIGNAL later in the program.
- X
- X Output is produced as C style comments so that the program can be used to
- X produce a .h file with minimum upheaval.
- X
- X I apologise unreservedly for the contorted use of the preprocessor...
- X
- X If your C preprocessor doesn't have the predefined __FILE__ macro, and
- X you want to call this file anything other than config.c, change the
- X following #define command accordingly.
- X*/
- X
- X#ifndef __FILE__
- X#define __FILE__ "config.c"
- X#endif
- X
- X#ifndef PASS
- X#define PASS 1
- X
- X#include <stdio.h>
- X
- X#ifndef SIGNAL
- X#ifdef unix
- X#define SIGNAL
- X#endif /*unix*/
- X#endif /*SIGNAL*/
- X
- X#ifdef SIGNAL
- X
- X#include <signal.h>
- X#include <setjmp.h>
- X
- X jmp_buf lab;
- X overflow(sig) int sig; { /* what to do on overflow/underflow */
- X (void) signal(sig, overflow);
- X longjmp(lab, 1);
- X }
- X
- X#else /*!SIGNAL*/
- X /* Dummy routines instead */
- X int lab=1;
- X int setjmp(lab) int lab; { return(0); }
- X
- X#endif /*SIGNAL*/
- X
- Xmain() {
- X int bits; /* the number of bits per unit returned by sizeof() */
- X int dprec, eprec, basic(), fprop(), dprop(), eprop();
- X char *malloc();
- X unsigned int size;
- X long total;
- X
- X#ifdef SIGNAL
- X#ifdef SIGFPE
- X (void) signal(SIGFPE, overflow);
- X#endif
- X#ifdef SIGOVER
- X (void) signal(SIGOVER, overflow);
- X#endif
- X/* Add more calls as necessary */
- X#endif /* SIGNAL */
- X
- X if (setjmp(lab)!=0) { printf("Unexpected over/underflow\n"); exit(1); }
- X
- X bits= basic();
- X (void) fprop(bits);
- X dprec= dprop(bits);
- X eprec= eprop();
- X printf("\n");
- X if (eprec!=dprec)
- X printf("/\* Expressions are evaluated in a %s %s %d %s *\/\n",
- X eprec>dprec ? "higher" : "lower (tut!)",
- X "precision than double, using", eprec, "base digits");
- X else printf("/\* Expressions are evaluated in double precision *\/\n");
- X
- X /* An extra goody: the approximate amount of data-space */
- X /* Allocate store until no more available */
- X size=1<<((bits*sizeof(int))-2);
- X total=0;
- X while (size!=0) {
- X while (malloc(size)!=(char *)NULL) total+=(size/2);
- X size/=2;
- X }
- X
- X printf("\n/\* Memory mallocatable ~= %ld Kbytes *\/\n",
- X (total+511)/512);
- X}
- X
- Xint basic() {
- X /* The properties of the basic types.
- X Returns number of bits per sizeof unit */
- X
- X char c; int bits;
- X
- X if (setjmp(lab)!=0) { printf("\nUnexpected under/overflow\n"); exit(1); }
- X
- X /* Calculate number of bits per character *************************/
- X c=1; bits=0;
- X do { c=c<<1; bits++; } while(c!=0);
- X c= (char)(-1);
- X printf("/\* Char = %d bits, %ssigned *\/\n", sizeof(c)*bits,
- X ((int)c)<0?"":"un");
- X
- X /* Shorts, ints and longs *****************************************/
- X sprop();
- X iprop();
- X lprop();
- X
- X if (setjmp(lab)!=0) { printf("\nUnexpected under/overflow\n"); exit(1); }
- X
- X /* Alignment constants ********************************************/
- X printf("/\* Alignments for char=%d short=%d int=%d long=%d *\/\n",
- X sizeof(struct{char i; char c;})-sizeof(char),
- X sizeof(struct{short i; char c;})-sizeof(short),
- X sizeof(struct{int i; char c;})-sizeof(int),
- X sizeof(struct{long i; char c;})-sizeof(long));
- X
- X /* Pointers *******************************************************/
- X printf("/\* Char pointers = %d bits%s *\/\n", sizeof(char *)*bits,
- X sizeof(char *)>sizeof(int)?" BEWARE! larger than int!":"");
- X printf("/\* Int pointers = %d bits%s *\/\n", sizeof(int *)*bits,
- X sizeof(int *)>sizeof(int)?" BEWARE! larger than int!":"");
- X
- X return bits;
- X}
- X
- Xint log(base, x) int base; double x; {
- X int r=0;
- X while (x>=base) { r++; x/=base; }
- X return r;
- X}
- X
- Xint eprop() { /* See if expressions are evaluated in extended precision */
- X int imant;
- X double a, b, base;
- X
- X if (setjmp(lab)!=0) { printf("\nUnexpected under/overflow\n"); exit(1); }
- X
- X /* Size of mantissa **************************************/
- X a=1.0;
- X do { a=a+a; } while ((((a+1.0)-a)-1.0) == 0.0);
- X b=1.0;
- X do { b=b+b; } while ((base=((a+b)-a)) == 0.0);
- X
- X imant=0; b=1.0;
- X do { imant++; b=b*base; }
- X while ((((b+1.0)-b)-1.0) == 0.0);
- X return imant;
- X}
- X
- X#define fabs(x) (((x)<0.0)?(-x):(x))
- X
- X#endif /* ifndef PASS */
- X
- X/* As I said, I apologise for the contortions below. The procedures are
- X expanded twice (for float and double) or three times (for short, int and
- X long) by the preprocessor. That way, I never make a change to one that
- X I forget to make to the other. #undef on an already undefined thing
- X is (wrongly) flagged as an error by some compilers, therefore the #ifdef
- X that follows:
- X*/
- X
- X#ifdef Number
- X#undef Number
- X#undef THING
- X#undef FPROP
- X#undef Store
- X#undef Sum
- X#undef Diff
- X#undef Mul
- X#undef Div
- X#endif
- X
- X#ifdef Integer
- X#undef Integer
- X#undef INT
- X#undef IPROP
- X#endif
- X
- X#if PASS == 1
- X
- X#define Number float
- X#define THING "float"
- X#define FPROP fprop
- X#define Store fStore
- X#define Sum fSum
- X#define Diff fDiff
- X#define Mul fMul
- X#define Div fDiv
- X
- X#define Integer short
- X#define INT "short"
- X#define IPROP sprop
- X
- X#endif /* PASS == 1 */
- X
- X#if PASS == 2
- X
- X#define Number double
- X#define THING "double"
- X#define FPROP dprop
- X#define Store dStore
- X#define Sum dSum
- X#define Diff dDiff
- X#define Mul dMul
- X#define Div dDiv
- X
- X#define Integer int
- X#define INT "int"
- X#define IPROP iprop
- X
- X#endif /* if PASS == 2 */
- X
- X#if PASS == 3
- X
- X#define Integer long
- X#define INT "long"
- X#define IPROP lprop
- X
- X#endif /* if PASS == 3 */
- X
- XIPROP() {
- X Integer newi, maxi, maxeri;
- X int ibits, ipower, two=2;
- X
- X /* Calculate max short/int/long ***********************************/
- X /* Calculate 2**n-1 until overflow - then use the previous value */
- X
- X newi=1; maxi=0;
- X
- X if (setjmp(lab)==0)
- X for(ipower=0; newi>maxi; ipower++) {
- X maxi=newi;
- X newi=newi*two+1;
- X }
- X
- X /* Now for those daft Cybers: */
- X
- X maxeri=0; newi=maxi;
- X
- X if (setjmp(lab)==0)
- X for(ibits=ipower; newi>maxeri; ibits++) {
- X maxeri=newi;
- X newi=newi+newi+1;
- X }
- X
- X printf("/\* Maximum %s = %ld (= 2**%d-1) *\/\n",
- X INT, (long)maxi, ipower);
- X
- X if (maxeri>maxi) {
- X printf("/\* There is a larger %s, %ld (= 2**%d-1), %s *\/\n",
- X INT, (long)maxeri, ibits,
- X "but only for addition, not multiplication");
- X }
- X}
- X
- X#ifdef Number
- X
- X/* These routines are intended to defeat any attempt at optimisation */
- XStore(a, b) Number a, *b; { *b=a; }
- XNumber Sum(a, b) Number a, b; { Number r; Store(a+b, &r); return (r); }
- XNumber Diff(a, b) Number a, b; { Number r; Store(a-b, &r); return (r); }
- XNumber Mul(a, b) Number a, b; { Number r; Store(a*b, &r); return (r); }
- XNumber Div(a, b) Number a, b; { Number r; Store(a/b, &r); return (r); }
- X
- Xint FPROP(bits) int bits; {
- X /* Properties of floating types, using algorithms by Cody and Waite
- X from MA Malcolm, as modified by WM Gentleman and SB Marovich.
- X Further extended by S Pemberton.
- X
- X Returns the number of digits in the fraction.
- X */
- X
- X int i, ibase, iexp, irnd, imant, iz, k, machep, maxexp, minexp,
- X mx, negeps, mantbits;
- X Number a, b, base, basein, basem1, eps, epsneg, xmax, newxmax,
- X xmin, xminner, y, y1, z, z1, z2;
- X
- X if (setjmp(lab)!=0) { printf("Unexpected over/underflow\n"); exit(1); }
- X
- X printf("\n/\* Properties of %s: *\/\n", THING);
- X
- X /* Base and size of mantissa **************************************/
- X a=1.0;
- X do { a=Sum(a, a); } while (Diff(Diff(Sum(a, 1.0), a), 1.0) == 0.0);
- X b=1.0;
- X do { b=Sum(b, b); } while ((base=Diff(Sum(a, b), a)) == 0.0);
- X ibase=base;
- X printf("/\* Base = %d *\/\n", ibase);
- X
- X imant=0; b=1.0;
- X do { imant++; b=Mul(b, base); }
- X while (Diff(Diff(Sum(b,1.0),b),1.0) == 0.0);
- X printf("/\* Significant base digits = %d %s %d %s *\/\n",
- X imant, "(= at least", log(10, (double)b),
- X "decimal digits)");
- X
- X /* Various flavours of epsilon ************************************/
- X basem1=Diff(base,1.0);
- X if (Diff(Sum(a, basem1), a) != 0.0) irnd=1;
- X else irnd=0;
- X
- X negeps=imant+imant;
- X basein=1.0/base;
- X a=1.0;
- X for(i=1; i<=negeps; i++) a*=basein;
- X
- X b=a;
- X while (Diff(Diff(1.0, a), 1.0) == 0.0) {
- X a*=base;
- X negeps--;
- X }
- X negeps= -negeps;
- X printf("/\* Smallest x such that 1.0-base**x != 1.0 = %d *\/\n", negeps);
- X
- X epsneg=a;
- X if ((ibase!=2) && (irnd==1)) {
- X /* a=(a*(1.0+a))/(1.0+1.0); => */
- X a=Div(Mul(a, Sum(1.0, a)), Sum(1.0, 1.0));
- X /* if ((1.0-a)-1.0 != 0.0) epsneg=a; => */
- X if (Diff(Diff(1.0, a), 1.0) != 0.0) epsneg=a;
- X }
- X printf("/\* Small x such that 1.0-x != 1.0 = %g *\/\n", epsneg);
- X /* it may not be the smallest */
- X
- X machep= -imant-imant;
- X a=b;
- X while (Diff(Sum(1.0, a), 1.0) == 0.0) { a*=base; machep++; }
- X printf("/\* Smallest x such that 1.0+base**x != 1.0 = %d *\/\n", machep);
- X
- X eps=a;
- X if ((ibase!=2) && (irnd==1)) {
- X /* a=(a*(1.0+a))/(1.0+1.0); => */
- X a=Div(Mul(a, Sum(1.0, a)), Sum(1.0, 1.0));
- X /* if ((1.0+a)-1.0 != 0.0) eps=a; => */
- X if (Diff(Sum(1.0, a), 1.0) != 0.0) eps=a;
- X }
- X printf("/\* Smallest x such that 1.0+x != 1.0 = %g *\/\n", eps);
- X
- X /* Round or chop **************************************************/
- X if (irnd == 1) { printf("/\* Arithmetic rounds *\/\n"); }
- X else {
- X printf("/\* Arithmetic chops");
- X if (Diff(Mul(Sum(1.0,eps),1.0),1.0) != 0.0) {
- X printf(" but uses guard digits");
- X }
- X printf(" *\/\n");
- X }
- X
- X /* Size of and minimum normalised exponent ************************/
- X y=0; i=0; k=1; z=basein; z1=(1.0+eps)/base;
- X
- X /* Coarse search for the largest power of two */
- X if (setjmp(lab)==0) /* in case of underflow trap */
- X do {
- X y=z; y1=z1;
- X z=Mul(y,y); z1=Mul(z1, y);
- X a=Mul(z,1.0);
- X z2=Div(z1,y);
- X if (z2 != y1) break;
- X if ((Sum(a,a) == 0.0) || (fabs(z) >= y)) break;
- X i++;
- X k+=k;
- X } while(1);
- X
- X if (ibase != 10) {
- X iexp=i+1; /* for the sign */
- X mx=k+k;
- X } else {
- X iexp=2;
- X iz=ibase;
- X while (k >= iz) { iz*=ibase; iexp++; }
- X mx=iz+iz-1;
- X }
- X
- X /* Fine tune starting with y and y1 */
- X if (setjmp(lab)==0) /* in case of underflow trap */
- X do {
- X xmin=y; z1=y1;
- X y=Div(y,base); y1=Div(y1,base);
- X a=Mul(y,1.0);
- X z2=Mul(y1,base);
- X if (z2 != z1) break;
- X if ((Sum(a,a) == 0.0) || (fabs(y) >= xmin)) break;
- X k++;
- X } while (1);
- X
- X if (setjmp(lab)!=0) { printf("Unexpected over/underflow\n"); exit(1); }
- X
- X minexp=(-k)+1;
- X
- X if ((mx <= k+k-3) && (ibase != 10)) { mx+=mx; iexp+=1; }
- X printf("/\* Number of bits used for exponent = %d *\/\n", iexp);
- X printf("/\* Minimum normalised exponent = %d *\/\n", minexp);
- X printf("/\* Minimum normalised positive number = %g *\/\n", xmin);
- X
- X /* Minimum exponent ************************************************/
- X if (setjmp(lab)==0) /* in case of underflow trap */
- X do {
- X xminner=y;
- X y=Div(y,base);
- X a=Mul(y,1.0);
- X if ((Sum(a,a) == 0.0) || (fabs(y) >= xminner)) break;
- X } while (1);
- X
- X if (setjmp(lab)!=0) { printf("Unexpected over/underflow\n"); exit(1); }
- X
- X if (xminner != 0.0 && xminner != xmin) {
- X printf("/\* The smallest numbers are not kept normalised *\/\n");
- X printf("/\* Smallest unnormalised positive number = %g *\/\n",
- X xminner);
- X } else printf("/\* The smallest numbers are normalised *\/\n");
- X
- X /* Maximum exponent ************************************************/
- X maxexp=2; xmax=1.0; newxmax=base+1.0;
- X if (setjmp(lab) == 0) {
- X while (xmax<newxmax) {
- X xmax=newxmax;
- X newxmax=Mul(newxmax, base);
- X if (Div(newxmax, base) != xmax) break; /* ieee infinity */
- X maxexp++;
- X }
- X }
- X if (setjmp(lab)!=0) { printf("Unexpected over/underflow\n"); exit(1); }
- X
- X printf("/\* Maximum exponent = %d *\/\n", maxexp);
- X
- X /* Largest number ***************************************************/
- X xmax=Diff(1.0, epsneg);
- X if (Mul(xmax,1.0) != xmax) xmax=Diff(1.0, Mul(base,epsneg));
- X for (i=1; i<=maxexp; i++) xmax=Mul(xmax, base);
- X printf("/\* Maximum number = %g *\/\n", xmax);
- X
- X /* Hidden bit + sanity check ****************************************/
- X if (ibase != 10) {
- X mantbits=log(2, (double)ibase)*imant;
- X if (mantbits+iexp+1 == sizeof(Number)*bits+1) {
- X printf("/\* Arithmetic uses a hidden bit *\/\n");
- X } else if (mantbits+iexp+1 == sizeof(Number)*bits) {
- X printf("/\* Arithmetic doesn't use a hidden bit *\/\n");
- X } else {
- X printf("/\* Something fishy here! %s %s %s *\/\n",
- X "Exponent size + mantissa size doesn't match",
- X "with the size of a", THING);
- X }
- X }
- X return imant;
- X}
- X
- X#endif /* ifdef Number */
- X
- X#if PASS == 3
- X#undef PASS
- X#define PASS 4
- X#endif
- X
- X#if PASS == 2
- X#undef PASS
- X#define PASS 3
- X#endif
- X
- X#if PASS == 1
- X#undef PASS
- X#define PASS 2
- X#endif
- X
- X#if PASS < 4
- X#include __FILE__
- X#endif
- EOF
- echo 'Part 01 out of 01 of pack.out complete.'
- exit 0
- --
-
- Steven Pemberton, CWI, Amsterdam; steven@cwi.nl
-
-
-