home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
EFFO
/
forum7.lzh
/
RICO
/
C
/
CONFIG
/
config.c
next >
Wrap
C/C++ Source or Header
|
2009-11-06
|
13KB
|
507 lines
/* 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 os9
#ifndef __FILE__
#define __FILE__ "config.c"
#endif
#endif
#ifndef PASS1
#define PASS1
#include <stdio.h>
#ifdef os9
#ifndef SIGNAL
#define SIGNAL
#endif
#endif
#ifndef SIGNAL
#ifdef unix
#define SIGNAL
#endif /*unix*/
#endif /*SIGNAL*/
#ifdef SIGNAL
#include <signal.h>
#include <setjmp.h>
#ifdef os9
/* OS9 Microware C doesn't understand void */
#define void int
#endif
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 SIGNAL
(void) signal(SIGFPE, overflow);
/*
(void) signal(SIGOVER, overflow);
*/
(void) signal(SIGZERODIV, overflow);
/* Add more calls as necessary */
#endif /* SIGNAL */
if (setjmp(lab)!=0) { printf("Unexpected over/underflow\n"); exit(1); }
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 PASS1 */
/* 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
#ifndef PASS2
#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
#else
#ifndef PASS3
#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
#else
#ifndef PASS4
#define Integer long
#define INT "long"
#define IPROP lprop
#endif /* ifndef PASS4 */
#endif /* ifndef PASS3 */
#endif /* ifndef PASS2 */
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 */
#ifndef PASS2
#define PASS2
#else
#ifndef PASS3
#define PASS3
#else
#ifndef PASS4
#define PASS4
#endif
#endif
#endif
#ifndef PASS4
#ifndef os9
#include __FILE__
#else
/* OS9 Microware C preprocessor got a bit confused */
#include "config.c"
#endif
#endif