|
|
1.1 root 1: /* Everything you wanted to know about your machine and C compiler,
2: but didn't know who to ask. */
3:
4: #ifndef VERSION
5: #define VERSION "4.2"
6: #endif
7:
8: /* Author: Steven Pemberton, CWI, Amsterdam; [email protected]
9: Bugfixes and upgrades gratefully received.
10:
11: Copyright (c) 1988, 1989, 1990 Steven Pemberton, CWI, Amsterdam.
12: All rights reserved.
13:
14: COMPILING
15: With luck and a following wind, just the following will work:
16: cc config.c -o config
17: You may get some messages about unreachable code. This is OK.
18:
19: If your compiler doesn't support: add flag:
20: signed char (eg pcc) -DNO_SC
21: unsigned char -DNO_UC
22: unsigned short and long -DNO_UI
23: void -DNO_VOID
24: signal(), or setjmp/longjmp() -DNO_SIG
25:
26: Try to compile first with no flags, and see if you get any errors -
27: you might be surprised. (Most non-ANSI compilers need -DNO_SC, though.)
28: Some compilers need a -f flag for floating point.
29:
30: If your C preprocessor doesn't have the predefined __FILE__ macro, and
31: you don't want to call this file config.c but, say, params.c, add the
32: flag -D__FILE__=\"params.c\" .
33:
34: Some naughty compilers define __STDC__, but don't really support it
35: (typically they define __STDC__ as 0). If this is the case for you,
36: add flag -DNO_STDC. (To those compiler writers: for shame).
37:
38: Some bad compilers won't accept the line "#include __FILE__" or
39: "#ifdef __FILE__". Add flag -DNO_FILE. In that case, this file *must*
40: be called config.c.
41:
42: Don't use any optimisation flags: the program may not work if you do.
43: Though "while (a+1.0-a-1.0 == 0.0)" may look like "while(1)" to an
44: optimiser, to a floating-point unit there's a world of difference.
45:
46: Some compilers offer various flags for different floating point
47: modes; it's worth trying all possible combinations of these.
48:
49: Add -DID=\"name\" if you want the machine/flags identified in the output.
50:
51: While it is not our policy to support defective compilers, pity has been
52: taken on people with compilers that can't produce object files bigger than
53: 32k (especially since it was an easy addition). Compile the program
54: into separate parts like this:
55: cc -DSEP -DPASS0 -o p0.o <other flags> config.c
56: cc -DSEP -DPASS1 -o p1.o <other flags> config.c
57: cc -DSEP -DPASS2 -o p2.o <other flags> config.c
58: cc -DSEP -DPASS3 -o p3.o <other flags> config.c
59: cc -o config p0.o p1.o p2.o p3.o
60:
61: SYSTEM DEPENDENCIES
62: You may possibly need to add some calls to signal() for other sorts of
63: exception on your machine than SIGFPE, and SIGOVER. See lines beginning
64: #ifdef SIGxxx in main() (and communicate the differences to me!).
65:
66: OUTPUT
67: Run without argument to get the information as English text. If run
68: with argument -l (e.g. config -l), output is a series of #define's for
69: the ANSI standard limits.h include file, excluding MB_MAX_CHAR. If run
70: with argument -f, output is a series of #define's for the ANSI standard
71: float.h include file (according to ANSI C Draft of May 13, 1988).
72: Flag -v gives verbose output: output includes the English text above
73: as C comments. The program exit(0)'s if everything went ok, otherwise
74: it exits with a positive number, telling how many problems there were.
75:
76: VERIFYING THE COMPILER
77: If, having produced the float.h and limits.h header files, you want to
78: verify that the compiler reads them back correctly (there are a lot of
79: boundary cases, of course, like minimum and maximum numbers), you can
80: recompile config.c with -DVERIFY set (plus the other flags that you used
81: when compiling the version that produced the header files). This then
82: recompiles the program so that it #includes "limits.h" and "float.h",
83: and checks that the constants it finds there are the same as the
84: constants it produces. Run the resulting program with config -fl.
85: Very few compilers have passed without error.
86:
87: You can also use this option if your compiler already has both files,
88: and you want to confirm that this program produces the right results.
89:
90: TROUBLESHOOTING.
91: This program is now quite trustworthy, and suspicious and wrong output
92: may well be caused by bugs in the compiler, not in the program (however
93: of course, this is not guaranteed, and no responsibility can be
94: accepted, etc.)
95:
96: The program only works if overflows are ignored by the C system or
97: are catchable with signal().
98:
99: If the program fails to run to completion (often with the error message
100: "Unexpected signal at point x"), this often turns out to be a bug in the
101: C compiler's run-time system. Check what was about to be printed, and
102: try to narrow the problem down.
103:
104: Another possible problem is that you have compiled the program to produce
105: loss-of-precision arithmetic traps. The program cannot cope with these,
106: and you should re-compile without them. (They should never be the default).
107:
108: Make sure you compiled with optimisation turned off.
109:
110: Output preceded by *** WARNING: identifies behaviour of the C system
111: deemed incorrect by the program. Likely problems are that printf or
112: scanf don't cope properly with certain boundary numbers: this program
113: goes to a lot of trouble to calculate its values, and these values
114: are mostly boundary numbers. Experience has shown that often printf
115: cannot cope with these values, and so in an attempt to increase
116: confidence in the output, for each float and double that is printed,
117: the printed value is checked by using sscanf to read it back.
118: Care is taken that numbers are printed with enough digits to uniquely
119: identify them, and therefore that they can be read back identically.
120: If the number read back is different, then there is probably a bug in
121: printf or sscanf, and the program prints the warning message.
122: If the two numbers in the warning look identical, then printf is more
123: than likely rounding the last digit(s) incorrectly. To put you at ease
124: that the two really are different, the bit patterns of the two numbers
125: are also printed. The difference is very likely in the last bit.
126: Many scanf's read the minimum double back as 0.0, and similarly cause
127: overflow when reading the maximum double. The program quite ruthlessly
128: declares all these behaviours faulty. The point is that if you get
129: one of these warnings, the output may be wrong, so you should check
130: the result carefully if you intend to use the results. Of course, printf
131: and sscanf may both be wrong, and cancel each other out, so you should
132: check the output carefully anyway.
133:
134: The warning that "a cast didn't work" refers to cases like this:
135:
136: float f;
137: #define C 1.234567890123456789
138: f= C;
139: if (f != (float) C) printf ("Wrong!");
140:
141: A faulty compiler will widen f to double and ignore the cast to float,
142: and because there is more accuracy in a double than a float, fail to
143: recognise that they are the same. In the actual case in point, f and C
144: are passed as parameters to a function that discovers they are not equal,
145: so it's just possible that the error was in the parameter passing,
146: not in the cast (see function Validate()).
147: For ANSI C, which has float constants, the error message is "constant has
148: wrong precision".
149:
150: REPORTING PROBLEMS
151: If the program doesn't work for you for any reason that can't be
152: narrowed down to a problem in the C compiler, or it has to be changed in
153: order to get it to compile, or it produces suspicious output (like a very
154: low maximum float, for instance), please mail the problem and an example
155: of the incorrect output to [email protected] or ..!hp4nl!cwi.nl!steven, so that
156: improvements can be worked into future versions; cwi.nl is the European
157: backbone, and is connected to uunet and other fine hosts.
158:
159: The program tries to catch and diagnose bugs in the compiler/run-time
160: system. I would be especially pleased to have reports of failures so
161: that I can improve this service.
162:
163: I apologise unreservedly for the contorted use of the preprocessor...
164:
165: THE SMALL PRINT
166: You may copy and distribute verbatim copies of this source file.
167:
168: You may modify this source file, and copy and distribute such
169: modified versions, provided that you leave the copyright notice
170: at the top of the file and also cause the modified file to carry
171: prominent notices stating that you changed the files and the date
172: of any change; and cause the whole of any work that you distribute
173: or publish, that in whole or in part contains or is a derivative of
174: this program or any part thereof, to be licensed at no charge to
175: all third parties on terms identical to those here.
176:
177: If you do have a fix to any problem, please send it to me, so that
178: other people can have the benefits.
179:
180: While every effort has been taken to make this program as reliable as
181: possible, no responsibility can be taken for the correctness of the
182: output, or suitability for any particular use.
183:
184: ACKNOWLEDGEMENTS
185: Many people have given time and ideas to making this program what it is.
186: To all of them thanks, and apologies for not mentioning them by name.
187:
188: HISTORY
189: 4.0 Added -f and -l options, and warnings
190: 4.1 Added VERIFY
191: 4.2 Added SEP
192: Fixed eps/epsneg
193: Added check for pseudo-unsigned chars
194: Added description for each #define output
195: Added check for absence of defines during verify
196: Added prototypes
197: Added NO_STDC and NO_FILE
198: Fixed alignments output
199: */
200:
201: #ifndef NO_FILE
202: #ifndef __FILE__
203: #define __FILE__ "config.c"
204: #endif
205: #endif
206:
207: /* If PASS isn't defined, then this is the first pass over this file. */
208: #ifndef PASS
209: #ifndef SEP
210: #define PASS 1
211: #define PASS0 1
212: #define PASS1 1
213: #endif /* SEP */
214:
215: /* A description of the ANSI constants */
216: #define D_CHAR_BIT "Number of bits in a storage unit"
217: #define D_CHAR_MAX "Maximum char"
218: #define D_CHAR_MIN "Minimum char"
219: #define D_SCHAR_MAX "Maximum signed char"
220: #define D_SCHAR_MIN "Minimum signed char"
221: #define D_UCHAR_MAX "Maximum unsigned char (minimum is always 0)"
222:
223: #define D_INT_MAX "Maximum %s"
224: #define D_INT_MIN "Minimum %s"
225: #define D_UINT_MAX "Maximum unsigned %s (minimum is always 0)"
226:
227: #define D_FLT_ROUNDS "Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown"
228: #define D_FLT_RADIX "Radix of exponent representation"
229: #define D_MANT_DIG "Number of base-FLT_RADIX digits in the mantissa of a %s"
230: #define D_DIG "Number of decimal digits of precision in a %s"
231: #define D_MIN_EXP "Minimum int x such that FLT_RADIX**(x-1) is a normalised %s"
232: #define D_MIN_10_EXP "Minimum int x such that 10**x is a normalised %s"
233: #define D_MAX_EXP "Maximum int x such that FLT_RADIX**(x-1) is a representable %s"
234: #define D_MAX_10_EXP "Maximum int x such that 10**x is a representable %s"
235: #define D_MAX "Maximum %s"
236: #define D_EPSILON "Minimum %s x such that 1.0+x != 1.0"
237: #define D_MIN "Minimum normalised %s"
238:
239: /* Procedure just marks the functions that don't return a result */
240: #ifdef NO_VOID
241: #define Procedure int
242: #else
243: #define Procedure void
244: #endif
245:
246: /* Some bad compilers define __STDC__, when they don't support it.
247: Compile with -DNO_STDC to get round this.
248: */
249: #ifndef NO_STDC
250: #ifdef __STDC__
251: #define STDC
252: #endif
253: #endif
254:
255: /* Stuff different for ANSI C, and old C:
256: ARGS and NOARGS are used for function prototypes.
257: Volatile is used to reduce the chance of optimisation,
258: and to prevent variables being put in registers (when setjmp/longjmp
259: wouldn't work as we want)
260: Long_double is the longest floating point type available.
261: stdc is used in tests like "if (stdc)", which is less ugly than #ifdef.
262: U is output after unsigned constants.
263: */
264: #ifdef STDC
265:
266: #define ARGS(x) x
267: #define NOARGS (void)
268: #define Volatile volatile
269: #define Long_double long double
270: #define stdc 1
271: #define U "U"
272:
273: #else /* Old style C */
274:
275: #define ARGS(x) ()
276: #define NOARGS ()
277: #define Volatile static
278: #define Long_double double
279: #define stdc 0
280: #define U ""
281:
282: #endif /* STDC */
283:
284: /* include files */
285: #include <stdio.h>
286:
287: #ifdef NO_SIG
288: #define jmp_buf int
289: #else
290: #include <signal.h>
291: #include <setjmp.h>
292: #endif
293:
294: #ifdef VERIFY
295: #include "limits.h"
296: #include "float.h"
297: #endif
298:
299: #define Vprintf if (V) printf
300: #define Unexpected(place) if (setjmp(lab)!=0) croak(place)
301: #define fabs(x) (((x)<0.0)?(-x):(x))
302:
303: #endif /* PASS */
304:
305: #ifdef PASS0
306:
307: /* Prototypes for what's to come: */
308:
309: char *malloc ARGS((unsigned size));
310: Procedure exit ARGS((int status));
311:
312: char *f_rep ARGS((int precision, Long_double val));
313:
314: int cprop NOARGS;
315: int basic NOARGS;
316: Procedure sprop NOARGS;
317: Procedure iprop NOARGS;
318: Procedure lprop NOARGS;
319: Procedure usprop NOARGS;
320: Procedure uiprop NOARGS;
321: Procedure ulprop NOARGS;
322: int fprop ARGS((int bits_per_byte));
323: int dprop ARGS((int bits_per_byte));
324: int ldprop ARGS((int bits_per_byte));
325: Procedure efprop ARGS((int fprec, int dprec, int lprec));
326: Procedure edprop ARGS((int fprec, int dprec, int lprec));
327: Procedure eldprop ARGS((int fprec, int dprec, int lprec));
328:
329: int setmode ARGS((char *s));
330: Procedure farewell ARGS((int bugs));
331: Procedure describe ARGS((char *description, char *extra));
332: Procedure check_defines NOARGS;
333: Procedure bitpattern ARGS((char *p, unsigned int size));
334: int ceil_log ARGS((int base, Long_double x));
335: Procedure croak ARGS((int place));
336: Procedure eek_a_bug ARGS((char *problem));
337: Procedure endian ARGS((int bits_per_byte));
338: int exponent ARGS((Long_double x, double *fract, int *exp));
339: int floor_log ARGS((int base, Long_double x));
340: Procedure f_define ARGS((char *desc, char *extra, char *sort, char *name,
341: int prec, Long_double val, char *mark));
342: Procedure i_define ARGS((char *desc, char *extra, char *sort, char *name,
343: long val, long req, char *mark));
344: Procedure u_define ARGS((char *desc, char *extra, char *sort, char *name,
345: unsigned long val, unsigned long req, char *mark));
346:
347: #ifdef NO_SIG /* There's no signal(), or setjmp/longjmp() */
348:
349: /* Dummy routines instead */
350:
351: Procedure setjmp ARGS((int lab));
352:
353: int lab=1;
354: int setjmp(lab) int lab; { return(0); }
355: Procedure signal(i, p) int i, (*p)(); {}
356:
357: #else
358: jmp_buf lab;
359: Procedure overflow(sig) int sig; { /* what to do on over/underflow */
360: signal(sig, overflow);
361: longjmp(lab, 1);
362: }
363:
364: #endif /*NO_SIG*/
365:
366: int V= 0, /* verbose */
367: L= 0, /* produce limits.h */
368: F= 0, /* produce float.h */
369: bugs=0; /* The number of (possible) bugs in the output */
370:
371: char co[4], oc[4]; /* Comment starter and ender symbols */
372:
373: int bits_per_byte; /* the number of bits per unit returned by sizeof() */
374: int flt_rounds; /* The calculated value of FLT_ROUNDS */
375: int flt_radix; /* The calculated value of FLT_RADIX */
376:
377: #ifdef TEST
378: /* Set the fp modes on a SUN with 68881 chip, to check that different
379: rounding modes etc. get properly detected.
380: Compile with additional flag -DTEST, and run with additional parameter
381: +hex-number, to set the 68881 mode register to hex-number
382: */
383:
384: /* Bits 0x30 = rounding mode: */
385: #define ROUND_BITS 0x30
386: #define TO_NEAREST 0x00
387: #define TO_ZERO 0x10
388: #define TO_MINUS_INF 0x20
389: #define TO_PLUS_INF 0x30 /* The SUN FP user's guide seems to be wrong here */
390:
391: /* Bits 0xc0 = extended rounding: */
392: #define EXT_BITS 0xc0
393: #define ROUND_EXTENDED 0x00
394: #define ROUND_SINGLE 0x40
395: #define ROUND_DOUBLE 0x80
396:
397: /* Enabled traps: */
398: #define EXE_INEX1 0x100
399: #define EXE_INEX2 0x200
400: #define EXE_DZ 0x400
401: #define EXE_UNFL 0x800
402: #define EXE_OVFL 0x1000
403: #define EXE_OPERR 0x2000
404: #define EXE_SNAN 0x4000
405: #define EXE_BSUN 0x8000
406:
407: /* Only used for testing, on a Sun with 68881 chip */
408: /* Print the FP mode */
409: printmode(new) unsigned new; {
410: fpmode_(&new);
411: printf("New fp mode:\n");
412: printf(" Round toward ");
413: switch (new & ROUND_BITS) {
414: case TO_NEAREST: printf("nearest"); break;
415: case TO_ZERO: printf("zero"); break;
416: case TO_MINUS_INF: printf("minus infinity"); break;
417: case TO_PLUS_INF: printf("plus infinity"); break;
418: default: printf("???"); break;
419: }
420:
421: printf("\n Extended rounding precision: ");
422:
423: switch (new & EXT_BITS) {
424: case ROUND_EXTENDED: printf("extended"); break;
425: case ROUND_SINGLE: printf("single"); break;
426: case ROUND_DOUBLE: printf("double"); break;
427: default: printf("???"); break;
428: }
429:
430: printf("\n Enabled exceptions:");
431: if (new & (unsigned) EXE_INEX1) printf(" inex1");
432: if (new & (unsigned) EXE_INEX2) printf(" inex2");
433: if (new & (unsigned) EXE_DZ) printf(" dz");
434: if (new & (unsigned) EXE_UNFL) printf(" unfl");
435: if (new & (unsigned) EXE_OVFL) printf(" ovfl");
436: if (new & (unsigned) EXE_OPERR) printf(" operr");
437: if (new & (unsigned) EXE_SNAN) printf(" snan");
438: if (new & (unsigned) EXE_BSUN) printf(" bsun");
439: printf("\n");
440: }
441:
442: /* Only used for testing, on a Sun with 68881 chip */
443: /* Set the FP mode */
444: int setmode(s) char *s; {
445: unsigned mode=0, dig;
446: char c;
447:
448: while (*s) {
449: c= *s++;
450: if (c>='0' && c<='9') dig= c-'0';
451: else if (c>='a' && c<='f') dig= c-'a'+10;
452: else if (c>='A' && c<='F') dig= c-'A'+10;
453: else return 1;
454: mode= mode<<4 | dig;
455: }
456: printmode(mode);
457: return 0;
458: }
459: #else
460: int setmode(s) char *s; {
461: fprintf(stderr, "Can't set mode: not compiled with TEST\n");
462: return(1);
463: }
464: #endif
465:
466: Procedure farewell(bugs) int bugs; {
467: if (bugs > 0) {
468: printf("\n%sFor hints on dealing with the problems above", co);
469: printf("\n see the section 'TROUBLESHOOTING' in the file ");
470: printf("%s%s\n", __FILE__, oc);
471: }
472: exit(bugs);
473: }
474:
475: /* The program has received a signal where it wasn't expecting one */
476: Procedure croak(place) int place; {
477: printf("*** Unexpected signal at point %d\n", place);
478: farewell(bugs+1); /* An exit isn't essential here, but avoids loops */
479: }
480:
481: main(argc, argv) int argc; char *argv[]; {
482: int dprec, fprec, lprec;
483: unsigned int size;
484: long total;
485: int i; char *s; int bad;
486:
487: #ifdef SIGFPE
488: signal(SIGFPE, overflow);
489: #endif
490: #ifdef SIGOVER
491: signal(SIGOVER, overflow);
492: #endif
493: /* Add more calls as necessary */
494:
495: Unexpected(1);
496:
497: bad=0;
498: for (i=1; i < argc; i++) {
499: s= argv[i];
500: if (*s == '-') {
501: s++;
502: while (*s) {
503: switch (*(s++)) {
504: case 'v': V=1; break;
505: case 'l': L=1; break;
506: case 'f': F=1; break;
507: default: bad=1; break;
508: }
509: }
510: } else if (*s == '+') {
511: s++;
512: bad= setmode(s);
513: } else bad= 1;
514: }
515: if (bad) {
516: fprintf(stderr,
517: "Usage: %s [-vlf]\n v=Verbose l=Limits.h f=Float.h\n",
518: argv[0]);
519: exit(1);
520: }
521: if (L || F) {
522: co[0]= '/'; oc[0]= ' ';
523: co[1]= '*'; oc[1]= '*';
524: co[2]= ' '; oc[2]= '/';
525: co[3]= '\0'; oc[3]= '\0';
526: } else {
527: co[0]= '\0'; oc[0]= '\0';
528: V=1;
529: }
530:
531: if (L) printf("%slimits.h%s\n", co, oc);
532: if (F) printf("%sfloat.h%s\n", co, oc);
533: #ifdef ID
534: printf("%sProduced on %s by config version %s, CWI, Amsterdam%s\n",
535: co, ID, VERSION, oc);
536: #else
537: printf("%sProduced by config version %s, CWI, Amsterdam%s\n",
538: co, VERSION, oc);
539: #endif
540:
541: #ifdef VERIFY
542: printf("%sVerification phase%s\n", co, oc);
543: #endif
544:
545: #ifdef NO_SIG
546: Vprintf("%sCompiled without signal(): %s%s\n",
547: co,
548: "there's nothing that can be done if overflow occurs",
549: oc);
550: #endif
551: #ifdef NO_SC
552: Vprintf("%sCompiled without signed char%s\n", co, oc);
553: #endif
554: #ifdef NO_UC
555: Vprintf("%Compiled without unsigned char%s\n", co, oc);
556: #endif
557: #ifdef NO_UI
558: Vprintf("%Compiled without unsigned short or long%s\n", co, oc);
559: #endif
560: #ifdef __STDC__
561: Vprintf("%sCompiler claims to be ANSI C level %d%s\n",
562: co, __STDC__, oc);
563: #else
564: Vprintf("%sCompiler does not claim to be ANSI C%s\n", co, oc);
565: #endif
566: printf("\n");
567: check_defines();
568:
569: bits_per_byte= basic();
570: Vprintf("\n");
571: if (F||V) {
572: fprec= fprop(bits_per_byte);
573: dprec= dprop(bits_per_byte);
574: lprec= ldprop(bits_per_byte);
575: efprop(fprec, dprec, lprec);
576: edprop(fprec, dprec, lprec);
577: eldprop(fprec, dprec, lprec);
578: }
579: if (V) {
580: /* An extra goody: the approximate amount of data-space */
581: /* Allocate store until no more available */
582: size=1<<((bits_per_byte*sizeof(int))-2);
583: total=0;
584: while (size!=0) {
585: while (malloc(size)!=(char *)NULL) total+=(size/2);
586: size/=2;
587: }
588:
589: Vprintf("%sMemory mallocatable ~= %ld Kbytes%s\n",
590: co, (total+511)/512, oc);
591: }
592: farewell(bugs);
593: return bugs; /* To keep compilers and lint happy */
594: }
595:
596: Procedure eek_a_bug(problem) char *problem; {
597: /* The program has discovered a problem */
598: printf("\n%s*** WARNING: %s%s\n", co, problem, oc);
599: bugs++;
600: }
601:
602: Procedure describe(description, extra) char *description, *extra; {
603: /* Produce the description for a #define */
604: printf(" %s", co);
605: printf(description, extra);
606: printf("%s\n", oc);
607: }
608:
609: Procedure i_define(desc, extra, sort, name, val, req, mark)
610: char *desc, *extra, *sort, *name; long val, req; char *mark; {
611: /* Produce a #define for a signed int type */
612: describe(desc, extra);
613: if (val >= 0) {
614: printf("#define %s%s %ld%s\n", sort, name, val, mark);
615: } else {
616: printf("#define %s%s (%ld%s)\n", sort, name, val, mark);
617: }
618: if (val != req) {
619: printf("%s*** Verify failed for above #define!\n", co);
620: printf(" Compiler has %ld for value%s\n\n", req, oc);
621: bugs++;
622: }
623: Vprintf("\n");
624: }
625:
626: Procedure u_define(desc, extra, sort, name, val, req, mark)
627: char *desc, *extra, *sort, *name; unsigned long val, req; char *mark; {
628: /* Produce a #define for an unsigned value */
629: describe(desc, extra);
630: printf("#define %s%s %lu%s%s\n", sort, name, val, U, mark);
631: if (val != req) {
632: printf("%s*** Verify failed for above #define!\n", co);
633: printf(" Compiler has %lu for value%s\n\n", req, oc);
634: bugs++;
635: }
636: Vprintf("\n");
637: }
638:
639: Procedure f_define(desc, extra, sort, name, precision, val, mark)
640: char *desc, *extra, *sort, *name; int precision;
641: Long_double val; char *mark; {
642: /* Produce a #define for a float/double/long double */
643: describe(desc, extra);
644: if (stdc) {
645: printf("#define %s%s %s%s\n",
646: sort, name, f_rep(precision, val), mark);
647: } else if (*mark == 'F') {
648: /* non-ANSI C has no float constants, so cast the constant */
649: printf("#define %s%s ((float)%s)\n",
650: sort, name, f_rep(precision, val));
651: } else {
652: printf("#define %s%s %s\n", sort, name, f_rep(precision, val));
653: }
654: Vprintf("\n");
655: }
656:
657: int floor_log(base, x) int base; Long_double x; {
658: /* return floor(log base(x)) */
659: int r=0;
660: while (x>=base) { r++; x/=base; }
661: return r;
662: }
663:
664: int ceil_log(base, x) int base; Long_double x; {
665: int r=0;
666: while (x>1.0) { r++; x/=base; }
667: return r;
668: }
669:
670: int exponent(x, fract, exp) Long_double x; double *fract; int *exp; {
671: /* Split x into a fraction and a power of ten;
672: returns 0 if x is unusable, 1 otherwise.
673: Only used for error messages about faulty output.
674: */
675: int r=0, neg=0;
676: Long_double old;
677: *fract=0.0; *exp=0;
678: if (x<0.0) {
679: x= -x;
680: neg= 1;
681: }
682: if (x==0.0) return 1;
683: if (x>=10.0) {
684: while (x>=10.0) {
685: old=x; r++; x/=10.0;
686: if (old==x) return 0;
687: }
688: } else {
689: while (x<1.0) {
690: old=x; r--; x*=10.0;
691: if (old==x) return 0;
692: }
693: }
694: if (neg) *fract= -x;
695: else *fract=x;
696: *exp=r;
697: return 1;
698: }
699:
700: char *f_rep(precision, val) int precision; Long_double val; {
701: /* Return the floating representation of val */
702: static char buf[1024];
703: char *f1;
704: if (sizeof(double) == sizeof(Long_double)) {
705: /* Assume they're the same, and use non-stdc format */
706: /* This is for stdc compilers using non-stdc libraries */
707: f1= "%.*e";
708: } else {
709: /* It had better support Le then */
710: f1= "%.*Le";
711: }
712: sprintf(buf, f1, precision, val);
713: return buf;
714: }
715:
716: Procedure bitpattern(p, size) char *p; unsigned int size; {
717: /* Printf the bit-pattern of p */
718: char c;
719: int i, j;
720:
721: for (i=1; i<=size; i++) {
722: c= *p;
723: p++;
724: for (j=bits_per_byte-1; j>=0; j--)
725: printf("%c", (c>>j)&1 ? '1' : '0');
726: if (i!=size) printf(" ");
727: }
728: }
729:
730: #define Order(x, px, mode)\
731: printf("%s %s ", co, mode); for (i=0; i<sizeof(x); i++) px[i]= c[i]; \
732: for (i=1; i<=sizeof(x); i++) { putchar((char)((x>>(bits_per_byte*(sizeof(x)-i)))&mask)); }\
733: printf("%s\n", oc);
734:
735: Procedure endian(bits_per_byte) int bits_per_byte; {
736: /* Printf the byte-order used on this machine */
737: /*unsigned*/ short s=0;
738: /*unsigned*/ int j=0;
739: /*unsigned*/ long l=0;
740:
741: char *ps= (char *) &s,
742: *pj= (char *) &j,
743: *pl= (char *) &l,
744: *c= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
745: unsigned int mask, i;
746:
747: mask=0;
748: for (i=1; i<=(unsigned)bits_per_byte; i++) mask= (mask<<1)|1;
749:
750: if (V) {
751: printf("%sCharacter order:%s\n", co, oc);
752: Order(s, ps, "short:");
753: Order(j, pj, "int: ");
754: Order(l, pl, "long: ");
755: }
756: }
757:
758: Procedure check_defines() {
759: /* ensure that all the #defines are present */
760: #ifdef VERIFY
761: if (L) {
762: #ifndef CHAR_BIT
763: printf("%s*** CHAR_BIT missing from limits.h%s\n", co, oc); bugs++;
764: #endif
765: #ifndef CHAR_MAX
766: printf("%s*** CHAR_MAX missing from limits.h%s\n", co, oc); bugs++;
767: #endif
768: #ifndef CHAR_MIN
769: printf("%s*** CHAR_MIN missing from limits.h%s\n", co, oc); bugs++;
770: #endif
771: #ifndef SCHAR_MAX
772: printf("%s*** SCHAR_MAX missing from limits.h%s\n", co, oc); bugs++;
773: #endif
774: #ifndef SCHAR_MIN
775: printf("%s*** SCHAR_MIN missing from limits.h%s\n", co, oc); bugs++;
776: #endif
777: #ifndef UCHAR_MAX
778: printf("%s*** UCHAR_MAX missing from limits.h%s\n", co, oc); bugs++;
779: #endif
780: #ifndef SHRT_MAX
781: printf("%s*** SHRT_MAX missing from limits.h%s\n", co, oc); bugs++;
782: #endif
783: #ifndef SHRT_MIN
784: printf("%s*** SHRT_MIN missing from limits.h%s\n", co, oc); bugs++;
785: #endif
786: #ifndef INT_MAX
787: printf("%s*** INT_MAX missing from limits.h%s\n", co, oc); bugs++;
788: #endif
789: #ifndef INT_MIN
790: printf("%s*** INT_MIN missing from limits.h%s\n", co, oc); bugs++;
791: #endif
792: #ifndef LONG_MAX
793: printf("%s*** LONG_MAX missing from limits.h%s\n", co, oc); bugs++;
794: #endif
795: #ifndef LONG_MIN
796: printf("%s*** LONG_MIN missing from limits.h%s\n", co, oc); bugs++;
797: #endif
798: #ifndef USHRT_MAX
799: printf("%s*** USHRT_MAX missing from limits.h%s\n", co, oc); bugs++;
800: #endif
801: #ifndef UINT_MAX
802: printf("%s*** UINT_MAX missing from limits.h%s\n", co, oc); bugs++;
803: #endif
804: #ifndef ULONG_MAX
805: printf("%s*** ULONG_MAX missing from limits.h%s\n", co, oc); bugs++;
806: #endif
807: } /* if (L) */
808:
809: if (F) {
810: #ifndef FLT_RADIX
811: printf("%s*** FLT_RADIX missing from float.h%s\n", co, oc); bugs++;
812: #endif
813: #ifndef FLT_MANT_DIG
814: printf("%s*** FLT_MANT_DIG missing from float.h%s\n", co, oc); bugs++;
815: #endif
816: #ifndef FLT_DIG
817: printf("%s*** FLT_DIG missing from float.h%s\n", co, oc); bugs++;
818: #endif
819: #ifndef FLT_ROUNDS
820: printf("%s*** FLT_ROUNDS missing from float.h%s\n", co, oc); bugs++;
821: #endif
822: #ifndef FLT_EPSILON
823: printf("%s*** FLT_EPSILON missing from float.h%s\n", co, oc); bugs++;
824: #endif
825: #ifndef FLT_MIN_EXP
826: printf("%s*** FLT_MIN_EXP missing from float.h%s\n", co, oc); bugs++;
827: #endif
828: #ifndef FLT_MIN
829: printf("%s*** FLT_MIN missing from float.h%s\n", co, oc); bugs++;
830: #endif
831: #ifndef FLT_MIN_10_EXP
832: printf("%s*** FLT_MIN_10_EXP missing from float.h%s\n", co, oc); bugs++;
833: #endif
834: #ifndef FLT_MAX_EXP
835: printf("%s*** FLT_MAX_EXP missing from float.h%s\n", co, oc); bugs++;
836: #endif
837: #ifndef FLT_MAX
838: printf("%s*** FLT_MAX missing from float.h%s\n", co, oc); bugs++;
839: #endif
840: #ifndef FLT_MAX_10_EXP
841: printf("%s*** FLT_MAX_10_EXP missing from float.h%s\n", co, oc); bugs++;
842: #endif
843: #ifndef DBL_MANT_DIG
844: printf("%s*** DBL_MANT_DIG missing from float.h%s\n", co, oc); bugs++;
845: #endif
846: #ifndef DBL_DIG
847: printf("%s*** DBL_DIG missing from float.h%s\n", co, oc); bugs++;
848: #endif
849: #ifndef DBL_EPSILON
850: printf("%s*** DBL_EPSILON missing from float.h%s\n", co, oc); bugs++;
851: #endif
852: #ifndef DBL_MIN_EXP
853: printf("%s*** DBL_MIN_EXP missing from float.h%s\n", co, oc); bugs++;
854: #endif
855: #ifndef DBL_MIN
856: printf("%s*** DBL_MIN missing from float.h%s\n", co, oc); bugs++;
857: #endif
858: #ifndef DBL_MIN_10_EXP
859: printf("%s*** DBL_MIN_10_EXP missing from float.h%s\n", co, oc); bugs++;
860: #endif
861: #ifndef DBL_MAX_EXP
862: printf("%s*** DBL_MAX_EXP missing from float.h%s\n", co, oc); bugs++;
863: #endif
864: #ifndef DBL_MAX
865: printf("%s*** DBL_MAX missing from float.h%s\n", co, oc); bugs++;
866: #endif
867: #ifndef DBL_MAX_10_EXP
868: printf("%s*** DBL_MAX_10_EXP missing from float.h%s\n", co, oc); bugs++;
869: #endif
870: #ifdef STDC
871: #ifndef LDBL_MANT_DIG
872: printf("%s*** LDBL_MANT_DIG missing from float.h%s\n", co, oc); bugs++;
873: #endif
874: #ifndef LDBL_DIG
875: printf("%s*** LDBL_DIG missing from float.h%s\n", co, oc); bugs++;
876: #endif
877: #ifndef LDBL_EPSILON
878: printf("%s*** LDBL_EPSILON missing from float.h%s\n", co, oc); bugs++;
879: #endif
880: #ifndef LDBL_MIN_EXP
881: printf("%s*** LDBL_MIN_EXP missing from float.h%s\n", co, oc); bugs++;
882: #endif
883: #ifndef LDBL_MIN
884: printf("%s*** LDBL_MIN missing from float.h%s\n", co, oc); bugs++;
885: #endif
886: #ifndef LDBL_MIN_10_EXP
887: printf("%s*** LDBL_MIN_10_EXP missing from float.h%s\n", co, oc); bugs++;
888: #endif
889: #ifndef LDBL_MAX_EXP
890: printf("%s*** LDBL_MAX_EXP missing from float.h%s\n", co, oc); bugs++;
891: #endif
892: #ifndef LDBL_MAX
893: printf("%s*** LDBL_MAX missing from float.h%s\n", co, oc); bugs++;
894: #endif
895: #ifndef LDBL_MAX_10_EXP
896: printf("%s*** LDBL_MAX_10_EXP missing from float.h%s\n", co, oc); bugs++;
897: #endif
898: #endif /* STDC */
899: } /* if (F) */
900: #endif /* VERIFY */
901: }
902:
903: #ifdef VERIFY
904: #ifndef SCHAR_MAX
905: #define SCHAR_MAX char_max
906: #endif
907: #ifndef SCHAR_MIN
908: #define SCHAR_MIN char_min
909: #endif
910: #ifndef UCHAR_MAX
911: #define UCHAR_MAX char_max
912: #endif
913: #endif /* VERIFY */
914:
915: #ifndef CHAR_BIT
916: #define CHAR_BIT char_bit
917: #endif
918: #ifndef CHAR_MAX
919: #define CHAR_MAX char_max
920: #endif
921: #ifndef CHAR_MIN
922: #define CHAR_MIN char_min
923: #endif
924: #ifndef SCHAR_MAX
925: #define SCHAR_MAX char_max
926: #endif
927: #ifndef SCHAR_MIN
928: #define SCHAR_MIN char_min
929: #endif
930: #ifndef UCHAR_MAX
931: #define UCHAR_MAX char_max
932: #endif
933:
934: int cprop() {
935: /* Properties of type char */
936: Volatile char c, char_max, char_min;
937: Volatile int bits_per_byte, is_signed;
938: long char_bit;
939:
940: Unexpected(2);
941:
942: /* Calculate number of bits per character *************************/
943: c=1; bits_per_byte=0;
944: do { c=c<<1; bits_per_byte++; } while(c!=0);
945: c= (char)(-1);
946: if (((int)c)<0) is_signed=1;
947: else is_signed=0;
948: Vprintf("%sChar = %d bits, %ssigned%s\n",
949: co, (int)sizeof(c)*bits_per_byte, (is_signed?"":"un"), oc);
950: char_bit=(long)(sizeof(c)*bits_per_byte);
951: if (L) i_define(D_CHAR_BIT, "",
952: "CHAR", "_BIT", char_bit, (long) CHAR_BIT, "");
953:
954: c=0; char_max=0;
955: c++;
956: if (setjmp(lab)==0) { /* Yields char_max */
957: while (c>char_max) {
958: char_max=c;
959: c++;
960: }
961: } else {
962: Vprintf("%sCharacter overflow generates a trap!%s\n", co, oc);
963: }
964: c=0; char_min=0;
965: c--;
966: if (setjmp(lab)==0) { /* Yields char_min */
967: while (c<char_min) {
968: char_min=c;
969: c--;
970: }
971: }
972: if (is_signed && char_min == 0) {
973: Vprintf("%sBEWARE! Chars are pseudo-unsigned:%s\n", co, oc);
974: Vprintf("%s %s%s%s\n",
975: "They contain only nonnegative values, ",
976: "but sign extend when used as integers.", co, oc);
977: }
978: Unexpected(3);
979:
980: if (L) {
981: i_define(D_CHAR_MAX, "",
982: "CHAR", "_MAX", (long) char_max, (long) CHAR_MAX, "");
983: i_define(D_CHAR_MIN, "",
984: "CHAR", "_MIN", (long) char_min, (long) CHAR_MIN, "");
985: if (is_signed) {
986: i_define(D_SCHAR_MAX, "",
987: "SCHAR", "_MAX", (long) char_max,
988: (long) SCHAR_MAX, "");
989: i_define(D_SCHAR_MIN, "",
990: "SCHAR", "_MIN", (long) char_min,
991: (long) SCHAR_MIN, "");
992: } else {
993: i_define(D_UCHAR_MAX, "",
994: "UCHAR", "_MAX", (long) char_max,
995: (long) UCHAR_MAX, "");
996: }
997:
998: if (is_signed) {
999: #ifndef NO_UC
1000: Volatile unsigned char c, char_max;
1001: c=0; char_max=0;
1002: c++;
1003: if (setjmp(lab)==0) { /* Yields char_max */
1004: while (c>char_max) {
1005: char_max=c;
1006: c++;
1007: }
1008: }
1009: Unexpected(4);
1010: i_define(D_UCHAR_MAX, "",
1011: "UCHAR", "_MAX", (long) char_max,
1012: (long) UCHAR_MAX, "");
1013: #endif
1014: } else {
1015: #ifndef NO_SC /* Define NO_SC if the next line gives a syntax error */
1016: Volatile signed char c, char_max, char_min;
1017: c=0; char_max=0;
1018: c++;
1019: if (setjmp(lab)==0) { /* Yields char_max */
1020: while (c>char_max) {
1021: char_max=c;
1022: c++;
1023: }
1024: }
1025: c=0; char_min=0;
1026: c--;
1027: if (setjmp(lab)==0) { /* Yields char_min */
1028: while (c<char_min) {
1029: char_min=c;
1030: c--;
1031: }
1032: }
1033: Unexpected(5);
1034: i_define(D_SCHAR_MIN, "",
1035: "SCHAR", "_MIN", (long) char_min,
1036: (long) SCHAR_MIN, "");
1037: i_define(D_SCHAR_MAX, "",
1038: "SCHAR", "_MAX", (long) char_max,
1039: (long) SCHAR_MAX, "");
1040: #endif /* NO_SC */
1041: }
1042: }
1043: return bits_per_byte;
1044: }
1045:
1046: int basic() {
1047: /* The properties of the basic types.
1048: Returns number of bits per sizeof unit */
1049: Volatile int bits_per_byte;
1050: struct{char i1; char c1;} schar;
1051: struct{short i2; char c2;} sshort;
1052: struct{int i3; char c3;} sint;
1053: struct{long i4; char c4;} slong;
1054:
1055: bits_per_byte= cprop();
1056:
1057: /* Shorts, ints and longs *****************************************/
1058: Vprintf("%sShort=%d int=%d long=%d float=%d double=%d bits %s\n",
1059: co,
1060: (int) sizeof(short)*bits_per_byte,
1061: (int) sizeof(int)*bits_per_byte,
1062: (int) sizeof(long)*bits_per_byte,
1063: (int) sizeof(float)*bits_per_byte,
1064: (int) sizeof(double)*bits_per_byte, oc);
1065: if (stdc) {
1066: Vprintf("%sLong double=%d bits%s\n",
1067: co, (int) sizeof(Long_double)*bits_per_byte, oc);
1068: }
1069: Vprintf("%sChar pointers = %d bits%s%s\n",
1070: co, (int)sizeof(char *)*bits_per_byte,
1071: sizeof(char *)>sizeof(int)?" BEWARE! larger than int!":"",
1072: oc);
1073: Vprintf("%sInt pointers = %d bits%s%s\n",
1074: co, (int)sizeof(int *)*bits_per_byte,
1075: sizeof(int *)>sizeof(int)?" BEWARE! larger than int!":"",
1076: oc);
1077:
1078: /* Alignment constants ********************************************/
1079: Vprintf("%sAlignments used for char=%ld short=%ld int=%ld long=%ld%s\n",
1080: co,
1081: ((long)&schar.c1)-((long)&schar.i1),
1082: ((long)&sshort.c2)-((long)&sshort.i2),
1083: ((long)&sint.c3)-((long)&sint.i3),
1084: ((long)&slong.c4)-((long)&slong.i4),
1085: oc);
1086:
1087: /* Ten little endians *********************************************/
1088:
1089: endian(bits_per_byte);
1090:
1091: /* Pointers *******************************************************/
1092: if (V) {
1093: if ("abcd"=="abcd")
1094: printf("%sStrings are shared%s\n", co, oc);
1095: else printf("%sStrings are not shared%s\n", co, oc);
1096: }
1097:
1098: sprop();
1099: iprop();
1100: lprop();
1101: usprop();
1102: uiprop();
1103: ulprop();
1104:
1105: Unexpected(6);
1106:
1107: return bits_per_byte;
1108: }
1109:
1110: #else /* not PASS0 */
1111:
1112: #ifdef SEP
1113: extern jmp_buf lab;
1114: extern int V, L, F, bugs, bits_per_byte;
1115: extern char co[], oc[];
1116: extern char *f_rep();
1117: #endif /* SEP */
1118: #endif /* ifdef PASS0 */
1119:
1120: /* As I said, I apologise for the contortions below. The functions are
1121: expanded by the preprocessor twice or three times (for float and double,
1122: and maybe for long double, and for short, int and long). That way,
1123: I never make a change to one that I forget to make to the other.
1124: You can look on it as C's fault for not supporting multi-line macro's.
1125: This whole file is read 3 times by the preprocessor, with PASSn set for
1126: n=1, 2 or 3, to decide which parts to reprocess.
1127: */
1128:
1129: /* #undef on an already undefined thing is (wrongly) flagged as an error
1130: by some compilers, therefore the #ifdef that follows:
1131: */
1132: #ifdef Number
1133: #undef Number
1134: #undef THING
1135: #undef Thing
1136: #undef thing
1137: #undef FPROP
1138: #undef Fname
1139: #undef Store
1140: #undef Sum
1141: #undef Diff
1142: #undef Mul
1143: #undef Div
1144: #undef ZERO
1145: #undef HALF
1146: #undef ONE
1147: #undef TWO
1148: #undef THREE
1149: #undef FOUR
1150: #undef Self
1151: #undef F_check
1152: #undef Validate
1153: #undef EPROP
1154: #undef MARK
1155:
1156: /* These are the float.h constants */
1157: #undef F_RADIX
1158: #undef F_MANT_DIG
1159: #undef F_DIG
1160: #undef F_ROUNDS
1161: #undef F_EPSILON
1162: #undef F_MIN_EXP
1163: #undef F_MIN
1164: #undef F_MIN_10_EXP
1165: #undef F_MAX_EXP
1166: #undef F_MAX
1167: #undef F_MAX_10_EXP
1168: #endif
1169:
1170: #ifdef Integer
1171: #undef Integer
1172: #undef INT
1173: #undef IPROP
1174: #undef Iname
1175: #undef UPROP
1176: #undef Uname
1177: #undef OK_UI
1178: #undef IMARK
1179:
1180: #undef I_MAX
1181: #undef I_MIN
1182: #undef U_MAX
1183: #endif
1184:
1185: #ifdef PASS1
1186:
1187: /* Define the things we're going to use this pass */
1188:
1189: #define Number float
1190: #define THING "FLOAT"
1191: #define Thing "Float"
1192: #define thing "float"
1193: #define Fname "FLT"
1194: #define FPROP fprop
1195: #define Store fStore
1196: #define Sum fSum
1197: #define Diff fDiff
1198: #define Mul fMul
1199: #define Div fDiv
1200: #define ZERO 0.0
1201: #define HALF 0.5
1202: #define ONE 1.0
1203: #define TWO 2.0
1204: #define THREE 3.0
1205: #define FOUR 4.0
1206: #define Self fSelf
1207: #define F_check fCheck
1208: #define MARK "F"
1209: #ifdef VERIFY
1210: #define Validate(prec, val, req, same) fValidate(prec, val, req, same)
1211: #endif
1212:
1213: #define EPROP efprop
1214:
1215: #define Integer short
1216: #define INT "short"
1217: #define IPROP sprop
1218: #define Iname "SHRT"
1219: #ifndef NO_UI
1220: #define OK_UI 1
1221: #endif
1222: #define IMARK ""
1223:
1224: #define UPROP usprop
1225: #define Uname "USHRT"
1226:
1227: #ifdef VERIFY
1228: #ifdef SHRT_MAX
1229: #define I_MAX SHRT_MAX
1230: #endif
1231: #ifdef SHRT_MIN
1232: #define I_MIN SHRT_MIN
1233: #endif
1234: #ifdef USHRT_MAX
1235: #define U_MAX USHRT_MAX
1236: #endif
1237:
1238: #ifdef FLT_RADIX
1239: #define F_RADIX FLT_RADIX
1240: #endif
1241: #ifdef FLT_MANT_DIG
1242: #define F_MANT_DIG FLT_MANT_DIG
1243: #endif
1244: #ifdef FLT_DIG
1245: #define F_DIG FLT_DIG
1246: #endif
1247: #ifdef FLT_ROUNDS
1248: #define F_ROUNDS FLT_ROUNDS
1249: #endif
1250: #ifdef FLT_EPSILON
1251: #define F_EPSILON FLT_EPSILON
1252: #endif
1253: #ifdef FLT_MIN_EXP
1254: #define F_MIN_EXP FLT_MIN_EXP
1255: #endif
1256: #ifdef FLT_MIN
1257: #define F_MIN FLT_MIN
1258: #endif
1259: #ifdef FLT_MIN_10_EXP
1260: #define F_MIN_10_EXP FLT_MIN_10_EXP
1261: #endif
1262: #ifdef FLT_MAX_EXP
1263: #define F_MAX_EXP FLT_MAX_EXP
1264: #endif
1265: #ifdef FLT_MAX
1266: #define F_MAX FLT_MAX
1267: #endif
1268: #ifdef FLT_MAX_10_EXP
1269: #define F_MAX_10_EXP FLT_MAX_10_EXP
1270: #endif
1271: #endif /* VERIFY */
1272:
1273: #endif /* PASS1 */
1274:
1275: #ifdef PASS2
1276:
1277: #define Number double
1278: #define THING "DOUBLE"
1279: #define Thing "Double"
1280: #define thing "double"
1281: #define Fname "DBL"
1282: #define FPROP dprop
1283: #define Store dStore
1284: #define Sum dSum
1285: #define Diff dDiff
1286: #define Mul dMul
1287: #define Div dDiv
1288: #define ZERO 0.0
1289: #define HALF 0.5
1290: #define ONE 1.0
1291: #define TWO 2.0
1292: #define THREE 3.0
1293: #define FOUR 4.0
1294: #define Self dSelf
1295: #define F_check dCheck
1296: #define MARK ""
1297: #ifdef VERIFY
1298: #define Validate(prec, val, req, same) dValidate(prec, val, req, same)
1299: #endif
1300:
1301: #define EPROP edprop
1302:
1303: #define Integer int
1304: #define INT "int"
1305: #define IPROP iprop
1306: #define Iname "INT"
1307: #define OK_UI 1 /* Unsigned int is always possible */
1308: #define IMARK ""
1309:
1310: #define UPROP uiprop
1311: #define Uname "UINT"
1312:
1313: #ifdef VERIFY
1314: #ifdef INT_MAX
1315: #define I_MAX INT_MAX
1316: #endif
1317: #ifdef INT_MIN
1318: #define I_MIN INT_MIN
1319: #endif
1320: #ifdef UINT_MAX
1321: #define U_MAX UINT_MAX
1322: #endif
1323:
1324: #ifdef DBL_MANT_DIG
1325: #define F_MANT_DIG DBL_MANT_DIG
1326: #endif
1327: #ifdef DBL_DIG
1328: #define F_DIG DBL_DIG
1329: #endif
1330: #ifdef DBL_EPSILON
1331: #define F_EPSILON DBL_EPSILON
1332: #endif
1333: #ifdef DBL_MIN_EXP
1334: #define F_MIN_EXP DBL_MIN_EXP
1335: #endif
1336: #ifdef DBL_MIN
1337: #define F_MIN DBL_MIN
1338: #endif
1339: #ifdef DBL_MIN_10_EXP
1340: #define F_MIN_10_EXP DBL_MIN_10_EXP
1341: #endif
1342: #ifdef DBL_MAX_EXP
1343: #define F_MAX_EXP DBL_MAX_EXP
1344: #endif
1345: #ifdef DBL_MAX
1346: #define F_MAX DBL_MAX
1347: #endif
1348: #ifdef DBL_MAX_10_EXP
1349: #define F_MAX_10_EXP DBL_MAX_10_EXP
1350: #endif
1351: #endif /* VERIFY */
1352:
1353: #endif /* PASS2 */
1354:
1355: #ifdef PASS3
1356:
1357: #ifdef STDC
1358: #define Number long double
1359: #endif
1360:
1361: #define THING "LONG DOUBLE"
1362: #define Thing "Long double"
1363: #define thing "long double"
1364: #define Fname "LDBL"
1365: #define FPROP ldprop
1366: #define Store ldStore
1367: #define Sum ldSum
1368: #define Diff ldDiff
1369: #define Mul ldMul
1370: #define Div ldDiv
1371: #define ZERO 0.0L
1372: #define HALF 0.5L
1373: #define ONE 1.0L
1374: #define TWO 2.0L
1375: #define THREE 3.0L
1376: #define FOUR 4.0L
1377: #define Self ldSelf
1378: #define F_check ldCheck
1379: #define MARK "L"
1380: #ifdef VERIFY
1381: #define Validate(prec, val, req, same) ldValidate(prec, val, req, same)
1382: #endif
1383:
1384: #define EPROP eldprop
1385:
1386: #define Integer long
1387: #define INT "long"
1388: #define IPROP lprop
1389: #define Iname "LONG"
1390: #ifndef NO_UI
1391: #define OK_UI 1
1392: #endif
1393: #define IMARK "L"
1394:
1395: #define UPROP ulprop
1396: #define Uname "ULONG"
1397:
1398: #ifdef VERIFY
1399: #ifdef LONG_MAX
1400: #define I_MAX LONG_MAX
1401: #endif
1402: #ifdef LONG_MIN
1403: #define I_MIN LONG_MIN
1404: #endif
1405: #ifdef ULONG_MAX
1406: #define U_MAX ULONG_MAX
1407: #endif
1408:
1409: #ifdef LDBL_MANT_DIG
1410: #define F_MANT_DIG LDBL_MANT_DIG
1411: #endif
1412: #ifdef LDBL_DIG
1413: #define F_DIG LDBL_DIG
1414: #endif
1415: #ifdef LDBL_EPSILON
1416: #define F_EPSILON LDBL_EPSILON
1417: #endif
1418: #ifdef LDBL_MIN_EXP
1419: #define F_MIN_EXP LDBL_MIN_EXP
1420: #endif
1421: #ifdef LDBL_MIN
1422: #define F_MIN LDBL_MIN
1423: #endif
1424: #ifdef LDBL_MIN_10_EXP
1425: #define F_MIN_10_EXP LDBL_MIN_10_EXP
1426: #endif
1427: #ifdef LDBL_MAX_EXP
1428: #define F_MAX_EXP LDBL_MAX_EXP
1429: #endif
1430: #ifdef LDBL_MAX
1431: #define F_MAX LDBL_MAX
1432: #endif
1433: #ifdef LDBL_MAX_10_EXP
1434: #define F_MAX_10_EXP LDBL_MAX_10_EXP
1435: #endif
1436: #endif /* VERIFY */
1437:
1438: #endif /* PASS3 */
1439:
1440: #ifndef I_MAX
1441: #define I_MAX int_max
1442: #endif
1443: #ifndef I_MIN
1444: #define I_MIN int_min
1445: #endif
1446: #ifndef U_MAX
1447: #define U_MAX int_max
1448: #endif
1449:
1450: #ifndef F_RADIX
1451: #define F_RADIX f_radix
1452: #endif
1453: #ifndef F_MANT_DIG
1454: #define F_MANT_DIG f_mant_dig
1455: #endif
1456: #ifndef F_DIG
1457: #define F_DIG f_dig
1458: #endif
1459: #ifndef F_ROUNDS
1460: #define F_ROUNDS f_rounds
1461: #endif
1462: #ifndef F_EPSILON
1463: #define F_EPSILON f_epsilon
1464: #endif
1465: #ifndef F_MIN_EXP
1466: #define F_MIN_EXP f_min_exp
1467: #endif
1468: #ifndef F_MIN
1469: #define F_MIN f_min
1470: #endif
1471: #ifndef F_MIN_10_EXP
1472: #define F_MIN_10_EXP f_min_10_exp
1473: #endif
1474: #ifndef F_MAX_EXP
1475: #define F_MAX_EXP f_max_exp
1476: #endif
1477: #ifndef F_MAX
1478: #define F_MAX f_max
1479: #endif
1480: #ifndef F_MAX_10_EXP
1481: #define F_MAX_10_EXP f_max_10_exp
1482: #endif
1483:
1484: #ifndef VERIFY
1485: #define Validate(prec, val, req, same) {;}
1486: #endif
1487:
1488: #ifdef Integer
1489:
1490: Procedure IPROP() {
1491: /* the properties of short, int, and long */
1492: Volatile Integer newi, int_max, maxeri, int_min, minneri;
1493: Volatile int ibits, ipower, two=2;
1494:
1495: /* Calculate max short/int/long ***********************************/
1496: /* Calculate 2**n-1 until overflow - then use the previous value */
1497:
1498: newi=1; int_max=0;
1499:
1500: if (setjmp(lab)==0) { /* Yields int_max */
1501: for(ipower=0; newi>int_max; ipower++) {
1502: int_max=newi;
1503: newi=newi*two+1;
1504: }
1505: Vprintf("%sOverflow of a%s %s does not generate a trap%s\n",
1506: co, INT[0]=='i'?"n":"", INT, oc);
1507: } else {
1508: Vprintf("%sOverflow of a%s %s generates a trap%s\n",
1509: co, INT[0]=='i'?"n":"", INT, oc);
1510: }
1511: Unexpected(7);
1512:
1513: /* Minimum value: assume either two's or one's complement *********/
1514: int_min= -int_max;
1515: if (setjmp(lab)==0) { /* Yields int_min */
1516: if (int_min-1 < int_min) int_min--;
1517: }
1518: Unexpected(8);
1519:
1520: /* Now for those daft Cybers: */
1521:
1522: maxeri=0; newi=int_max;
1523:
1524: if (setjmp(lab)==0) { /* Yields maxeri */
1525: for(ibits=ipower; newi>maxeri; ibits++) {
1526: maxeri=newi;
1527: newi=newi+newi+1;
1528: }
1529: }
1530: Unexpected(9);
1531:
1532: minneri= -maxeri;
1533: if (setjmp(lab)==0) { /* Yields minneri */
1534: if (minneri-1 < minneri) minneri--;
1535: }
1536: Unexpected(10);
1537:
1538: Vprintf("%sMaximum %s = %ld (= 2**%d-1)%s\n",
1539: co, INT, (long)int_max, ipower, oc);
1540: Vprintf("%sMinimum %s = %ld%s\n", co, INT, (long)int_min, oc);
1541:
1542: if (L) i_define(D_INT_MAX, INT,
1543: Iname, "_MAX", (long) int_max, (long) I_MAX, IMARK);
1544: if (L) i_define(D_INT_MIN, INT,
1545: Iname, "_MIN", (long) int_min, (long) I_MIN, IMARK);
1546:
1547: if (maxeri>int_max) {
1548: Vprintf("%sThere is a larger %s, %ld (= 2**%d-1), %s %s%s\n",
1549: co, INT, (long)maxeri, ibits,
1550: "but only for addition, not multiplication",
1551: "(I smell a Cyber!)",
1552: oc);
1553: }
1554:
1555: if (minneri<int_min) {
1556: Vprintf("%sThere is a smaller %s, %ld, %s %s%s\n",
1557: co, INT, (long)minneri,
1558: "but only for addition, not multiplication",
1559: "(I smell a Cyber!)",
1560: oc);
1561: }
1562: }
1563:
1564: Procedure UPROP () {
1565: /* The properties of unsigned short/int/long */
1566: #ifdef OK_UI
1567: Volatile unsigned Integer int_max, newi, two;
1568: newi=1; int_max=0; two=2;
1569:
1570: if (setjmp(lab)==0) { /* Yields int_max */
1571: while(newi>int_max) {
1572: int_max=newi;
1573: newi=newi*two+1;
1574: }
1575: }
1576: Unexpected(11);
1577: Vprintf("%sMaximum unsigned %s = %lu%s\n",
1578: co, INT, (unsigned long) int_max, oc);
1579: if (L) u_define(D_UINT_MAX, INT,
1580: Uname, "_MAX", (unsigned long) int_max,
1581: (unsigned long) U_MAX, IMARK);
1582: #endif
1583: }
1584:
1585: #endif /* Integer */
1586:
1587: #ifdef Number
1588:
1589: /* The following routines are intended to defeat any attempt at optimisation
1590: or use of extended precision, and to defeat faulty narrowing casts.
1591: The weird prototypes are because of widening incompatibilities.
1592: */
1593: #ifdef STDC
1594: #define ARGS1(atype, a) (atype a)
1595: #define ARGS2(atype, a, btype, b) (atype a, btype b)
1596: #else
1597: #define ARGS1(atype, a) (a) atype a;
1598: #define ARGS2(atype, a, btype, b) (a, b) atype a; btype b;
1599: #endif
1600:
1601: Procedure Store ARGS2(Number, a, Number *, b) { *b=a; }
1602: Number Sum ARGS2(Number, a, Number, b) {Number r; Store(a+b, &r); return (r); }
1603: Number Diff ARGS2(Number, a, Number, b){Number r; Store(a-b, &r); return (r); }
1604: Number Mul ARGS2(Number, a, Number, b) {Number r; Store(a*b, &r); return (r); }
1605: Number Div ARGS2(Number, a, Number, b) {Number r; Store(a/b, &r); return (r); }
1606: Number Self ARGS1(Number, a) {Number r; Store(a, &r); return (r); }
1607:
1608: Procedure F_check ARGS((int precision, Long_double val1));
1609:
1610: Procedure F_check(precision, val1) int precision; Long_double val1; {
1611: /* You don't think I'm going to go to all the trouble of writing
1612: a program that works out what all sorts of values are, only to
1613: have printf go and print the wrong values out, do you?
1614: No, you're right, so this function tries to see if printf
1615: has written the right value, by reading it back again.
1616: This introduces a new problem of course: suppose printf writes
1617: the correct value, and scanf reads it back wrong... oh well.
1618: But I'm adamant about this: the precision given is enough
1619: to uniquely identify the printed number, therefore I insist
1620: that sscanf read the number back identically. Harsh yes, but
1621: sometimes you've got to be cruel to be kind.
1622: */
1623: Long_double new1;
1624: Number val, new, diff;
1625: double rem;
1626: int e;
1627: char *rep;
1628: char *f2;
1629:
1630: if (sizeof(double) == sizeof(Long_double)) {
1631: /* Assume they're the same, and use non-stdc format */
1632: /* This is for stdc compilers using non-stdc libraries */
1633: f2= "%le"; /* Input */
1634: } else {
1635: /* It had better support Le then */
1636: f2= "%Le";
1637: }
1638: val= val1;
1639: rep= f_rep(precision, (Long_double) val);
1640: if (setjmp(lab)==0) {
1641: sscanf(rep, f2, &new1);
1642: } else {
1643: eek_a_bug("sscanf caused a trap");
1644: printf("%s scanning: %s format: %s%s\n\n", co, rep, f2, oc);
1645: Unexpected(12);
1646: return;
1647: }
1648:
1649: if (setjmp(lab)==0) { /* See if new is usable */
1650: new= new1;
1651: if (new != 0.0) {
1652: diff= val/new - 1.0;
1653: if (diff < 0.1) diff= 1.0;
1654: /* That should be enough to generate a trap */
1655: }
1656: } else {
1657: eek_a_bug("sscanf returned an unusable number");
1658: printf("%s scanning: %s with format: %s%s\n\n",
1659: co, rep, f2, oc);
1660: Unexpected(13);
1661: return;
1662: }
1663:
1664: Unexpected(14);
1665: if (new != val) {
1666: eek_a_bug("Possibly bad output from printf above");
1667: if (!exponent((Long_double)val, &rem, &e)) {
1668: printf("%s but value was an unusable number%s\n\n",
1669: co, oc);
1670: return;
1671: }
1672: printf("%s expected value around %.*fe%d, bit pattern:\n ",
1673: co, precision, rem, e);
1674: bitpattern((char *) &val, sizeof(val));
1675: printf ("%s\n", oc);
1676: printf("%s sscanf gave %s, bit pattern:\n ",
1677: co, f_rep(precision, (Long_double) new));
1678: bitpattern((char *) &new, sizeof(new));
1679: printf ("%s\n", oc);
1680: if (setjmp(lab) == 0) {
1681: diff= val-new;
1682: printf("%s difference= %s%s\n\n",
1683: co, f_rep(precision, (Long_double) diff), oc);
1684: } /* else forget it */
1685: Unexpected(15);
1686: }
1687: }
1688:
1689: #ifdef VERIFY
1690: Procedure Validate(prec, val, req, same) int prec, same; Long_double val, req; {
1691: /* Check that the compiler has read a #define value correctly */
1692: Unexpected(16);
1693: if (!same) {
1694: printf("%s*** Verify failed for above #define!\n", co);
1695: if (setjmp(lab) == 0) { /* for the case that req == nan */
1696: printf(" Compiler has %s for value%s\n",
1697: f_rep(prec, req), oc);
1698: } else {
1699: printf(" Compiler has %s for value%s\n",
1700: "an unusable number", oc);
1701: }
1702: if (setjmp(lab) == 0) {
1703: F_check(prec, (Long_double) req);
1704: } /*else forget it*/
1705: if (setjmp(lab) == 0) {
1706: if (req > 0.0 && val > 0.0) {
1707: printf("%s difference= %s%s\n",
1708: co, f_rep(prec, val-req), oc);
1709: }
1710: } /*else forget it*/
1711: Unexpected(17);
1712: printf("\n");
1713: bugs++;
1714: } else if (val != req) {
1715: if (stdc) {
1716: printf("%s*** Verify failed for above #define!\n", co);
1717: printf(" Constant has the wrong precision%s\n",
1718: oc);
1719: } else eek_a_bug("the cast didn't work");
1720: printf("\n");
1721: bugs++;
1722: }
1723: }
1724: #endif /* VERIFY */
1725:
1726: int FPROP(bits_per_byte) int bits_per_byte; {
1727: /* Properties of floating types, using algorithms by Cody and Waite
1728: from MA Malcolm, as modified by WM Gentleman and SB Marovich.
1729: Further extended by S Pemberton.
1730:
1731: Returns the number of digits in the fraction.
1732: */
1733:
1734: Volatile int
1735: i, f_radix, iexp, irnd, mrnd, f_rounds, f_mant_dig,
1736: iz, k, inf, machep, f_max_exp, f_min_exp, mx, negeps,
1737: mantbits, digs, f_dig, trap,
1738: hidden, normal, f_min_10_exp, f_max_10_exp;
1739: Volatile Number
1740: a, b, base, basein, basem1, f_epsilon, epsneg,
1741: eps, epsp1, etop, ebot,
1742: f_max, newxmax, f_min, xminner, y, y1, z, z1, z2;
1743:
1744: Unexpected(18);
1745:
1746: Vprintf("%sPROPERTIES OF %s:%s\n", co, THING, oc);
1747:
1748: /* Base and size of mantissa **************************************/
1749: /* First repeatedly double until adding 1 has no effect. */
1750: /* For instance, if base is 10, with 3 significant digits */
1751: /* it will try 1, 2, 4, 8, ... 512, 1024, and stop there, */
1752: /* since 1024 is only representable as 1020. */
1753: a=1.0;
1754: if (setjmp(lab)==0) { /* inexact trap? */
1755: do { a=Sum(a, a); }
1756: while (Diff(Diff(Sum(a, ONE), a), ONE) == ZERO);
1757: } else {
1758: fprintf(stderr, "*** Program got loss-of-precision trap!\n");
1759: /* And supporting those is just TOO much trouble! */
1760: farewell(bugs+1);
1761: }
1762: Unexpected(19);
1763: /* Now double until you find a number that can be added to the */
1764: /* above number. For 1020 this is 8 or 16, depending whether the */
1765: /* result is rounded or truncated. */
1766: /* In either case the result is 1030. 1030-1020= the base, 10. */
1767: b=1.0;
1768: do { b=Sum(b, b); } while ((base=Diff(Sum(a, b), a)) == ZERO);
1769: f_radix=base;
1770: Vprintf("%sBase = %d%s\n", co, f_radix, oc);
1771:
1772: /* Sanity check; if base<2, I can't guarantee the rest will work */
1773: if (f_radix < 2) {
1774: eek_a_bug("Function return or parameter passing faulty? (This is a guess.)");
1775: printf("\n");
1776: return(0);
1777: }
1778:
1779: #ifdef PASS1 /* only for FLT */
1780: flt_radix= f_radix;
1781: if (F) i_define(D_FLT_RADIX, "",
1782: "FLT", "_RADIX", (long) f_radix, (long) F_RADIX, "");
1783: #else
1784: if (f_radix != flt_radix) {
1785: printf("\n%s*** WARNING: %s %s (%d) %s%s\n",
1786: co, thing, "arithmetic has a different radix",
1787: f_radix, "from float", oc);
1788: bugs++;
1789: }
1790: #endif
1791:
1792: /* Now the number of digits precision: */
1793: f_mant_dig=0; b=1.0;
1794: do { f_mant_dig++; b=Mul(b, base); }
1795: while (Diff(Diff(Sum(b, ONE), b), ONE) == ZERO);
1796: f_dig=floor_log(10, (Long_double)(b/base)) + (base==10?1:0);
1797: Vprintf("%sSignificant base digits = %d %s %d %s%s\n",
1798: co, f_mant_dig, "(= at least", f_dig, "decimal digits)", oc);
1799: if (F) i_define(D_MANT_DIG, thing,
1800: Fname, "_MANT_DIG", (long) f_mant_dig,
1801: (long) F_MANT_DIG, "");
1802: if (F) i_define(D_DIG, thing,
1803: Fname, "_DIG", (long) f_dig, (long) F_DIG, "");
1804: digs= ceil_log(10, (Long_double)b); /* the number of digits to printf */
1805:
1806: /* Rounding *******************************************************/
1807: basem1=Diff(base, HALF);
1808: if (Diff(Sum(a, basem1), a) != ZERO) {
1809: if (f_radix == 2) basem1=0.375;
1810: else basem1=1.0;
1811: if (Diff(Sum(a, basem1), a) != ZERO) irnd=2; /* away from 0 */
1812: else irnd=1; /* to nearest */
1813: } else irnd=0; /* towards 0 */
1814:
1815: basem1=Diff(base, HALF);
1816:
1817: if (Diff(Diff(-a, basem1), -a) != ZERO) {
1818: if (f_radix == 2) basem1=0.375;
1819: else basem1=1.0;
1820: if (Diff(Diff(-a, basem1), -a) != ZERO) mrnd=2; /* away from 0*/
1821: else mrnd=1; /* to nearest */
1822: } else mrnd=0; /* towards 0 */
1823:
1824: f_rounds= -1; /* Unknown rounding */
1825: if (irnd==0 && mrnd==0) f_rounds=0; /* zero = chops */
1826: if (irnd==1 && mrnd==1) f_rounds=1; /* nearest */
1827: if (irnd==2 && mrnd==0) f_rounds=2; /* +inf */
1828: if (irnd==0 && mrnd==2) f_rounds=3; /* -inf */
1829:
1830: if (f_rounds != -1) {
1831: Vprintf("%sArithmetic rounds towards ", co);
1832: switch (f_rounds) {
1833: case 0: Vprintf("zero (i.e. it chops)"); break;
1834: case 1: Vprintf("nearest"); break;
1835: case 2: Vprintf("+infinity"); break;
1836: case 3: Vprintf("-infinity"); break;
1837: default: Vprintf("???"); break;
1838: }
1839: Vprintf("%s\n", oc);
1840: } else { /* Hmm, try to give some help here: */
1841: Vprintf("%sArithmetic rounds oddly: %s\n", co, oc);
1842: Vprintf("%s Negative numbers %s%s\n",
1843: co, mrnd==0 ? "towards zero" :
1844: mrnd==1 ? "to nearest" :
1845: "away from zero",
1846: oc);
1847: Vprintf("%s Positive numbers %s%s\n",
1848: co, irnd==0 ? "towards zero" :
1849: irnd==1 ? "to nearest" :
1850: "away from zero",
1851: oc);
1852: }
1853: /* An extra goody */
1854: if (f_radix == 2 && f_rounds == 1) {
1855: if (Diff(Sum(a, ONE), a) != ZERO) {
1856: Vprintf("%s Tie breaking rounds up%s\n", co, oc);
1857: } else if (Diff(Sum(a, THREE), a) == FOUR) {
1858: Vprintf("%s Tie breaking rounds to even%s\n", co, oc);
1859: } else {
1860: Vprintf("%s Tie breaking rounds down%s\n", co, oc);
1861: }
1862: }
1863: #ifdef PASS1 /* only for FLT */
1864: flt_rounds= f_rounds;
1865: if (F)
1866: i_define(D_FLT_ROUNDS, "",
1867: "FLT", "_ROUNDS", (long) f_rounds, (long) F_ROUNDS, "");
1868: #else
1869: if (f_rounds != flt_rounds) {
1870: printf("\n%s*** WARNING: %s %s (%d) %s%s\n",
1871: co, thing, "arithmetic rounds differently",
1872: f_rounds, "from float", oc);
1873: bugs++;
1874: }
1875: #endif
1876:
1877: /* Various flavours of epsilon ************************************/
1878: negeps=f_mant_dig+f_mant_dig;
1879: basein=1.0/base;
1880: a=1.0;
1881: for(i=1; i<=negeps; i++) a*=basein;
1882:
1883: b=a;
1884: while (Diff(Diff(ONE, a), ONE) == ZERO) {
1885: a*=base;
1886: negeps--;
1887: }
1888: negeps= -negeps;
1889: Vprintf("%sSmallest x such that 1.0-base**x != 1.0 = %d%s\n",
1890: co, negeps, oc);
1891:
1892: etop = ONE;
1893: ebot = ZERO;
1894: eps = Sum(ebot, Div(Diff(etop, ebot), TWO));
1895: while (eps != ebot && eps != etop) {
1896: epsp1 = Diff(ONE, eps);
1897: if (epsp1 < ONE) etop = eps;
1898: else ebot = eps;
1899: eps = Sum(ebot, Div(Diff(etop, ebot), TWO));
1900: }
1901: /* Sanity check */
1902: if (Diff(ONE, etop) >= ONE || Diff(ONE, ebot) != ONE) {
1903: eek_a_bug("internal error calculating epsneg");
1904: }
1905: Vprintf("%sSmallest x such that 1.0-x != 1.0 = %s%s\n",
1906: co, f_rep(digs, (Long_double) eps), oc);
1907: if (V) F_check(digs, (Long_double) eps);
1908:
1909: epsneg=a;
1910: if ((f_radix!=2) && irnd) {
1911: /* a=(a*(1.0+a))/(1.0+1.0); => */
1912: a=Div(Mul(a, Sum(ONE, a)), Sum(ONE, ONE));
1913: /* if ((1.0-a)-1.0 != 0.0) epsneg=a; => */
1914: if (Diff(Diff(ONE, a), ONE) != ZERO) epsneg=a;
1915: }
1916: /* epsneg is used later */
1917: Unexpected(20);
1918:
1919: machep= -f_mant_dig-f_mant_dig;
1920: a=b;
1921: while (Diff(Sum(ONE, a), ONE) == ZERO) { a*=base; machep++; }
1922: Vprintf("%sSmallest x such that 1.0+base**x != 1.0 = %d%s\n",
1923: co, machep, oc);
1924:
1925: etop = ONE;
1926: ebot = ZERO;
1927: eps = Sum(ebot, Div(Diff(etop, ebot), TWO));
1928: while (eps != ebot && eps != etop) {
1929: epsp1 = Sum(ONE, eps);
1930: if (epsp1 > ONE) etop = eps;
1931: else ebot = eps;
1932: eps = Sum(ebot, Div(Diff(etop, ebot), TWO));
1933: }
1934: /* Sanity check */
1935: if (Sum(ONE, etop) <= ONE || Sum(ONE, ebot) != ONE) {
1936: eek_a_bug("internal error calculating eps");
1937: }
1938: f_epsilon=etop;
1939:
1940: Vprintf("%sSmallest x such that 1.0+x != 1.0 = %s%s\n",
1941: co, f_rep(digs, (Long_double) f_epsilon), oc);
1942: /* Possible loss of precision warnings here from non-stdc compilers: */
1943: if (F) f_define(D_EPSILON, thing,
1944: Fname, "_EPSILON", digs, (Long_double) f_epsilon, MARK);
1945: if (V || F) F_check(digs, (Long_double) f_epsilon);
1946: Unexpected(21);
1947: if (F) Validate(digs, (Long_double) f_epsilon, (Long_double) F_EPSILON,
1948: f_epsilon == Self(F_EPSILON));
1949: Unexpected(22);
1950:
1951: /* Extra chop info *************************************************/
1952: if (f_rounds == 0) {
1953: if (Diff(Mul(Sum(ONE,f_epsilon),ONE),ONE) != ZERO) {
1954: Vprintf("%sAlthough arithmetic chops, it uses guard digits%s\n", co, oc);
1955: }
1956: }
1957:
1958: /* Size of and minimum normalised exponent ************************/
1959: y=0; i=0; k=1; z=basein; z1=(1.0+f_epsilon)/base;
1960:
1961: /* Coarse search for the largest power of two */
1962: if (setjmp(lab)==0) { /* for underflow trap */ /* Yields i, k, y, y1 */
1963: do {
1964: y=z; y1=z1;
1965: z=Mul(y,y); z1=Mul(z1, y);
1966: a=Mul(z,ONE);
1967: z2=Div(z1,y);
1968: if (z2 != y1) break;
1969: if ((Sum(a,a) == ZERO) || (fabs(z) >= y)) break;
1970: i++;
1971: k+=k;
1972: } while(1);
1973: } else {
1974: Vprintf("%s%s underflow generates a trap%s\n", co, Thing, oc);
1975: }
1976: Unexpected(23);
1977:
1978: if (f_radix != 10) {
1979: iexp=i+1; /* for the sign */
1980: mx=k+k;
1981: } else {
1982: iexp=2;
1983: iz=f_radix;
1984: while (k >= iz) { iz*=f_radix; iexp++; }
1985: mx=iz+iz-1;
1986: }
1987:
1988: /* Fine tune starting with y and y1 */
1989: if (setjmp(lab)==0) { /* for underflow trap */ /* Yields k, f_min */
1990: do {
1991: f_min=y; z1=y1;
1992: y=Div(y,base); y1=Div(y1,base);
1993: a=Mul(y,ONE);
1994: z2=Mul(y1,base);
1995: if (z2 != z1) break;
1996: if ((Sum(a,a) == ZERO) || (fabs(y) >= f_min)) break;
1997: k++;
1998: } while (1);
1999: }
2000: Unexpected(24);
2001:
2002: f_min_exp=(-k)+1;
2003:
2004: if ((mx <= k+k-3) && (f_radix != 10)) { mx+=mx; iexp+=1; }
2005: Vprintf("%sNumber of bits used for exponent = %d%s\n", co, iexp, oc);
2006: Vprintf("%sMinimum normalised exponent = %d%s\n", co, f_min_exp, oc);
2007: if (F)
2008: i_define(D_MIN_EXP, thing,
2009: Fname, "_MIN_EXP", (long) f_min_exp, (long) F_MIN_EXP, "");
2010:
2011: if (setjmp(lab)==0) {
2012: Vprintf("%sMinimum normalised positive number = %s%s\n",
2013: co, f_rep(digs, (Long_double) f_min), oc);
2014: } else {
2015: eek_a_bug("printf can't print the smallest normalised number");
2016: printf("\n");
2017: }
2018: Unexpected(25);
2019: /* Possible loss of precision warnings here from non-stdc compilers: */
2020: if (setjmp(lab) == 0) {
2021: if (F) f_define(D_MIN, thing,
2022: Fname, "_MIN", digs, (Long_double) f_min, MARK);
2023: if (V || F) F_check(digs, (Long_double) f_min);
2024: } else {
2025: eek_a_bug("xxx_MIN caused a trap");
2026: printf("\n");
2027: }
2028:
2029: if (setjmp(lab) == 0) {
2030: if (F) Validate(digs, (Long_double) f_min, (Long_double) F_MIN,
2031: f_min == Self(F_MIN));
2032: } else {
2033: printf("%s*** Verify failed for above #define!\n %s %s\n\n",
2034: co, "Compiler has an unusable number for value", oc);
2035: bugs++;
2036: }
2037: Unexpected(26);
2038:
2039: a=1.0; f_min_10_exp=0;
2040: while (a > f_min*10.0) { a/=10.0; f_min_10_exp--; }
2041: if (F) i_define(D_MIN_10_EXP, thing,
2042: Fname, "_MIN_10_EXP", (long) f_min_10_exp,
2043: (long) F_MIN_10_EXP, "");
2044:
2045: /* Minimum exponent ************************************************/
2046: if (setjmp(lab)==0) { /* for underflow trap */ /* Yields xminner */
2047: do {
2048: xminner=y;
2049: y=Div(y,base);
2050: a=Mul(y,ONE);
2051: if ((Sum(a,a) == ZERO) || (fabs(y) >= xminner)) break;
2052: } while (1);
2053: }
2054: Unexpected(27);
2055:
2056: if (xminner != 0.0 && xminner != f_min) {
2057: normal= 0;
2058: Vprintf("%sThe smallest numbers are not kept normalised%s\n",
2059: co, oc);
2060: if (setjmp(lab)==0) {
2061: Vprintf("%sSmallest unnormalised positive number = %s%s\n",
2062: co, f_rep(digs, (Long_double) xminner), oc);
2063: if (V) F_check(digs, (Long_double) xminner);
2064: } else {
2065: eek_a_bug("printf can't print the smallest unnormalised number.");
2066: printf("\n");
2067: }
2068: Unexpected(28);
2069: } else {
2070: normal= 1;
2071: Vprintf("%sThe smallest numbers are normalised%s\n", co, oc);
2072: }
2073:
2074: /* Maximum exponent ************************************************/
2075: f_max_exp=2; f_max=1.0; newxmax=base+1.0;
2076: inf=0; trap=0;
2077: while (f_max<newxmax) {
2078: f_max=newxmax;
2079: if (setjmp(lab) == 0) { /* Yields inf, f_max_exp */
2080: newxmax=Mul(newxmax, base);
2081: } else {
2082: trap=1;
2083: break;
2084: }
2085: if (Div(newxmax, base) != f_max) {
2086: inf=1; /* ieee infinity */
2087: break;
2088: }
2089: f_max_exp++;
2090: }
2091: Unexpected(29);
2092: if (trap) {
2093: Vprintf("%s%s overflow generates a trap%s\n", co, Thing, oc);
2094: }
2095:
2096: if (inf) Vprintf("%sThere is an 'infinite' value%s\n", co, oc);
2097: Vprintf("%sMaximum exponent = %d%s\n", co, f_max_exp, oc);
2098: if (F) i_define(D_MAX_EXP, thing,
2099: Fname, "_MAX_EXP", (long) f_max_exp,
2100: (long) F_MAX_EXP, "");
2101:
2102: /* Largest number ***************************************************/
2103: f_max=Diff(ONE, epsneg);
2104: if (Mul(f_max,ONE) != f_max) f_max=Diff(ONE, Mul(base,epsneg));
2105: for (i=1; i<=f_max_exp; i++) f_max=Mul(f_max, base);
2106:
2107: if (setjmp(lab)==0) {
2108: Vprintf("%sMaximum number = %s%s\n",
2109: co, f_rep(digs, (Long_double) f_max), oc);
2110: } else {
2111: eek_a_bug("printf can't print the largest double.");
2112: printf("\n");
2113: }
2114: if (setjmp(lab)==0) {
2115: /* Possible loss of precision warnings here from non-stdc compilers: */
2116: if (F) f_define(D_MAX, thing,
2117: Fname, "_MAX", digs, (Long_double) f_max, MARK);
2118: if (V || F) F_check(digs, (Long_double) f_max);
2119: } else {
2120: eek_a_bug("xxx_MAX caused a trap");
2121: printf("\n");
2122: }
2123: if (setjmp(lab)==0) {
2124: if (F) Validate(digs, (Long_double) f_max, (Long_double) F_MAX,
2125: f_max == Self(F_MAX));
2126: } else {
2127: printf("%s*** Verify failed for above #define!\n %s %s\n\n",
2128: co, "Compiler has an unusable number for value", oc);
2129: bugs++;
2130: }
2131: Unexpected(30);
2132:
2133: a=1.0; f_max_10_exp=0;
2134: while (a < f_max/10.0) { a*=10.0; f_max_10_exp++; }
2135: if (F) i_define(D_MAX_10_EXP, thing,
2136: Fname, "_MAX_10_EXP", (long) f_max_10_exp,
2137: (long) F_MAX_10_EXP, "");
2138:
2139: /* Hidden bit + sanity check ****************************************/
2140: if (f_radix != 10) {
2141: hidden=0;
2142: mantbits=floor_log(2, (Long_double)f_radix)*f_mant_dig;
2143: if (mantbits+iexp == (int)sizeof(Number)*bits_per_byte) {
2144: hidden=1;
2145: Vprintf("%sArithmetic uses a hidden bit%s\n", co, oc);
2146: } else if (mantbits+iexp+1 == (int)sizeof(Number)*bits_per_byte) {
2147: Vprintf("%sArithmetic doesn't use a hidden bit%s\n",
2148: co, oc);
2149: } else {
2150: printf("\n%s%s\n %s %s %s!%s\n\n",
2151: co,
2152: "*** Something fishy here!",
2153: "Exponent size + mantissa size doesn't match",
2154: "with the size of a", thing,
2155: oc);
2156: }
2157: if (hidden && f_radix == 2 && f_max_exp+f_min_exp==3) {
2158: Vprintf("%sIt looks like %s length IEEE format%s\n",
2159: co, f_mant_dig==24 ? "single" :
2160: f_mant_dig==53 ? "double" :
2161: f_mant_dig >53 ? "extended" :
2162: "some", oc);
2163: if (f_rounds != 1 || normal) {
2164: Vprintf("%s though ", co);
2165: if (f_rounds != 1) {
2166: Vprintf("the rounding is unusual");
2167: if (normal) Vprintf(" and ");
2168: }
2169: if (normal) Vprintf("the normalisation is unusual");
2170: Vprintf("%s\n", oc);
2171: }
2172: } else {
2173: Vprintf("%sIt doesn't look like IEEE format%s\n",
2174: co, oc);
2175: }
2176: }
2177: printf("\n"); /* regardless of verbosity */
2178: return f_mant_dig;
2179: }
2180:
2181: Procedure EPROP(fprec, dprec, lprec) int fprec, dprec, lprec; {
2182: /* See if expressions are evaluated in extended precision.
2183: Some compilers optimise even if you don't want it,
2184: and then this function fails to produce the right result.
2185: We try to diagnose this if it happens.
2186: */
2187: Volatile int eprec;
2188: Volatile double a, b, base, old;
2189: Volatile Number d, oldd, dbase, one, zero;
2190: Volatile int bad=0;
2191:
2192: /* Size of mantissa **************************************/
2193: a=1.0;
2194: if (setjmp(lab) == 0) { /* Yields nothing */
2195: do { old=a; a=a+a; }
2196: while ((((a+1.0)-a)-1.0) == 0.0 && a>old);
2197: } else bad=1;
2198: if (a <= old) bad=1;
2199:
2200: if (!bad) {
2201: b=1.0;
2202: if (setjmp(lab) == 0) { /* Yields nothing */
2203: do { old=b; b=b+b; }
2204: while ((base=((a+b)-a)) == 0.0 && b>old);
2205: if (b <= old) bad=1;
2206: } else bad=1;
2207: }
2208:
2209: if (!bad) {
2210: eprec=0; d=1.0; dbase=base; one=1.0; zero=0.0;
2211: if (setjmp(lab) == 0) { /* Yields nothing */
2212: do { eprec++; oldd=d; d=d*dbase; }
2213: while ((((d+one)-d)-one) == zero && d>oldd);
2214: if (d <= oldd) bad=1;
2215: } else bad=1;
2216: }
2217:
2218: Unexpected(31);
2219:
2220: if (bad) {
2221: Vprintf("%sCan't determine precision for %s expressions:\n%s%s\n",
2222: co, thing, " check that you compiled without optimisation!",
2223: oc);
2224: } else if (eprec==dprec) {
2225: Vprintf("%s%s expressions are evaluated in double precision%s\n",
2226: co, Thing, oc);
2227: } else if (eprec==fprec) {
2228: Vprintf("%s%s expressions are evaluated in float precision%s\n",
2229: co, Thing, oc);
2230: } else if (eprec==lprec) {
2231: Vprintf("%s%s expressions are evaluated in long double precision%s\n",
2232: co, Thing, oc);
2233: } else {
2234: Vprintf("%s%s expressions are evaluated in a %s %s %d %s%s\n",
2235: co, Thing, eprec>dprec ? "higher" : "lower",
2236: "precision than double,\n using",
2237: eprec, "base digits",
2238: oc);
2239: }
2240: }
2241:
2242: #else /* not Number */
2243:
2244: #ifdef FPROP
2245: /* ARGSUSED */
2246: int FPROP(bits_per_byte) int bits_per_byte; { return 0; }
2247: #endif
2248: #ifdef EPROP
2249: /* ARGSUSED */
2250: Procedure EPROP(fprec, dprec, lprec) int fprec, dprec, lprec; {}
2251: #endif
2252:
2253: #endif /* ifdef Number */
2254:
2255: #ifdef PASS3
2256: #undef PASS
2257: #endif
2258:
2259: #ifdef PASS2
2260: #undef PASS2
2261: #define PASS3 1
2262: #endif
2263:
2264: #ifdef PASS1
2265: #undef PASS1
2266: #define PASS2 1
2267: #endif
2268:
2269: #ifdef PASS0
2270: #undef PASS0
2271: #endif
2272:
2273: #ifdef PASS /* then rescan this file */
2274: #ifdef NO_FILE
2275: #include "config.c"
2276: #else /* if the next line fails to compile, define NO_FILE */
2277: #include __FILE__
2278: #endif
2279: #endif /* PASS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.