]>
Commit | Line | Data |
---|---|---|
2aa62f2b | 1 | /** @file\r |
2 | Every thing you wanted to know about your compiler but didn't know whom to ask.\r | |
3 | \r | |
4 | COPYRIGHT(c) 1993-9 Steven Pemberton, CWI. All rights reserved.\r | |
5 | Steven Pemberton, CWI, Amsterdam; "Steven.Pemberton@cwi.nl"\r | |
6 | Used with permission.\r | |
7 | \r | |
8 | Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r | |
9 | This program and the accompanying materials\r | |
10 | are licensed and made available under the terms and conditions of the BSD License\r | |
11 | which accompanies this distribution. The full text of the license may be found at\r | |
12 | http://opensource.org/licenses/bsd-license.\r | |
13 | \r | |
14 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r | |
15 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r | |
16 | **/\r | |
17 | #if defined(_MSC_VER) /* Handle Microsoft VC++ compiler specifics. */\r | |
18 | #pragma warning ( disable : 4018 )\r | |
19 | #pragma warning ( disable : 4055 )\r | |
20 | #pragma warning ( disable : 4116 )\r | |
21 | #pragma warning ( disable : 4130 )\r | |
22 | #pragma warning ( disable : 4189 )\r | |
23 | #pragma warning ( disable : 4244 )\r | |
24 | #pragma warning ( disable : 4723 )\r | |
25 | #endif /* defined(_MSC_VER) */\r | |
26 | \r | |
27 | //#define NO_SC 1 // Compiler doesn't support signed char\r | |
28 | //#define NO_UC 1 // Compiler doesn't support unsigned char\r | |
29 | //#define NO_UI 1 // Compiler doesn't support unsigned short and long\r | |
30 | //#define NO_VOID 1 // Compiler doesn't support void\r | |
31 | //#define NO_SIG 1 // Compiler doesn't support signal() or setjmp/longjmp()\r | |
32 | \r | |
33 | /* Some compilers can't cope with "#ifdef __FILE__". Use\r | |
34 | either the FILENAME or BAD_CPP macro as described below.\r | |
35 | */\r | |
36 | /* If your C preprocessor doesn't have the predefined __FILE__\r | |
37 | macro, and you don't want to call this file enquire.c but, say,\r | |
38 | tell.c, uncomment the following and change enquire.c to tell.c.\r | |
39 | */\r | |
40 | //#define FILENAME "enquire.c"\r | |
41 | \r | |
42 | /* Some compilers won't accept the line "#include FILENAME". Uncomment\r | |
43 | the following macro. In that case, this file *must* be called enquire.c.\r | |
44 | */\r | |
45 | //#define BAD_CPP 1\r | |
46 | \r | |
47 | /* Some naughty compilers define __STDC__, but don't really\r | |
48 | support it. Some define it as 0, in which case we ignore it.\r | |
49 | But if your compiler defines it, and isn't really ANSI C,\r | |
50 | uncomment the BAD_STDC macro. (To those compiler writers: for shame).\r | |
51 | */\r | |
52 | //#define BAD_STDC 1\r | |
53 | \r | |
54 | /* Some naughty compilers define __STDC__, but don't have the\r | |
55 | stddef.h include file. Uncomment the BAD_STDDEF macro. (Gcc needs this on\r | |
56 | some machines, due to clashes between stddef.h and other include files.)\r | |
57 | */\r | |
58 | //#define BAD_STDDEF 1\r | |
59 | \r | |
60 | /* Some systems crash when you try to malloc all store. To save users of such\r | |
61 | defective systems too much grief, they may uncomment the BAD_MALLOC macro,\r | |
62 | which ignores that bit of the code.\r | |
63 | */\r | |
64 | //#define BAD_MALLOC 1\r | |
65 | \r | |
66 | \r | |
67 | \r | |
68 | #ifndef PROGRAM\r | |
69 | #define PROGRAM enquire.c\r | |
70 | #define VERSION "5.1a"\r | |
71 | #define PURPOSE Everything you wanted to know about your machine and C compiler\r | |
72 | #define BUT didnt know who to ask\r | |
73 | #define FOR Any OS, any C compiler\r | |
74 | #define AUTHOR Steven Pemberton, CWI, Amsterdam; "Steven.Pemberton@cwi.nl"\r | |
75 | #define COPYRIGHT(c) 1993-9 Steven Pemberton, CWI. All rights reserved.\r | |
76 | #define NOTE Improvements gratefully received. Please mention the version.\r | |
77 | #define COMPILE On Unix compile with: "sh enquire.c"; see below for details\r | |
78 | #define WEB "http://www.cwi.nl/~steven/enquire.html"\r | |
79 | #endif\r | |
80 | \r | |
81 | #ifdef NOTDEFINED /* This is how you compile it; see below for details */\r | |
82 | case $0 in\r | |
83 | *.c) ;;\r | |
84 | sh) echo 'Use "sh enquire.c", not "sh < enquire.c"' >&2; exit 1;;\r | |
85 | *) echo 'Filename must end in ".c"' >&2; exit 1;;\r | |
86 | esac\r | |
87 | if test -r test.c\r | |
88 | then echo Would overwrite test.c - try it somewhere safer >&2; exit 1\r | |
89 | fi\r | |
90 | CFLAGS=\r | |
91 | echo Testing for needed CFLAGS ...\r | |
92 | echo "main(){char c; c=0;}" > test.c\r | |
93 | if ${CC=cc} ${1+"$@"} -o enquire test.c $LIBS\r | |
94 | then :\r | |
95 | else\r | |
96 | echo '*** "'$CC ${1+"$@"} -o enquire test.c $LIBS'" failed'\r | |
97 | echo '*** Giving up'\r | |
98 | /bin/rm -f test.c\r | |
99 | exit 1\r | |
100 | fi\r | |
101 | echo "main(){signed char c; c=0;}" > test.c\r | |
102 | if $CC ${1+"$@"} -o enquire test.c $LIBS 2>/dev/null\r | |
103 | then echo " Signed char ok"\r | |
104 | else\r | |
105 | CFLAGS=-DNO_SC\r | |
106 | echo " Signed char not accepted; using $CFLAGS"\r | |
107 | fi\r | |
108 | echo "main(){unsigned char c; c=0;}" > test.c\r | |
109 | if $CC ${1+"$@"} -o enquire test.c $LIBS 2>/dev/null\r | |
110 | then echo " Unsigned char ok"\r | |
111 | else\r | |
112 | CFLAGS="$CFLAGS -DNO_UC"\r | |
113 | echo " Unsigned char not accepted; using $CFLAGS"\r | |
114 | fi\r | |
115 | echo "main(){unsigned short s;unsigned long l;s=0;l=0;}" > test.c\r | |
116 | if $CC ${1+"$@"} -o enquire test.c $LIBS 2>/dev/null\r | |
117 | then echo " Unsigned short and long ok"\r | |
118 | else\r | |
119 | CFLAGS="$CFLAGS -DNO_UI"\r | |
120 | echo " Unsigned short or long not accepted; using $CFLAGS"\r | |
121 | fi\r | |
122 | echo "void foo(){} main(){foo();}" > test.c\r | |
123 | if $CC ${1+"$@"} -o enquire test.c $LIBS 2>/dev/null\r | |
124 | then echo " Void ok"\r | |
125 | else\r | |
126 | CFLAGS="$CFLAGS -DNO_VOID"\r | |
127 | echo " Void not accepted; using $CFLAGS"\r | |
128 | fi\r | |
129 | /bin/rm -f test.c a.out\r | |
130 | \r | |
131 | echo Compiling $0 ...\r | |
132 | case $# in\r | |
133 | 0) : check bug in interpreting "$@" in some shells, if no parameters\r | |
134 | case `echo 1 "$@" 2` in\r | |
135 | "1 2") echo ' *** There is a bug in your shell expanding "$@"!'\r | |
136 | echo ' *** Taking remedial action' ;;\r | |
137 | "1 2") ;;\r | |
138 | esac\r | |
139 | esac\r | |
140 | case $ID in\r | |
141 | "") echo " $CC" $CFLAGS "$@" $0 -o enquire $LIBS\r | |
142 | $CC $CFLAGS ${1+"$@"} $0 -o enquire $LIBS ||\r | |
143 | { echo '***' Try setting some CFLAGS; exit 1; }\r | |
144 | ;;\r | |
145 | *) echo " $CC" $CFLAGS "$@" -DID="\"$ID\"" $0 -o enquire $LIBS\r | |
146 | $CC $CFLAGS ${1+"$@"} -DID="\"$ID\"" $0 -o enquire $LIBS ||\r | |
147 | { echo '***' Try setting some CFLAGS; exit 1; }\r | |
148 | esac\r | |
149 | echo "Producing enquire.out limits.h and float.h ..."\r | |
150 | echo " enquire > enquire.out"\r | |
151 | ./enquire > enquire.out || echo ' *** Some problems: see enquire.out'\r | |
152 | echo " enquire -l > limits.h"\r | |
153 | ./enquire -l > limits.h || echo ' *** Some problems: see limits.h'\r | |
154 | echo " enquire -f > float.h"\r | |
155 | ./enquire -f > float.h || echo ' *** Some problems: see float.h'\r | |
156 | echo "Verifying the contents of limits.h and float.h ..."\r | |
157 | echo " $CC" -DVERIFY $CFLAGS "$@" $0 -o verify $LIBS\r | |
158 | $CC -DVERIFY $CFLAGS ${@+"$@"} $0 -o verify $LIBS ||\r | |
159 | { echo '***' Failed; exit 1; }\r | |
160 | echo " verify -fl > verify.out"\r | |
161 | ./verify -fl > verify.out ||\r | |
162 | echo ' *** Some problems: see verify.out'\r | |
163 | echo Done\r | |
164 | exit 0\r | |
165 | #endif\r | |
166 | \r | |
167 | /*\r | |
168 | PURPOSE\r | |
169 | This is a program that determines many properties of the C\r | |
170 | compiler and machine that it is run on, such as minimum and\r | |
171 | maximum [un]signed char/int/long, many properties of float/ [long]\r | |
172 | double, and so on.\r | |
173 | \r | |
174 | As an option it produces the ANSI C float.h and limits.h files.\r | |
175 | \r | |
176 | As a further option, it even checks that the compiler reads the\r | |
177 | header files correctly.\r | |
178 | \r | |
179 | It is a good test-case for compilers, since it exercises them with\r | |
180 | many limiting values, such as the minimum and maximum floating-point\r | |
181 | numbers.\r | |
182 | \r | |
183 | COMPILING AND RUNNING ON UNIX MACHINES\r | |
184 | With luck and a following wind, on Unix systems just the following\r | |
185 | will work:\r | |
186 | sh enquire.c (or whatever filename you chose).\r | |
187 | Any parameters are passed to the C compiler, so if the compilation\r | |
188 | fails for any reason curable as explained below, you can do the following:\r | |
189 | sh enquire.c -DBAD_CPP\r | |
190 | \r | |
191 | If you do get compilation errors, check the line in question.\r | |
192 | Very often there is a comment attached saying which define to set.\r | |
193 | \r | |
194 | You can use a different C compiler than the default cc by setting CC:\r | |
195 | CC=gcc sh enquire.c -ansi\r | |
196 | You can load extra libraries by setting LIBS:\r | |
197 | CC=gcc LIBS=-lflong sh enquire.c -ansi\r | |
198 | Add ID="string" for the string to be added to the output; for instance:\r | |
199 | ID="`hostname` cc -ansi" sh enquire.c -ansi\r | |
200 | \r | |
201 | Compiling may give messages about unreachable code. These you can ignore.\r | |
202 | \r | |
203 | Some compilers offer various flags for different floating point\r | |
204 | modes; it's worth trying all possible combinations of these.\r | |
205 | \r | |
206 | Don't say I haven't tried to make life easy for you...\r | |
207 | \r | |
208 | COMPILING AND RUNNING ON NON-UNIX SYSTEMS\r | |
209 | On non-Unix systems, you must say (the equivalent of):\r | |
210 | cc enquire.c -o enquire\r | |
211 | enquire > enquire.out\r | |
212 | enquire -l > limits.h\r | |
213 | enquire -f > float.h\r | |
214 | cc -DVERIFY enquire.c -o verify #this includes limits.h and float.h\r | |
215 | verify -fl > verify.out\r | |
216 | \r | |
217 | If your compiler doesn't support: add flag:\r | |
218 | signed char (eg pcc) -DNO_SC\r | |
219 | unsigned char -DNO_UC\r | |
220 | unsigned short and long -DNO_UI\r | |
221 | void -DNO_VOID\r | |
222 | signal(), or setjmp/longjmp() -DNO_SIG\r | |
223 | \r | |
224 | Try to compile first with no flags, and see if you get any errors\r | |
225 | - you might be surprised. (Most non-ANSI compilers need -DNO_SC,\r | |
226 | though.) Some compilers need a -f flag for floating point.\r | |
227 | \r | |
228 | Don't use any optimisation flags: the program may not work if you\r | |
229 | do. Though "while (a+1.0-a-1.0 == 0.0)" may look like "while(1)"\r | |
230 | to an optimiser, to a floating-point unit there's a world of difference.\r | |
231 | \r | |
232 | Compiling may give messages about unreachable code. These you can ignore.\r | |
233 | \r | |
234 | Some compilers offer various flags for different floating point\r | |
235 | modes; it's worth trying all possible combinations of these.\r | |
236 | \r | |
237 | FAULTY COMPILERS\r | |
238 | Because of bugs and/or inadequacies, some compilers need the following\r | |
239 | defines:\r | |
240 | \r | |
241 | - If your C preprocessor doesn't have the predefined __FILE__\r | |
242 | macro, and you don't want to call this file enquire.c but, say,\r | |
243 | tell.c, add the flag -DFILENAME=\"tell.c\" .\r | |
244 | \r | |
245 | - Some compilers won't accept the line "#include FILENAME". Add\r | |
246 | flag -DBAD_CPP. In that case, this file *must* be called\r | |
247 | enquire.c.\r | |
248 | \r | |
249 | - Some compilers can't cope with "#ifdef __FILE__". Use\r | |
250 | -DFILENAME= or -DBAD_CPP as above.\r | |
251 | \r | |
252 | - Some naughty compilers define __STDC__, but don't really\r | |
253 | support it. Some define it as 0, in which case we ignore it.\r | |
254 | But if your compiler defines it, and isn't really ANSI C, add\r | |
255 | flag -DBAD_STDC. (To those compiler writers: for shame).\r | |
256 | \r | |
257 | - Some naughty compilers define __STDC__, but don't have the\r | |
258 | stddef.h include file. Add flag -DBAD_STDDEF. (Gcc needs this\r | |
259 | on some machines, due to clashes between stddef.h and other\r | |
260 | include files.)\r | |
261 | \r | |
262 | - Some systems crash when you try to malloc all store. To save\r | |
263 | users of such defective systems too much grief, they may\r | |
264 | compile with -DBAD_MALLOC, which ignores that bit of the code.\r | |
265 | \r | |
266 | Summary of naughty-compiler flags:\r | |
267 | If your compiler doesn't support: add flag:\r | |
268 | __FILE__ (and you changed the filename) -DFILENAME=\"name.c\"\r | |
269 | #ifdef __FILE__ -DBAD_CPP or -DFILENAME=...\r | |
270 | #include FILENAME -DBAD_CPP\r | |
271 | __STDC__ (properly) -DBAD_STDC\r | |
272 | stddef.h -DBAD_STDDEF\r | |
273 | malloc(LOTS) == NULL -DBAD_MALLOC\r | |
274 | \r | |
275 | While it is not our policy to support defective compilers, pity has been\r | |
276 | taken on people with compilers that can't produce object files bigger than\r | |
277 | 32k (especially since it was an easy addition). Compile the program\r | |
278 | into separate parts like this:\r | |
279 | cc -c -DSEP -DPASS0 -o p0.o <other flags> enquire.c\r | |
280 | cc -c -DSEP -DPASS1 -o p1.o <other flags> enquire.c\r | |
281 | cc -c -DSEP -DPASS2 -o p2.o <other flags> enquire.c\r | |
282 | cc -c -DSEP -DPASS3 -o p3.o <other flags> enquire.c\r | |
283 | cc -o enquire p0.o p1.o p2.o p3.o\r | |
284 | \r | |
285 | SYSTEM DEPENDENCIES\r | |
286 | You may possibly need to add some calls to signal() for other sorts of\r | |
287 | exception on your machine than SIGFPE, SIGOVER, SIGBUS, and SIGSEGV.\r | |
288 | See lines beginning #ifdef SIGxxx (and communicate the differences to me!).\r | |
289 | \r | |
290 | OUTPUT\r | |
291 | Running without argument gives the information as English text. If run\r | |
292 | with argument -l (e.g. enquire -l), output is a series of #define's for\r | |
293 | the ANSI standard limits.h include file, excluding MB_MAX_CHAR. If run\r | |
294 | with argument -f, output is a series of #define's for the ANSI standard\r | |
295 | float.h include file (according to ANSI C Draft of Dec 7, 1988).\r | |
296 | Flag -v gives verbose output: output includes the English text above\r | |
297 | as C comments. The program exit(0)'s if everything went ok, otherwise\r | |
298 | it exits with a positive number, telling how many problems there were.\r | |
299 | \r | |
300 | VERIFYING THE COMPILER\r | |
301 | If, having produced the float.h and limits.h header files, you want to\r | |
302 | verify that the compiler reads them back correctly (there are a lot of\r | |
303 | boundary cases, of course, like minimum and maximum numbers), you can\r | |
304 | recompile enquire.c with -DVERIFY set (plus the other flags that you used\r | |
305 | when compiling the version that produced the header files). This then\r | |
306 | recompiles the program so that it #includes "limits.h" and "float.h",\r | |
307 | and checks that the constants it finds there are the same as the\r | |
308 | constants it produces. Run the resulting program with enquire -fl.\r | |
309 | Many compilers fail this test.\r | |
310 | NB: You *must* recompile with the same compiler and flags, otherwise\r | |
311 | you may get odd results.\r | |
312 | \r | |
313 | You can also use this option if your compiler already has both files,\r | |
314 | and you want to confirm that this program produces the right results.\r | |
315 | \r | |
316 | TROUBLESHOOTING.\r | |
317 | This program is now quite trustworthy, and suspicious and wrong output\r | |
318 | may well be caused by bugs in the compiler, not in the program (however\r | |
319 | of course, this is not guaranteed, and no responsibility can be\r | |
320 | accepted, etc.)\r | |
321 | \r | |
322 | The program only works if overflows are ignored by the C system or\r | |
323 | are catchable with signal().\r | |
324 | \r | |
325 | If the program fails to run to completion (often with the error message\r | |
326 | "Unexpected signal at point x"), this often turns out to be a bug in the\r | |
327 | C compiler's run-time system. Check what was about to be printed, and\r | |
328 | try to narrow the problem down.\r | |
329 | \r | |
330 | Another possible problem is that you have compiled the program to produce\r | |
331 | loss-of-precision arithmetic traps. The program cannot cope with these,\r | |
332 | and you should re-compile without them. (They should never be the default).\r | |
333 | \r | |
334 | Make sure you compiled with optimisation turned off.\r | |
335 | \r | |
336 | Output preceded by *** WARNING: identifies behaviour of the C system\r | |
337 | deemed incorrect by the program. Likely problems are that printf or\r | |
338 | scanf don't cope properly with certain boundary numbers: this program\r | |
339 | goes to a lot of trouble to calculate its values, and these values\r | |
340 | are mostly boundary numbers. Experience has shown that often printf\r | |
341 | cannot cope with these values, and so in an attempt to increase\r | |
342 | confidence in the output, for each float and double that is printed,\r | |
343 | the printed value is checked by using sscanf to read it back.\r | |
344 | Care is taken that numbers are printed with enough digits to uniquely\r | |
345 | identify them, and therefore that they can be read back identically.\r | |
346 | If the number read back is different, then there is probably a bug in\r | |
347 | printf or sscanf, and the program prints the warning message.\r | |
348 | If the two numbers in the warning look identical, then printf is more\r | |
349 | than likely rounding the last digit(s) incorrectly. To put you at ease\r | |
350 | that the two really are different, the bit patterns of the two numbers\r | |
351 | are also printed. The difference is very likely in the last bit.\r | |
352 | Many scanf's read the minimum double back as 0.0, and similarly cause\r | |
353 | overflow when reading the maximum double. This program quite ruthlessly\r | |
354 | declares all these behaviours faulty. The point is that if you get\r | |
355 | one of these warnings, the output may be wrong, so you should check\r | |
356 | the result carefully if you intend to use the results. Of course, printf\r | |
357 | and sscanf may both be wrong, and cancel each other out, so you should\r | |
358 | check the output carefully anyway.\r | |
359 | \r | |
360 | The warning that "a cast didn't work" refers to cases like this:\r | |
361 | \r | |
362 | float f;\r | |
363 | #define C 1.234567890123456789\r | |
364 | f= C;\r | |
365 | if (f != (float) C) printf ("Wrong!");\r | |
366 | \r | |
367 | A faulty compiler will widen f to double and ignore the cast to float,\r | |
368 | and because there is more accuracy in a double than a float, fail to\r | |
369 | recognise that they are the same. In the actual case in point, f and C\r | |
370 | are passed as parameters to a function that discovers they are not equal,\r | |
371 | so it's just possible that the error was in the parameter passing,\r | |
372 | not in the cast (see function Verify()).\r | |
373 | For ANSI C, which has float constants, the error message is "constant has\r | |
374 | wrong precision".\r | |
375 | \r | |
376 | REPORTING PROBLEMS\r | |
377 | If the program doesn't work for you for any reason that can't be\r | |
378 | narrowed down to a problem in the C compiler, or it has to be\r | |
379 | changed in order to get it to compile, or it produces suspicious\r | |
380 | output (like a very low maximum float, for instance), please mail\r | |
381 | the problem and an example of the incorrect output to\r | |
382 | Steven.Pemberton@cwi.nl so that improvements can be worked into\r | |
383 | future versions. Try to give as much information as possible;\r | |
384 | DON'T FORGET TO MENTION THE VERSION NUMBER!\r | |
385 | \r | |
386 | The program tries to catch and diagnose bugs in the compiler/run-time\r | |
387 | system. I would be especially pleased to have reports of failures so\r | |
388 | that I can improve this service.\r | |
389 | \r | |
390 | I apologise unreservedly for the contorted use of the preprocessor...\r | |
391 | but it was fun!\r | |
392 | \r | |
393 | NEW VERSIONS\r | |
394 | Worried that you may not have the latest version? Ftp to\r | |
395 | ftp.cwi.nl, and look in directory pub/steven/enquire\r | |
396 | for file enquireXX.c; XX is the version number. Or look at\r | |
397 | http://www.cwi.nl/~steven/enquire.html\r | |
398 | \r | |
399 | HOW DOES ENQUIRE WORK?\r | |
400 | There is an article that explains a lot of the workings: The\r | |
401 | Ergonomics of Portability; available from the above addresses as file\r | |
402 | enquire.ps.\r | |
403 | \r | |
404 | THE SMALL PRINT\r | |
405 | This is not a public domain program; nor is any other program that\r | |
406 | carries a copyright notice. It is however freely copyable under the\r | |
407 | following conditions:\r | |
408 | \r | |
409 | You may copy and distribute verbatim copies of this source file.\r | |
410 | You may modify this source file, and copy and distribute such\r | |
411 | modified versions, provided that you leave the copyright notice\r | |
412 | at the top of the file and also cause the modified file to carry\r | |
413 | prominent notices stating that you changed the files and the\r | |
414 | date of any change; and cause the whole of any work that you\r | |
415 | distribute or publish, that in whole or in part contains or is a\r | |
416 | derivative of this program or any part thereof, to be licensed\r | |
417 | at no charge to all third parties on terms identical to those\r | |
418 | here.\r | |
419 | \r | |
420 | While every effort has been taken to make this program as reliable as\r | |
421 | possible, no responsibility can be taken for the correctness of the\r | |
422 | output, nor suitability for any particular use.\r | |
423 | \r | |
424 | If you do have a fix to any problem, please send it to me, so that\r | |
425 | other people can have the benefits.\r | |
426 | \r | |
427 | This program is an offshoot of a project funded by public funds.\r | |
428 | If you use this program for research or commercial use (i.e. more\r | |
429 | than just for the fun of knowing about your compiler) mailing a short\r | |
430 | note of acknowledgement may help keep enquire.c supported.\r | |
431 | \r | |
432 | ACKNOWLEDGEMENTS\r | |
433 | Many people have given time and ideas to making this program what it is.\r | |
434 | To all of them thanks, and apologies for not mentioning them by name.\r | |
435 | \r | |
436 | HISTORY\r | |
437 | Originally started as a program to generate configuration constants\r | |
438 | for a large piece of software we were writing, which later took on\r | |
439 | a life of its own...\r | |
440 | 1.0 Length 6658!; end 1984?\r | |
441 | Unix only. Only printed a dozen maximum int/double values.\r | |
442 | 2.0 Length 10535; Spring 1985\r | |
443 | Prints values as #defines (about 20 of them)\r | |
444 | More extensive floating point, using Cody and Waite\r | |
445 | Handles signals better\r | |
446 | Programs around optimisations\r | |
447 | Handles Cybers\r | |
448 | 3.0 Length 12648; Aug 1987; prints about 42 values\r | |
449 | Added PASS stuff, so treats float as well as double\r | |
450 | 4.0 Length 33891; Feb 1989; prints around 85 values\r | |
451 | First GNU version (for gcc, where they called it hard-params.c)\r | |
452 | Generates float.h and limits.h files\r | |
453 | Handles long double\r | |
454 | Generates warnings for dubious output\r | |
455 | 4.1 Length 47738; April 1989\r | |
456 | Added VERIFY and TEST\r | |
457 | 4.2 Length 63442; Feb 1990\r | |
458 | Added SEP\r | |
459 | Fixed eps/epsneg\r | |
460 | Added check for pseudo-unsigned chars\r | |
461 | Added description for each #define output\r | |
462 | Added check for absence of defines during verify\r | |
463 | Added prototypes\r | |
464 | Added BAD_STDC and BAD_CPP\r | |
465 | Fixed alignments output\r | |
466 | 4.3 Length 75000; Oct 1990; around 114 lines of output\r | |
467 | Function xmalloc defined, Richard Stallman, June 89.\r | |
468 | Alignments computed from member offsets rather than structure sizes,\r | |
469 | Richard Stallman, Oct 89\r | |
470 | Print whether char* and int* pointers have the same format;\r | |
471 | also char * and function *\r | |
472 | Update to Draft C version Dec 7, 1988\r | |
473 | - types of constants produced in limits.h\r | |
474 | (whether to put a U after unsigned shorts and chars and\r | |
475 | whether to output -1024 as (-1023-1))\r | |
476 | - values of SCHAR_MIN/MAX\r | |
477 | - values of *_EPSILON (not the smallest but the effective smallest)\r | |
478 | Added FILENAME, since ANSI C doesn't allow #define __FILE__\r | |
479 | Renamed from config.c to enquire.c\r | |
480 | Added size_t and ptrdiff_t enquiries\r | |
481 | Added promotion enquiries\r | |
482 | Added type checks of #defines\r | |
483 | Added BAD_STDDEF\r | |
484 | Changed endian to allow for cases where not all bits are used\r | |
485 | Sanity check for max integrals\r | |
486 | Fixed definition of setjmp for -DNO_SIG\r | |
487 | Moved #define ... 0.0L inside #ifdef STDC, in case some cpp's tokenize\r | |
488 | Added BAD_MALLOC\r | |
489 | 5.0 Length 88228; February 1993; around 120 lines of output\r | |
490 | (depends on what you count)\r | |
491 | Added the 'sh enquire.c' horror/delight: thanks David Mankins@think\r | |
492 | Added checks for long names: thanks Steve Simon@leeds-poly\r | |
493 | Added FPE signal checks: thanks Leonid A. Broukhis\r | |
494 | Added check for dereferencing NULL\r | |
495 | Added TESTI\r | |
496 | Added LIBS, fixed showtype: thanks Rainer Orth@TechFak.Uni-Bielefeld.DE\r | |
497 | Added a free(): thanks nickc@perihelion.co.uk\r | |
498 | Added signal catching to the malloc part\r | |
499 | Renamed naughty-compiler defines to BAD_*\r | |
500 | Renamed and altered Verify() to better check faulty compilers\r | |
501 | Shut some compilers up from giving incorrect warnings.\r | |
502 | Fixed sign_of(): thanks Hugh Redelmeier@redvax\r | |
503 | Fixed USHRT_MAX for sizeof(short)=sizeof(int) but INT_MAX > SHRT_MAX\r | |
504 | Fixed NO_UI\r | |
505 | Fixed -DSEP: thanks Mike Black@seismo\r | |
506 | Fixed the case where stdio.h includes limits.h: thanks rms@gnu\r | |
507 | Fixed exponent(): thanks Christophe BINOT\r | |
508 | <chb%hpvpta.france.hp.com@hplb.hpl.hp.com>\r | |
509 | 5.0a Aug 1997\r | |
510 | Made handling of ID= easier\r | |
511 | Improved the reporting of use of bits in Floating values.\r | |
512 | 5.1 Length 88739; Sep 1998\r | |
513 | Fixed detection of infinity for machines with no overflow trap\r | |
514 | Speeded up search for max char (first 32 bit char machine turned up...)\r | |
515 | 5.1a Length 88832; Feb 1999\r | |
516 | Changed identification message\r | |
517 | 5.1b Length 88926; Oct 2002\r | |
518 | Fixed a missing \n in an output line; thanks Leonid Broukhis again\r | |
519 | */\r | |
520 | \r | |
521 | /* Set FILENAME to the name of this file */\r | |
522 | #ifndef FILENAME\r | |
523 | #ifdef BAD_CPP\r | |
524 | #define FILENAME "enquire.c"\r | |
525 | #else\r | |
526 | #ifdef __FILE__ /* It's a compiler bug if this fails. Define BAD_CPP */\r | |
527 | #define FILENAME __FILE__\r | |
528 | #else\r | |
529 | #define FILENAME "enquire.c"\r | |
530 | #endif /* __FILE__ */\r | |
531 | #endif /* BAD_CPP */\r | |
532 | #endif /* FILENAME */\r | |
533 | \r | |
534 | /* This file is read three times (it #includes itself), to generate\r | |
535 | otherwise identical code for each of short+float, int+double,\r | |
536 | long+long double. If PASS isn't defined, then this is the first pass.\r | |
537 | Code bracketed by 'PASS0' is for stuff independent of all three,\r | |
538 | but is read during the first pass.\r | |
539 | */\r | |
540 | #ifndef PASS\r | |
541 | #ifdef SEP /* so we're only interested if this is pass 1 or not */\r | |
542 | #ifdef PASS1\r | |
543 | #define PASS 1\r | |
544 | #else\r | |
545 | #define PASS 0\r | |
546 | #endif\r | |
547 | #else /* no SEP, so this is the first pass */\r | |
548 | #define PASS 1\r | |
549 | #define PASS0 1\r | |
550 | #define PASS1 1\r | |
551 | #endif /* SEP */\r | |
552 | \r | |
553 | /* Void just marks the functions that don't return a result */\r | |
554 | #ifdef NO_VOID\r | |
555 | #define Void int\r | |
556 | #else\r | |
557 | #define Void void\r | |
558 | #endif\r | |
559 | \r | |
560 | /* Set STDC to whether this is *really* an ANSI C compiler.\r | |
561 | Some bad compilers define __STDC__, when they don't support it.\r | |
562 | Compile with -DBAD_STDC to get round this.\r | |
563 | */\r | |
564 | #ifndef BAD_STDC\r | |
565 | #ifdef __STDC__\r | |
566 | #if __STDC__ /* If __STDC__ is 0, assume it isn't supported */\r | |
567 | #define STDC\r | |
568 | #endif\r | |
569 | #endif\r | |
570 | #endif\r | |
571 | \r | |
572 | /* Stuff different for ANSI C, and old C:\r | |
573 | ARGS and NOARGS are used for function prototypes.\r | |
574 | Volatile is used to reduce the chance of optimisation,\r | |
575 | and to prevent variables being put in registers (when setjmp/longjmp\r | |
576 | wouldn't work as we want)\r | |
577 | Long_double is the longest floating point type available.\r | |
578 | stdc is used in tests like "if (stdc)", which is less ugly than #ifdef.\r | |
579 | U is output after unsigned constants.\r | |
580 | */\r | |
581 | #ifdef STDC\r | |
582 | \r | |
583 | #define ARGS(x) x\r | |
584 | #define NOARGS (void)\r | |
585 | #define Volatile volatile\r | |
586 | #define Long_double long double\r | |
587 | #define stdc 1\r | |
588 | #define U "U"\r | |
589 | \r | |
590 | #else /* Old style C */\r | |
591 | \r | |
592 | #define ARGS(x) ()\r | |
593 | #define NOARGS ()\r | |
594 | #define Volatile static\r | |
595 | #define Long_double double\r | |
596 | #define stdc 0\r | |
597 | #define U ""\r | |
598 | \r | |
599 | #endif /* STDC */\r | |
600 | \r | |
601 | /* include files */\r | |
602 | #include <stdio.h>\r | |
603 | #include <wchar.h>\r | |
604 | \r | |
605 | #ifdef STDC\r | |
606 | #ifndef BAD_STDDEF\r | |
607 | #include <stddef.h> /* for size_t: if this fails, define BAD_STDDEF */\r | |
608 | #endif\r | |
609 | #endif\r | |
610 | \r | |
611 | #ifdef NO_SIG\r | |
612 | #define jmp_buf int\r | |
613 | #else\r | |
614 | #include <signal.h> /* if this fails, define NO_SIG */\r | |
615 | #include <setjmp.h> /* if this fails, define NO_SIG */\r | |
616 | #endif\r | |
617 | //#ifndef NO_SIG\r | |
618 | //#include <signal.h> /* if this fails, define NO_SIG */\r | |
619 | //#include <setjmp.h> /* if this fails, define NO_SIG */\r | |
620 | //#endif\r | |
621 | \r | |
622 | /* Kludge around the possiblity that <stdio.h> includes <limits.h> */\r | |
623 | #ifdef CHAR_BIT\r | |
624 | #undef CHAR_BIT\r | |
625 | #undef CHAR_MAX\r | |
626 | #undef CHAR_MIN\r | |
627 | #undef SCHAR_MAX\r | |
628 | #undef SCHAR_MIN\r | |
629 | #undef UCHAR_MAX\r | |
630 | #undef UCHAR_MIN\r | |
631 | #endif\r | |
632 | \r | |
633 | #ifdef VERIFY\r | |
634 | #include "limits.h"\r | |
635 | #include "float.h"\r | |
636 | #endif\r | |
637 | \r | |
638 | /* The largest unsigned type */\r | |
639 | #ifdef NO_UI\r | |
640 | #define ulong unsigned int\r | |
641 | #else\r | |
642 | #define ulong unsigned long\r | |
643 | #endif\r | |
644 | \r | |
645 | /* Some shorthands */\r | |
646 | #define Vprintf if (V) printf\r | |
647 | #define Unexpected(place) if (setjmp(lab)!=0) croak(place)\r | |
648 | #define fabs(x) (((x)<0.0)?(-x):(x))\r | |
649 | \r | |
650 | #endif /* PASS */\r | |
651 | \r | |
652 | /* A description of the ANSI constants */\r | |
653 | #define D_CHAR_BIT "Number of bits in a storage unit"\r | |
654 | #define D_CHAR_MAX "Maximum char"\r | |
655 | #define D_CHAR_MIN "Minimum char"\r | |
656 | #define D_SCHAR_MAX "Maximum signed char"\r | |
657 | #define D_SCHAR_MIN "Minimum signed char"\r | |
658 | #define D_UCHAR_MAX "Maximum unsigned char (minimum is always 0)"\r | |
659 | \r | |
660 | #define D_INT_MAX "Maximum %s"\r | |
661 | #define D_INT_MIN "Minimum %s"\r | |
662 | #define D_UINT_MAX "Maximum unsigned %s (minimum is always 0)"\r | |
663 | \r | |
664 | #define D_FLT_ROUNDS "Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown"\r | |
665 | #define D_FLT_RADIX "Radix of exponent representation"\r | |
666 | #define D_MANT_DIG "Number of base-FLT_RADIX digits in the significand of a %s"\r | |
667 | #define D_DIG "Number of decimal digits of precision in a %s"\r | |
668 | #define D_MIN_EXP "Minimum int x such that FLT_RADIX**(x-1) is a normalised %s"\r | |
669 | #define D_MIN_10_EXP "Minimum int x such that 10**x is a normalised %s"\r | |
670 | #define D_MAX_EXP "Maximum int x such that FLT_RADIX**(x-1) is a representable %s"\r | |
671 | #define D_MAX_10_EXP "Maximum int x such that 10**x is a representable %s"\r | |
672 | #define D_MAX "Maximum %s"\r | |
673 | #define D_EPSILON "Difference between 1.0 and the minimum %s greater than 1.0"\r | |
674 | #define D_MIN "Minimum normalised %s"\r | |
675 | \r | |
676 | #ifdef PASS0\r | |
677 | \r | |
678 | /* Prototypes for what's to come: */\r | |
679 | \r | |
680 | int false NOARGS;\r | |
681 | \r | |
682 | #ifdef BAD_STDDEF\r | |
683 | char *malloc (); /* Old style prototype, since we don't know what size_t is */\r | |
684 | #else\r | |
685 | char *malloc ARGS((size_t size));\r | |
686 | #endif\r | |
687 | Void free ARGS((char *p)); /* Syntax error here? Try -DNO_VOID */\r | |
688 | \r | |
689 | Void exit ARGS((int status));\r | |
690 | \r | |
691 | char *f_rep ARGS((int precision, Long_double val));\r | |
692 | \r | |
693 | int maximum_int NOARGS;\r | |
694 | int cprop NOARGS;\r | |
695 | int basic NOARGS;\r | |
696 | Void sprop NOARGS;\r | |
697 | Void iprop NOARGS;\r | |
698 | Void lprop NOARGS;\r | |
699 | Void usprop NOARGS;\r | |
700 | Void uiprop NOARGS;\r | |
701 | Void ulprop NOARGS;\r | |
702 | int fprop ARGS((int byte_size));\r | |
703 | int dprop ARGS((int byte_size));\r | |
704 | int ldprop ARGS((int byte_size));\r | |
705 | Void efprop ARGS((int fprec, int dprec, int lprec));\r | |
706 | Void edprop ARGS((int fprec, int dprec, int lprec));\r | |
707 | Void eldprop ARGS((int fprec, int dprec, int lprec));\r | |
708 | \r | |
709 | int setmode ARGS((char *s));\r | |
710 | Void farewell ARGS((int bugs));\r | |
711 | Void describe ARGS((char *description, char *extra));\r | |
712 | Void missing ARGS((char *s));\r | |
713 | Void fmissing ARGS((char *s));\r | |
714 | Void check_defines NOARGS;\r | |
715 | Void bitpattern ARGS((char *p, unsigned int size));\r | |
716 | int ceil_log ARGS((int base, Long_double x));\r | |
717 | Void croak ARGS((int place));\r | |
718 | Void trap1 ARGS((int sig));\r | |
719 | Void eek_a_bug ARGS((char *problem));\r | |
720 | Void endian ARGS((int byte_size));\r | |
721 | int exponent ARGS((Long_double x, Long_double *fract, int *exp));\r | |
722 | int floor_log ARGS((int base, Long_double x));\r | |
723 | Void f_define ARGS((char *desc, char *extra, char *sort, char *name,\r | |
724 | int prec, Long_double val, char *mark));\r | |
725 | Void i_define ARGS((char *desc, char *extra, char *sort, char *name,\r | |
726 | long val, long lim, long req, char *mark));\r | |
727 | Void u_define ARGS((char *desc, char *extra, char *sort, char *name,\r | |
728 | ulong val, ulong req, char *mark));\r | |
729 | \r | |
730 | #ifdef NO_SIG /* There's no signal(), or setjmp/longjmp() */\r | |
731 | \r | |
732 | /* Dummy routines instead */\r | |
733 | typedef int jmp_buf;\r | |
734 | \r | |
735 | int setjmp ARGS((jmp_buf lab));\r | |
736 | \r | |
737 | jmp_buf lab, mlab;\r | |
738 | int setjmp(jmp_buf lab) { return(0); }\r | |
739 | void longjmp(jmp_buf lab, int val) { return; }\r | |
740 | \r | |
741 | Void signal(int i, void (*p)()) {}\r | |
742 | \r | |
743 | #else\r | |
744 | jmp_buf lab, mlab;\r | |
745 | Void overflow(int sig)\r | |
746 | { /* what to do on over/underflow */\r | |
747 | signal(sig, overflow);\r | |
748 | longjmp(lab, 1);\r | |
749 | }\r | |
750 | \r | |
751 | Void address(int sig)\r | |
752 | { /* what to do on an address error */\r | |
753 | signal(sig, address);\r | |
754 | longjmp(mlab, 1);\r | |
755 | }\r | |
756 | \r | |
757 | #endif /*NO_SIG*/\r | |
758 | \r | |
759 | int V= 0, /* verbose */\r | |
760 | L= 0, /* produce limits.h */\r | |
761 | F= 0, /* produce float.h */\r | |
762 | bugs=0; /* The number of (possible) bugs in the output */\r | |
763 | \r | |
764 | char co[4], oc[4]; /* Comment starter and ender symbols */\r | |
765 | \r | |
766 | int bits_per_byte; /* the number of bits per unit returned by sizeof() */\r | |
767 | int flt_rounds; /* The calculated value of FLT_ROUNDS */\r | |
768 | int flt_radix; /* The calculated value of FLT_RADIX */\r | |
769 | Volatile int trapped; /* For testing FPE traps */\r | |
770 | \r | |
771 | #ifdef TEST\r | |
772 | /* Set the fp modes on a SUN with 68881 chip, to check that different\r | |
773 | rounding modes etc. get properly detected.\r | |
774 | Compile with -f68881 for cc, -m68881 for gcc, and with additional flag\r | |
775 | -DTEST. Run with additional parameter +hex-number, to set the 68881 mode\r | |
776 | register to hex-number\r | |
777 | */\r | |
778 | \r | |
779 | /* Bits 0x30 = rounding mode */\r | |
780 | #define ROUND_BITS 0x30\r | |
781 | #define TO_NEAREST 0x00\r | |
782 | #define TO_ZERO 0x10\r | |
783 | #define TO_MINUS_INF 0x20\r | |
784 | #define TO_PLUS_INF 0x30 /* The SUN FP user's guide seems to be wrong here */\r | |
785 | \r | |
786 | /* Bits 0xc0 = extended rounding */\r | |
787 | #define EXT_BITS 0xc0\r | |
788 | #define ROUND_EXTENDED 0x00\r | |
789 | #define ROUND_SINGLE 0x40\r | |
790 | #define ROUND_DOUBLE 0x80\r | |
791 | \r | |
792 | /* Enabled traps */\r | |
793 | #define EXE_INEX1 0x100\r | |
794 | #define EXE_INEX2 0x200\r | |
795 | #define EXE_DZ 0x400\r | |
796 | #define EXE_UNFL 0x800\r | |
797 | #define EXE_OVFL 0x1000\r | |
798 | #define EXE_OPERR 0x2000\r | |
799 | #define EXE_SNAN 0x4000\r | |
800 | #define EXE_BSUN 0x8000\r | |
801 | \r | |
802 | /* Only used for testing, on a Sun with 68881 chip */\r | |
803 | /* Print the FP mode */\r | |
804 | printmode(new) unsigned new; {\r | |
805 | fpmode_(&new);\r | |
806 | printf("New fp mode:\n");\r | |
807 | printf(" Round toward ");\r | |
808 | switch (new & ROUND_BITS) {\r | |
809 | case TO_NEAREST: printf("nearest"); break;\r | |
810 | case TO_ZERO: printf("zero"); break;\r | |
811 | case TO_MINUS_INF: printf("minus infinity"); break;\r | |
812 | case TO_PLUS_INF: printf("plus infinity"); break;\r | |
813 | default: printf("???"); break;\r | |
814 | }\r | |
815 | \r | |
816 | printf("\n Extended rounding precision: ");\r | |
817 | \r | |
818 | switch (new & EXT_BITS) {\r | |
819 | case ROUND_EXTENDED: printf("extended"); break;\r | |
820 | case ROUND_SINGLE: printf("single"); break;\r | |
821 | case ROUND_DOUBLE: printf("double"); break;\r | |
822 | default: printf("???"); break;\r | |
823 | }\r | |
824 | \r | |
825 | printf("\n Enabled exceptions:");\r | |
826 | if (new & (unsigned) EXE_INEX1) printf(" inex1");\r | |
827 | if (new & (unsigned) EXE_INEX2) printf(" inex2");\r | |
828 | if (new & (unsigned) EXE_DZ) printf(" divz");\r | |
829 | if (new & (unsigned) EXE_UNFL) printf(" unfl");\r | |
830 | if (new & (unsigned) EXE_OVFL) printf(" ovfl");\r | |
831 | if (new & (unsigned) EXE_OPERR) printf(" operr");\r | |
832 | if (new & (unsigned) EXE_SNAN) printf(" snan");\r | |
833 | if (new & (unsigned) EXE_BSUN) printf(" bsun");\r | |
834 | printf("\n");\r | |
835 | }\r | |
836 | \r | |
837 | /* Only used for testing, on a Sun with 68881 chip */\r | |
838 | /* Set the FP mode */\r | |
839 | int setmode(s) char *s; {\r | |
840 | unsigned mode=0, dig;\r | |
841 | char c;\r | |
842 | \r | |
843 | while (*s) {\r | |
844 | c= *s++;\r | |
845 | if (c>='0' && c<='9') dig= c-'0';\r | |
846 | else if (c>='a' && c<='f') dig= c-'a'+10;\r | |
847 | else if (c>='A' && c<='F') dig= c-'A'+10;\r | |
848 | else return 1;\r | |
849 | mode= mode<<4 | dig;\r | |
850 | }\r | |
851 | printmode(mode);\r | |
852 | return 0;\r | |
853 | }\r | |
854 | #define SETMODE\r | |
855 | #endif\r | |
856 | \r | |
857 | #ifdef TESTI /* Test mode using SunOs IEEE routines */\r | |
858 | \r | |
859 | #include <sys/ieeefp.h>\r | |
860 | \r | |
861 | int setmode(char *s) {\r | |
862 | char *dummy, c, *cmd, *val;\r | |
863 | while (*s) {\r | |
864 | switch (c= *s++) {\r | |
865 | case '=': cmd= "direction"; val= "nearest"; break;\r | |
866 | case '0': cmd= "direction"; val= "tozero"; break;\r | |
867 | case '+': cmd= "direction"; val= "positive"; break;\r | |
868 | case '-': cmd= "direction"; val= "negative"; break;\r | |
869 | case '1': cmd= "precision"; val= "single"; break;\r | |
870 | case '2': cmd= "precision"; val= "double"; break;\r | |
871 | case '3': cmd= "precision"; val= "extended"; break;\r | |
872 | case '~': cmd= "exception"; val= "inexact"; break;\r | |
873 | case '/': cmd= "exception"; val= "division"; break;\r | |
874 | case '>': cmd= "exception"; val= "overflow"; break;\r | |
875 | case '<': cmd= "exception"; val= "underflow"; break;\r | |
876 | default:\r | |
877 | printf("Bad setmode character: %c\n", c);\r | |
878 | return 1;\r | |
879 | break;\r | |
880 | }\r | |
881 | printf("Set %s %s", cmd, val);\r | |
882 | if (ieee_flags("set", cmd, val, &dummy)) {\r | |
883 | printf(": failed\n");\r | |
884 | return 1;\r | |
885 | }\r | |
886 | printf("\n");\r | |
887 | }\r | |
888 | return 0;\r | |
889 | }\r | |
890 | #define SETMODE\r | |
891 | #endif\r | |
892 | \r | |
893 | #ifndef SETMODE\r | |
894 | /* ARGSUSED */\r | |
895 | int\r | |
896 | setmode(char *s)\r | |
897 | {\r | |
898 | fprintf(stderr, "Can't set mode: not compiled with TEST\n");\r | |
899 | return(1);\r | |
900 | }\r | |
901 | #endif\r | |
902 | \r | |
903 | int\r | |
904 | memeq(\r | |
905 | char *p1,\r | |
906 | int size1,\r | |
907 | char *p2,\r | |
908 | int size2\r | |
909 | )\r | |
910 | {\r | |
911 | /* See if two blocks of store are identical */\r | |
912 | int i;\r | |
913 | if (size1 != size2) return 0;\r | |
914 | for (i=1; i<=size1; i++) {\r | |
915 | if (*p1++ != *p2++) return 0;\r | |
916 | }\r | |
917 | return 1;\r | |
918 | }\r | |
919 | \r | |
920 | Void\r | |
921 | farewell(int bugs)\r | |
922 | {\r | |
923 | if (bugs == 0) exit(0);\r | |
924 | printf("\n%sFor hints on dealing with the ", co);\r | |
925 | if (bugs == 1) printf("problem");\r | |
926 | else printf("%d problems", bugs);\r | |
927 | printf(" above\n see the section 'TROUBLESHOOTING' in the file ");\r | |
928 | printf("%s%s\n", FILENAME, oc);\r | |
929 | exit(bugs);\r | |
930 | }\r | |
931 | \r | |
932 | /* The program has received a signal where it wasn't expecting one */\r | |
933 | Void\r | |
934 | croak(int place)\r | |
935 | {\r | |
936 | printf("*** Unexpected signal at point %d\n", place);\r | |
937 | farewell(bugs+1); /* An exit isn't essential here, but avoids loops */\r | |
938 | }\r | |
939 | \r | |
940 | /* This is here in case alloca.c is used, which calls this. */\r | |
941 | char *\r | |
942 | xmalloc(unsigned size)\r | |
943 | {\r | |
944 | char *value = malloc(size);\r | |
945 | if (value == 0) {\r | |
946 | fprintf(stderr, "Virtual memory exceeded\n");\r | |
947 | exit(bugs+1);\r | |
948 | }\r | |
949 | return value;\r | |
950 | }\r | |
951 | \r | |
952 | int maxint;\r | |
953 | \r | |
954 | int\r | |
955 | maximum_int( void )\r | |
956 | {\r | |
957 | /* Find the maximum integer */\r | |
958 | Volatile int newi, int_max, two=2;\r | |
959 | \r | |
960 | /* Calculate maxint ***********************************/\r | |
961 | /* Calculate 2**n-1 until overflow - then use the previous value */\r | |
962 | \r | |
963 | newi=1; int_max=0;\r | |
964 | \r | |
965 | if (setjmp(lab)==0) { /* Yields int_max */\r | |
966 | while(newi>int_max) {\r | |
967 | int_max=newi;\r | |
968 | newi=newi*two+1;\r | |
969 | }\r | |
970 | }\r | |
971 | Unexpected(0);\r | |
972 | return int_max;\r | |
973 | }\r | |
974 | \r | |
975 | /* How long are my identifiers? I could go further here, but some compilers\r | |
976 | have line length limits that I don't want to break.\r | |
977 | */\r | |
978 | \r | |
979 | int zzzzzzzzz1zzzzzzzzz2zzzzzzzzz3zzzzzzzzz4zzzzzzzzz5zzzzzzzzz6zzzz=64;\r | |
980 | \r | |
981 | int\r | |
982 | name_len( void )\r | |
983 | {\r | |
984 | int zzzzzzzzz1zzzzzzzzz2zzzzzzzzz3zz=32;\r | |
985 | { int zzzzzzzzz1zzzzzz=16;\r | |
986 | { int zzzzzzzz=8;\r | |
987 | { int zzzzzzz=7;\r | |
988 | { int zzzzzz=6;\r | |
989 | return\r | |
990 | zzzzzzzzz1zzzzzzzzz2zzzzzzzzz3zzzzzzzzz4zzzzzzzzz5zzzzzzzzz6zzzz;\r | |
991 | }\r | |
992 | }\r | |
993 | }\r | |
994 | }\r | |
995 | }\r | |
996 | \r | |
997 | #define aaaaaaaaa1aaaaaaaaa2aaaaaaaaa3aaaaaaaaa4aaaaaaaaa5aaaaaaaaa6aaaa 64\r | |
998 | #define LENGTH 64\r | |
999 | \r | |
1000 | #ifdef aaaaaaaaa1aaaaaaaaa2aaaaaaaaa3aa\r | |
1001 | #undef LENGTH\r | |
1002 | #define LENGTH 32\r | |
1003 | #endif\r | |
1004 | \r | |
1005 | #ifdef aaaaaaaaa1aaaaaa\r | |
1006 | #undef LENGTH\r | |
1007 | #define LENGTH 16\r | |
1008 | #endif\r | |
1009 | \r | |
1010 | #ifdef aaaaaaaa\r | |
1011 | #undef LENGTH\r | |
1012 | #define LENGTH 8\r | |
1013 | #endif\r | |
1014 | \r | |
1015 | #undef aaaaaaaaa1aaaaaaaaa2aaaaaaaaa3aaaaaaaaa4aaaaaaaaa5aaaaaaaaa6aaaa\r | |
1016 | \r | |
1017 | Void long_names()\r | |
1018 | {\r | |
1019 | int l= name_len();\r | |
1020 | Vprintf("Compiler names are at least %d chars long", l);\r | |
1021 | if (l != 64)\r | |
1022 | Vprintf(" (but less than %d)", l*2);\r | |
1023 | Vprintf("\n");\r | |
1024 | Vprintf("Preprocessor names are at least %d long", LENGTH);\r | |
1025 | if (LENGTH != 64)\r | |
1026 | Vprintf(" (but less than %d)", LENGTH*2);\r | |
1027 | Vprintf("\n\n");\r | |
1028 | }\r | |
1029 | \r | |
1030 | /* Used by FPROP to see if FP traps are generated, and if they may return */\r | |
1031 | \r | |
1032 | Void\r | |
1033 | trap2(int sig)\r | |
1034 | {\r | |
1035 | longjmp(lab, 1);\r | |
1036 | }\r | |
1037 | \r | |
1038 | Void\r | |
1039 | trap1(int sig)\r | |
1040 | {\r | |
1041 | trapped= 1; /* A global */\r | |
1042 | signal(sig, trap2);\r | |
1043 | }\r | |
1044 | \r | |
1045 | Void\r | |
1046 | setsignals( void )\r | |
1047 | {\r | |
1048 | #ifdef SIGFPE\r | |
1049 | signal(SIGFPE, overflow);\r | |
1050 | #endif\r | |
1051 | #ifdef SIGOVER\r | |
1052 | signal(SIGOVER, overflow);\r | |
1053 | #endif\r | |
1054 | #ifdef SIGBUS\r | |
1055 | signal(SIGBUS, address);\r | |
1056 | #endif\r | |
1057 | #ifdef SIGSEGV\r | |
1058 | signal(SIGSEGV, address);\r | |
1059 | #endif\r | |
1060 | /* Add more calls as necessary */\r | |
1061 | }\r | |
1062 | \r | |
1063 | #undef LENGTH\r | |
1064 | \r | |
1065 | int\r | |
1066 | main(int argc, char *argv[])\r | |
1067 | {\r | |
1068 | int dprec, fprec, lprec;\r | |
1069 | int i;\r | |
1070 | wchar_t *s;\r | |
1071 | int bad;\r | |
1072 | \r | |
1073 | setsignals();\r | |
1074 | Unexpected(1);\r | |
1075 | \r | |
1076 | bad=0;\r | |
1077 | for (i=1; i < argc; i++) {\r | |
1078 | s = (wchar_t *)(argv[i]);\r | |
1079 | if (*s == L'-') {\r | |
1080 | s++;\r | |
1081 | while (*s) {\r | |
1082 | switch (*(s++)) {\r | |
1083 | case L'v': V=1; break;\r | |
1084 | case L'l': L=1; break;\r | |
1085 | case L'f': F=1; break;\r | |
1086 | default: bad=1; break;\r | |
1087 | }\r | |
1088 | }\r | |
1089 | } else if (*s == L'+') {\r | |
1090 | s++;\r | |
1091 | bad = setmode((char *)s);\r | |
1092 | } else bad= 1;\r | |
1093 | }\r | |
1094 | if (bad) {\r | |
1095 | fprintf(stderr,\r | |
1096 | "Usage: %ls [-vlf]\n v=Verbose l=Limits.h f=Float.h\n",\r | |
1097 | (wchar_t *)(argv[0]));\r | |
1098 | exit(1);\r | |
1099 | }\r | |
1100 | if (L || F) {\r | |
1101 | co[0]= '/'; oc[0]= ' ';\r | |
1102 | co[1]= '*'; oc[1]= '*';\r | |
1103 | co[2]= ' '; oc[2]= '/';\r | |
1104 | co[3]= '\0'; oc[3]= '\0';\r | |
1105 | } else {\r | |
1106 | co[0]= '\0'; oc[0]= '\0';\r | |
1107 | V=1;\r | |
1108 | }\r | |
1109 | \r | |
1110 | if (L) printf("%slimits.h%s\n", co, oc);\r | |
1111 | if (F) printf("%sfloat.h%s\n", co, oc);\r | |
1112 | #ifdef ID\r | |
1113 | printf("%sProduced by enquire version %s (%s), CWI, Amsterdam\n %s\n",\r | |
1114 | co, VERSION, ID, WEB, oc);\r | |
1115 | #else\r | |
1116 | printf("%sProduced by enquire version %s, CWI, Amsterdam\n %s %s\n",\r | |
1117 | co, VERSION, WEB, oc);\r | |
1118 | #endif\r | |
1119 | \r | |
1120 | #ifdef VERIFY\r | |
1121 | printf("%sVerification phase%s\n", co, oc);\r | |
1122 | #endif\r | |
1123 | \r | |
1124 | #ifdef NO_SIG\r | |
1125 | Vprintf("%sCompiled without signal(): %s%s\n",\r | |
1126 | co,\r | |
1127 | "there's nothing that can be done if overflow occurs",\r | |
1128 | oc);\r | |
1129 | #endif\r | |
1130 | #ifdef NO_SC\r | |
1131 | Vprintf("%sCompiled without signed char%s\n", co, oc);\r | |
1132 | #endif\r | |
1133 | #ifdef NO_UC\r | |
1134 | Vprintf("%sCompiled without unsigned char%s\n", co, oc);\r | |
1135 | #endif\r | |
1136 | #ifdef NO_UI\r | |
1137 | Vprintf("%sCompiled without unsigned short or long%s\n", co, oc);\r | |
1138 | #endif\r | |
1139 | #ifdef __STDC__\r | |
1140 | Vprintf("%sCompiler claims to be ANSI C level %d%s\n",\r | |
1141 | co, __STDC__, oc);\r | |
1142 | #else\r | |
1143 | Vprintf("%sCompiler does not claim to be ANSI C%s\n", co, oc);\r | |
1144 | #endif\r | |
1145 | printf("\n");\r | |
1146 | \r | |
1147 | long_names();\r | |
1148 | check_defines();\r | |
1149 | \r | |
1150 | maxint= maximum_int();\r | |
1151 | bits_per_byte= basic();\r | |
1152 | Vprintf("\n");\r | |
1153 | if (F||V) {\r | |
1154 | fprec= fprop(bits_per_byte);\r | |
1155 | dprec= dprop(bits_per_byte);\r | |
1156 | lprec= ldprop(bits_per_byte);\r | |
1157 | efprop(fprec, dprec, lprec);\r | |
1158 | edprop(fprec, dprec, lprec);\r | |
1159 | eldprop(fprec, dprec, lprec);\r | |
1160 | }\r | |
1161 | #ifndef BAD_MALLOC\r | |
1162 | if (V) {\r | |
1163 | /* An extra goody: the approximate amount of data-space */\r | |
1164 | /* Allocate store until no more available */\r | |
1165 | /* Different implementations have a different argument type\r | |
1166 | to malloc. Here we assume that it's the same type as\r | |
1167 | that which sizeof() returns */\r | |
1168 | unsigned int size;\r | |
1169 | Volatile long total;\r | |
1170 | char kmg, *ptr, *save;\r | |
1171 | char **link;\r | |
1172 | \r | |
1173 | save= NULL;\r | |
1174 | size=maximum_int()/4;\r | |
1175 | total=0;\r | |
1176 | while (size!=0) {\r | |
1177 | if (setjmp(mlab) == 0) {\r | |
1178 | while ((ptr= malloc((false()?sizeof(int):size))) != (char *)NULL) {\r | |
1179 | //if (save == NULL) save= ptr; /* save the biggest chunk */\r | |
1180 | link = (char **)ptr;\r | |
1181 | if (save == NULL) {\r | |
1182 | // Save pointer to first allocated chunk\r | |
1183 | save= ptr;\r | |
1184 | *link = NULL;\r | |
1185 | }\r | |
1186 | else {\r | |
1187 | // Build list of all subsequently allocated chunks, LIFO\r | |
1188 | *link = save;\r | |
1189 | save = ptr;\r | |
1190 | }\r | |
1191 | total+=(size/2);\r | |
1192 | }\r | |
1193 | } else {\r | |
1194 | eek_a_bug("Trying to malloc all store generates a trap");\r | |
1195 | }\r | |
1196 | size/=2;\r | |
1197 | }\r | |
1198 | if (setjmp(mlab)!=0) croak(-1);\r | |
1199 | \r | |
1200 | //if (save != NULL) free(save);\r | |
1201 | while(save != NULL) {\r | |
1202 | link = (char **)save;\r | |
1203 | ptr = *link;\r | |
1204 | free(save);\r | |
1205 | save = ptr;\r | |
1206 | }\r | |
1207 | \r | |
1208 | total= (total+511)/512; /* Sic */ kmg= 'K';\r | |
1209 | if (total > 10000) {\r | |
1210 | total= (total+999)/1000; kmg= 'M';\r | |
1211 | }\r | |
1212 | if (total > 10000) {\r | |
1213 | total= (total+999)/1000; kmg= 'G';\r | |
1214 | }\r | |
1215 | if (total > 10000) {\r | |
1216 | total= (total+999)/1000; kmg= 'T';\r | |
1217 | }\r | |
1218 | Vprintf("%sMemory mallocatable ~= %ld %cbytes%s\n",\r | |
1219 | co, total, kmg, oc);\r | |
1220 | }\r | |
1221 | #endif\r | |
1222 | farewell(bugs);\r | |
1223 | return bugs; /* To keep compilers and lint happy */\r | |
1224 | }\r | |
1225 | \r | |
1226 | Void\r | |
1227 | eek_a_bug(char *problem)\r | |
1228 | {\r | |
1229 | /* The program has discovered a problem */\r | |
1230 | printf("\n%s*** WARNING: %s%s\n", co, problem, oc);\r | |
1231 | bugs++;\r | |
1232 | }\r | |
1233 | \r | |
1234 | Void\r | |
1235 | describe(char *description, char *extra)\r | |
1236 | {\r | |
1237 | /* Produce the description for a #define */\r | |
1238 | printf(" %s", co);\r | |
1239 | printf(description, extra);\r | |
1240 | printf("%s\n", oc);\r | |
1241 | }\r | |
1242 | \r | |
1243 | Void\r | |
1244 | i_define(\r | |
1245 | char *desc,\r | |
1246 | char *extra,\r | |
1247 | char *sort,\r | |
1248 | char *name,\r | |
1249 | long val,\r | |
1250 | long lim,\r | |
1251 | long req,\r | |
1252 | char *mark\r | |
1253 | )\r | |
1254 | {\r | |
1255 | /* Produce a #define for a signed int type */\r | |
1256 | describe(desc, extra);\r | |
1257 | if (val >= 0) {\r | |
1258 | printf("#define %s%s %ld%s\n", sort, name, val, mark);\r | |
1259 | } else if (val + lim < 0) {\r | |
1260 | /* We may not produce a constant like -1024 if the max\r | |
1261 | allowable value is 1023. It has then to be output as\r | |
1262 | -1023-1. lim is the max allowable value. */\r | |
1263 | printf("#define %s%s (%ld%s%ld%s)\n",\r | |
1264 | sort, name, -lim, mark, val+lim, mark);\r | |
1265 | } else {\r | |
1266 | printf("#define %s%s (%ld%s)\n", sort, name, val, mark);\r | |
1267 | }\r | |
1268 | /* If VERIFY is not set, val and req are just the same value;\r | |
1269 | if it is set, val is the value as calculated, and req is\r | |
1270 | the #defined constant\r | |
1271 | */\r | |
1272 | if (val != req) {\r | |
1273 | printf("%s*** Verify failed for above #define!\n", co);\r | |
1274 | printf(" Compiler has %ld for value%s\n\n", req, oc);\r | |
1275 | bugs++;\r | |
1276 | }\r | |
1277 | Vprintf("\n");\r | |
1278 | }\r | |
1279 | \r | |
1280 | Void\r | |
1281 | u_define(\r | |
1282 | char *desc,\r | |
1283 | char *extra,\r | |
1284 | char *sort,\r | |
1285 | char *name,\r | |
1286 | ulong val,\r | |
1287 | ulong req,\r | |
1288 | char *mark\r | |
1289 | )\r | |
1290 | {\r | |
1291 | /* Produce a #define for an unsigned value */\r | |
1292 | describe(desc, extra);\r | |
1293 | printf("#define %s%s %lu%s%s\n", sort, name, val, U, mark);\r | |
1294 | if (val != req) {\r | |
1295 | printf("%s*** Verify failed for above #define!\n", co);\r | |
1296 | printf(" Compiler has %lu for value%s\n\n", req, oc);\r | |
1297 | bugs++;\r | |
1298 | }\r | |
1299 | Vprintf("\n");\r | |
1300 | }\r | |
1301 | \r | |
1302 | Void f_define(\r | |
1303 | char *desc,\r | |
1304 | char *extra,\r | |
1305 | char *sort,\r | |
1306 | char *name,\r | |
1307 | int precision,\r | |
1308 | Long_double val,\r | |
1309 | char *mark\r | |
1310 | )\r | |
1311 | {\r | |
1312 | /* Produce a #define for a float/double/long double */\r | |
1313 | describe(desc, extra);\r | |
1314 | if (stdc) {\r | |
1315 | printf("#define %s%s %s%s\n",\r | |
1316 | sort, name, f_rep(precision, val), mark);\r | |
1317 | } else if (*mark == 'F') {\r | |
1318 | /* non-ANSI C has no float constants, so cast the constant */\r | |
1319 | printf("#define %s%s ((float)%s)\n",\r | |
1320 | sort, name, f_rep(precision, val));\r | |
1321 | } else {\r | |
1322 | printf("#define %s%s %s\n", sort, name, f_rep(precision, val));\r | |
1323 | }\r | |
1324 | Vprintf("\n");\r | |
1325 | }\r | |
1326 | \r | |
1327 | int\r | |
1328 | floor_log(int base, Long_double x)\r | |
1329 | {\r | |
1330 | /* return floor(log base(x)) */\r | |
1331 | int r=0;\r | |
1332 | while (x>=base) { r++; x/=base; }\r | |
1333 | return r;\r | |
1334 | }\r | |
1335 | \r | |
1336 | int\r | |
1337 | ceil_log(int base, Long_double x)\r | |
1338 | {\r | |
1339 | int r=0;\r | |
1340 | while (x>1.0) { r++; x/=base; }\r | |
1341 | return r;\r | |
1342 | }\r | |
1343 | \r | |
1344 | int\r | |
1345 | exponent(Long_double x, Long_double *fract, int *exp)\r | |
1346 | {\r | |
1347 | /* Split x into a fraction and a power of ten;\r | |
1348 | returns 0 if x is unusable, 1 otherwise.\r | |
1349 | Only used for error messages about faulty output.\r | |
1350 | */\r | |
1351 | int r=0, neg=0;\r | |
1352 | Long_double old;\r | |
1353 | *fract=0.0; *exp=0;\r | |
1354 | if (x<0.0) {\r | |
1355 | x= -x;\r | |
1356 | neg= 1;\r | |
1357 | }\r | |
1358 | if (x==0.0) return 1;\r | |
1359 | if (x>=10.0) {\r | |
1360 | while (x>=10.0) {\r | |
1361 | old=x; r++; x/=10.0;\r | |
1362 | if (old==x) return 0;\r | |
1363 | }\r | |
1364 | } else {\r | |
1365 | while (x<1.0) {\r | |
1366 | old=x; r--; x*=10.0;\r | |
1367 | if (old==x) return 0;\r | |
1368 | }\r | |
1369 | }\r | |
1370 | if (neg) *fract= -x;\r | |
1371 | else *fract= x;\r | |
1372 | *exp=r;\r | |
1373 | return 1;\r | |
1374 | }\r | |
1375 | \r | |
1376 | char *\r | |
1377 | f_rep(int precision, Long_double val)\r | |
1378 | {\r | |
1379 | /* Return the floating representation of val */\r | |
1380 | static char buf[1024];\r | |
1381 | char *f1;\r | |
1382 | if (sizeof(double) == sizeof(Long_double)) {\r | |
1383 | /* Assume they're the same, and use non-stdc format */\r | |
1384 | /* This is for stdc compilers using non-stdc libraries */\r | |
1385 | f1= "%.*e";\r | |
1386 | } else {\r | |
1387 | /* It had better support Le then */\r | |
1388 | f1= "%.*Le";\r | |
1389 | }\r | |
1390 | sprintf(buf, f1, precision, val);\r | |
1391 | return buf;\r | |
1392 | }\r | |
1393 | \r | |
1394 | Void\r | |
1395 | bitpattern(char *p, unsigned int size)\r | |
1396 | {\r | |
1397 | /* Printf the bit-pattern of p */\r | |
1398 | char c;\r | |
1399 | unsigned int i;\r | |
1400 | int j;\r | |
1401 | \r | |
1402 | for (i=1; i<=size; i++) {\r | |
1403 | c= *p;\r | |
1404 | p++;\r | |
1405 | for (j=bits_per_byte-1; j>=0; j--)\r | |
1406 | printf("%c", (c>>j)&1 ? '1' : '0');\r | |
1407 | if (i!=size) printf(" ");\r | |
1408 | }\r | |
1409 | }\r | |
1410 | \r | |
1411 | Void\r | |
1412 | fill(char *p, int size)\r | |
1413 | {\r | |
1414 | char *ab= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";\r | |
1415 | int i;\r | |
1416 | \r | |
1417 | for (i=0; i<size; i++)\r | |
1418 | p[i]= ab[i];\r | |
1419 | }\r | |
1420 | \r | |
1421 | #define Order(x, mode)\\r | |
1422 | printf("%s%s ", co, mode); fill((char *)&x, sizeof(x)); \\r | |
1423 | for (i=1; i<=sizeof(x); i++) { c=((x>>(byte_size*(sizeof(x)-i)))&mask);\\r | |
1424 | putchar(c==0 ? '?' : (char)c); }\\r | |
1425 | printf("%s\n", oc);\r | |
1426 | \r | |
1427 | Void\r | |
1428 | endian(int byte_size)\r | |
1429 | {\r | |
1430 | /* Printf the byte-order used on this machine */\r | |
1431 | /*unsigned*/ short s=0;\r | |
1432 | /*unsigned*/ int j=0;\r | |
1433 | /*unsigned*/ long l=0;\r | |
1434 | \r | |
1435 | unsigned int mask, i, c;\r | |
1436 | \r | |
1437 | mask=0;\r | |
1438 | for (i=1; i<=(unsigned)byte_size; i++) mask= (mask<<1)|1;\r | |
1439 | \r | |
1440 | if (V) {\r | |
1441 | printf("%sCHARACTER ORDER%s\n", co, oc);\r | |
1442 | Order(s, "short:");\r | |
1443 | Order(j, "int: ");\r | |
1444 | Order(l, "long: ");\r | |
1445 | }\r | |
1446 | }\r | |
1447 | \r | |
1448 | Void\r | |
1449 | missing(char *s)\r | |
1450 | {\r | |
1451 | printf("%s*** #define %s missing from limits.h%s\n", co, s, oc);\r | |
1452 | bugs++;\r | |
1453 | }\r | |
1454 | \r | |
1455 | Void\r | |
1456 | fmissing(char *s)\r | |
1457 | {\r | |
1458 | printf("%s*** #define %s missing from float.h%s\n", co, s, oc);\r | |
1459 | bugs++;\r | |
1460 | }\r | |
1461 | \r | |
1462 | /* To try and fool optimisers */\r | |
1463 | int false( void ) { return 0; }\r | |
1464 | \r | |
1465 | #define Promoted(x) (false()?(x):(-1))\r | |
1466 | #define is_signed(x) (Promoted(x) < 0)\r | |
1467 | #define sign_of(x) (is_signed(x)?"signed":"unsigned")\r | |
1468 | #define Signed 1\r | |
1469 | #define Unsigned 0\r | |
1470 | #define sgn(x) ((is_signed(x))?Signed:Unsigned)\r | |
1471 | \r | |
1472 | #define showtype(t, x) Vprintf("%s%s %s %s%s\n", co, t, sign_of(x), type_of((int)sizeof(x)), oc)\r | |
1473 | \r | |
1474 | char *type_of(int x)\r | |
1475 | {\r | |
1476 | if (x == sizeof(char)) {\r | |
1477 | if (sizeof(char) == sizeof(int)) return "char/short/int";\r | |
1478 | if (sizeof(char) == sizeof(short)) return "char/short";\r | |
1479 | return "char";\r | |
1480 | }\r | |
1481 | if (x == sizeof(short)) {\r | |
1482 | if (sizeof(short) == sizeof(int)) return "short/int";\r | |
1483 | return "short";\r | |
1484 | }\r | |
1485 | if (x == sizeof(int)) {\r | |
1486 | if (sizeof(int) == sizeof(long)) return "int/long";\r | |
1487 | return "int";\r | |
1488 | }\r | |
1489 | if (x == sizeof(long)) return "long";\r | |
1490 | return "unknown-type";\r | |
1491 | }\r | |
1492 | \r | |
1493 | char *ftype_of(int x)\r | |
1494 | {\r | |
1495 | if (x == sizeof(float)) {\r | |
1496 | return "float";\r | |
1497 | }\r | |
1498 | if (x == sizeof(double)) {\r | |
1499 | if (sizeof(double) == sizeof(Long_double))\r | |
1500 | return "(long)double";\r | |
1501 | return "double";\r | |
1502 | }\r | |
1503 | if (x == sizeof(Long_double)) {\r | |
1504 | return "long double";\r | |
1505 | }\r | |
1506 | return "unknown-type";\r | |
1507 | }\r | |
1508 | \r | |
1509 | Void typerr(char *name, int esign, int esize, int sign, int size)\r | |
1510 | {\r | |
1511 | Vprintf("*** %s has wrong type: expected %s %s, found %s %s\n",\r | |
1512 | name, sign_of(esign), type_of(esize),\r | |
1513 | sign_of(sign), type_of(size));\r | |
1514 | }\r | |
1515 | \r | |
1516 | Void ftyperr(char *name, int esize, int size)\r | |
1517 | {\r | |
1518 | Vprintf("*** %s has wrong type: expected %s, found %s\n",\r | |
1519 | name, ftype_of(esize), ftype_of(size));\r | |
1520 | }\r | |
1521 | \r | |
1522 | Void promotions( void )\r | |
1523 | {\r | |
1524 | int si; long sl;\r | |
1525 | unsigned int ui;\r | |
1526 | short ss;\r | |
1527 | \r | |
1528 | #ifndef NO_UI\r | |
1529 | unsigned long ul; /* if this fails, define NO_UI */\r | |
1530 | unsigned short us; /* if this fails, define NO_UI */\r | |
1531 | \r | |
1532 | ul=0; us=0;\r | |
1533 | #endif\r | |
1534 | /* Shut compiler warnings up: */\r | |
1535 | si=0; sl=0; ui=0; ss=0;\r | |
1536 | \r | |
1537 | Vprintf("\n%sPROMOTIONS%s\n", co, oc);\r | |
1538 | \r | |
1539 | /* Sanity checks. Possible warnings here; should be no problem */\r | |
1540 | if (is_signed(ui))\r | |
1541 | eek_a_bug("unsigned int promotes to signed!\n");\r | |
1542 | if (!is_signed(si))\r | |
1543 | eek_a_bug("signed int promotes to unsigned!\n");\r | |
1544 | if (!is_signed(sl))\r | |
1545 | eek_a_bug("signed long promotes to unsigned!\n");\r | |
1546 | if (sizeof(Promoted(si)) != sizeof(int))\r | |
1547 | eek_a_bug("int doesn't promote to int!\n");\r | |
1548 | if (sizeof(Promoted(sl)) != sizeof(long))\r | |
1549 | eek_a_bug("long doesn't promote to long!\n");\r | |
1550 | if (sizeof(Promoted(ss)) != sizeof(int))\r | |
1551 | eek_a_bug("short doesn't promote to int!\n");\r | |
1552 | if (sizeof(Promoted(ui)) != sizeof(int))\r | |
1553 | eek_a_bug("unsigned int doesn't promote to int!\n");\r | |
1554 | #ifndef NO_UI\r | |
1555 | if (sizeof(Promoted(ul)) != sizeof(long))\r | |
1556 | eek_a_bug("unsigned long doesn't promote to long!\n");\r | |
1557 | if (is_signed(ul))\r | |
1558 | eek_a_bug("unsigned long promotes to signed!\n");\r | |
1559 | #endif\r | |
1560 | \r | |
1561 | #ifndef NO_UI\r | |
1562 | showtype("unsigned short promotes to", Promoted(us));\r | |
1563 | #endif\r | |
1564 | showtype("long+unsigned gives", sl+ui);\r | |
1565 | }\r | |
1566 | \r | |
1567 | #define checktype(x, n, s, t) if((sgn(x)!=s)||(sizeof(x)!=sizeof(t))) typerr(n, s, (int)sizeof(t), sgn(x), (int)sizeof(x));\r | |
1568 | \r | |
1569 | #define fchecktype(x, n, t) if (sizeof(x) != sizeof(t)) ftyperr(n, (int)sizeof(x), (int)sizeof(t));\r | |
1570 | \r | |
1571 | Void check_defines( void )\r | |
1572 | {\r | |
1573 | /* ensure that all #defines are present and have the correct type */\r | |
1574 | #ifdef VERIFY\r | |
1575 | int usign;\r | |
1576 | \r | |
1577 | #ifdef NO_UI\r | |
1578 | usign= Signed;\r | |
1579 | #else\r | |
1580 | /* Implementations promote unsigned short differently */\r | |
1581 | usign= is_signed((unsigned short)0);\r | |
1582 | #endif\r | |
1583 | \r | |
1584 | if (L) {\r | |
1585 | #ifdef CHAR_BIT\r | |
1586 | checktype(CHAR_BIT, "CHAR_BIT", Signed, int);\r | |
1587 | #else\r | |
1588 | missing("CHAR_BIT");\r | |
1589 | #endif\r | |
1590 | #ifdef CHAR_MAX\r | |
1591 | checktype(CHAR_MAX, "CHAR_MAX", Signed, int);\r | |
1592 | #else\r | |
1593 | missing("CHAR_MAX");\r | |
1594 | #endif\r | |
1595 | #ifdef CHAR_MIN\r | |
1596 | checktype(CHAR_MIN, "CHAR_MIN", Signed, int);\r | |
1597 | #else\r | |
1598 | missing("CHAR_MIN");\r | |
1599 | #endif\r | |
1600 | #ifdef SCHAR_MAX\r | |
1601 | checktype(SCHAR_MAX, "SCHAR_MAX", Signed, int);\r | |
1602 | #else\r | |
1603 | missing("SCHAR_MAX");\r | |
1604 | #endif\r | |
1605 | #ifdef SCHAR_MIN\r | |
1606 | checktype(SCHAR_MIN, "SCHAR_MIN", Signed, int);\r | |
1607 | #else\r | |
1608 | missing("SCHAR_MIN");\r | |
1609 | #endif\r | |
1610 | #ifdef UCHAR_MAX\r | |
1611 | checktype(UCHAR_MAX, "UCHAR_MAX", Signed, int);\r | |
1612 | #else\r | |
1613 | missing("UCHAR_MAX");\r | |
1614 | #endif\r | |
1615 | #ifdef SHRT_MAX\r | |
1616 | checktype(SHRT_MAX, "SHRT_MAX", Signed, int);\r | |
1617 | #else\r | |
1618 | missing("SHRT_MAX");\r | |
1619 | #endif\r | |
1620 | #ifdef SHRT_MIN\r | |
1621 | checktype(SHRT_MIN, "SHRT_MIN", Signed, int);\r | |
1622 | #else\r | |
1623 | missing("SHRT_MIN");\r | |
1624 | #endif\r | |
1625 | #ifdef INT_MAX\r | |
1626 | checktype(INT_MAX, "INT_MAX", Signed, int);\r | |
1627 | #else\r | |
1628 | missing("INT_MAX");\r | |
1629 | #endif\r | |
1630 | #ifdef INT_MIN\r | |
1631 | checktype(INT_MIN, "INT_MIN", Signed, int);\r | |
1632 | #else\r | |
1633 | missing("INT_MIN");\r | |
1634 | #endif\r | |
1635 | #ifdef LONG_MAX\r | |
1636 | checktype(LONG_MAX, "LONG_MAX", Signed, long);\r | |
1637 | #else\r | |
1638 | missing("LONG_MAX");\r | |
1639 | #endif\r | |
1640 | #ifdef LONG_MIN\r | |
1641 | checktype(LONG_MIN, "LONG_MIN", Signed, long);\r | |
1642 | #else\r | |
1643 | missing("LONG_MIN");\r | |
1644 | #endif\r | |
1645 | #ifdef USHRT_MAX\r | |
1646 | checktype(USHRT_MAX, "USHRT_MAX", usign, int);\r | |
1647 | #else\r | |
1648 | missing("USHRT_MAX");\r | |
1649 | #endif\r | |
1650 | #ifdef UINT_MAX\r | |
1651 | checktype(UINT_MAX, "UINT_MAX", Unsigned, int);\r | |
1652 | #else\r | |
1653 | missing("UINT_MAX");\r | |
1654 | #endif\r | |
1655 | #ifdef ULONG_MAX\r | |
1656 | checktype(ULONG_MAX, "ULONG_MAX", Unsigned, long);\r | |
1657 | #else\r | |
1658 | missing("ULONG_MAX");\r | |
1659 | #endif\r | |
1660 | } /* if (L) */\r | |
1661 | \r | |
1662 | if (F) {\r | |
1663 | #ifdef FLT_RADIX\r | |
1664 | checktype(FLT_RADIX, "FLT_RADIX", Signed, int);\r | |
1665 | #else\r | |
1666 | fmissing("FLT_RADIX");\r | |
1667 | #endif\r | |
1668 | #ifdef FLT_MANT_DIG\r | |
1669 | checktype(FLT_MANT_DIG, "FLT_MANT_DIG", Signed, int);\r | |
1670 | #else\r | |
1671 | fmissing("FLT_MANT_DIG");\r | |
1672 | #endif\r | |
1673 | #ifdef FLT_DIG\r | |
1674 | checktype(FLT_DIG, "FLT_DIG", Signed, int);\r | |
1675 | #else\r | |
1676 | fmissing("FLT_DIG");\r | |
1677 | #endif\r | |
1678 | #ifdef FLT_ROUNDS\r | |
1679 | checktype(FLT_ROUNDS, "FLT_ROUNDS", Signed, int);\r | |
1680 | #else\r | |
1681 | fmissing("FLT_ROUNDS");\r | |
1682 | #endif\r | |
1683 | #ifdef FLT_EPSILON\r | |
1684 | fchecktype(FLT_EPSILON, "FLT_EPSILON", float);\r | |
1685 | #else\r | |
1686 | fmissing("FLT_EPSILON");\r | |
1687 | #endif\r | |
1688 | #ifdef FLT_MIN_EXP\r | |
1689 | checktype(FLT_MIN_EXP, "FLT_MIN_EXP", Signed, int);\r | |
1690 | #else\r | |
1691 | fmissing("FLT_MIN_EXP");\r | |
1692 | #endif\r | |
1693 | #ifdef FLT_MIN\r | |
1694 | fchecktype(FLT_MIN, "FLT_MIN", float);\r | |
1695 | #else\r | |
1696 | fmissing("FLT_MIN");\r | |
1697 | #endif\r | |
1698 | #ifdef FLT_MIN_10_EXP\r | |
1699 | checktype(FLT_MIN_10_EXP, "FLT_MIN_10_EXP", Signed, int);\r | |
1700 | #else\r | |
1701 | fmissing("FLT_MIN_10_EXP");\r | |
1702 | #endif\r | |
1703 | #ifdef FLT_MAX_EXP\r | |
1704 | checktype(FLT_MAX_EXP, "FLT_MAX_EXP", Signed, int);\r | |
1705 | #else\r | |
1706 | fmissing("FLT_MAX_EXP");\r | |
1707 | #endif\r | |
1708 | #ifdef FLT_MAX\r | |
1709 | fchecktype(FLT_MAX, "FLT_MAX", float);\r | |
1710 | #else\r | |
1711 | fmissing("FLT_MAX");\r | |
1712 | #endif\r | |
1713 | #ifdef FLT_MAX_10_EXP\r | |
1714 | checktype(FLT_MAX_10_EXP, "FLT_MAX_10_EXP", Signed, int);\r | |
1715 | #else\r | |
1716 | fmissing("FLT_MAX_10_EXP");\r | |
1717 | #endif\r | |
1718 | #ifdef DBL_MANT_DIG\r | |
1719 | checktype(DBL_MANT_DIG, "DBL_MANT_DIG", Signed, int);\r | |
1720 | #else\r | |
1721 | fmissing("DBL_MANT_DIG");\r | |
1722 | #endif\r | |
1723 | #ifdef DBL_DIG\r | |
1724 | checktype(DBL_DIG, "DBL_DIG", Signed, int);\r | |
1725 | #else\r | |
1726 | fmissing("DBL_DIG");\r | |
1727 | #endif\r | |
1728 | #ifdef DBL_EPSILON\r | |
1729 | fchecktype(DBL_EPSILON, "DBL_EPSILON", double);\r | |
1730 | #else\r | |
1731 | fmissing("DBL_EPSILON");\r | |
1732 | #endif\r | |
1733 | #ifdef DBL_MIN_EXP\r | |
1734 | checktype(DBL_MIN_EXP, "DBL_MIN_EXP", Signed, int);\r | |
1735 | #else\r | |
1736 | fmissing("DBL_MIN_EXP");\r | |
1737 | #endif\r | |
1738 | #ifdef DBL_MIN\r | |
1739 | fchecktype(DBL_MIN, "DBL_MIN", double);\r | |
1740 | #else\r | |
1741 | fmissing("DBL_MIN");\r | |
1742 | #endif\r | |
1743 | #ifdef DBL_MIN_10_EXP\r | |
1744 | checktype(DBL_MIN_10_EXP, "DBL_MIN_10_EXP", Signed, int);\r | |
1745 | #else\r | |
1746 | fmissing("DBL_MIN_10_EXP");\r | |
1747 | #endif\r | |
1748 | #ifdef DBL_MAX_EXP\r | |
1749 | checktype(DBL_MAX_EXP, "DBL_MAX_EXP", Signed, int);\r | |
1750 | #else\r | |
1751 | fmissing("DBL_MAX_EXP");\r | |
1752 | #endif\r | |
1753 | #ifdef DBL_MAX\r | |
1754 | fchecktype(DBL_MAX, "DBL_MAX", double);\r | |
1755 | #else\r | |
1756 | fmissing("DBL_MAX");\r | |
1757 | #endif\r | |
1758 | #ifdef DBL_MAX_10_EXP\r | |
1759 | checktype(DBL_MAX_10_EXP, "DBL_MAX_10_EXP", Signed, int);\r | |
1760 | #else\r | |
1761 | fmissing("DBL_MAX_10_EXP");\r | |
1762 | #endif\r | |
1763 | #ifdef STDC\r | |
1764 | #ifdef LDBL_MANT_DIG\r | |
1765 | checktype(LDBL_MANT_DIG, "LDBL_MANT_DIG", Signed, int);\r | |
1766 | #else\r | |
1767 | fmissing("LDBL_MANT_DIG");\r | |
1768 | #endif\r | |
1769 | #ifdef LDBL_DIG\r | |
1770 | checktype(LDBL_DIG, "LDBL_DIG", Signed, int);\r | |
1771 | #else\r | |
1772 | fmissing("LDBL_DIG");\r | |
1773 | #endif\r | |
1774 | #ifdef LDBL_EPSILON\r | |
1775 | fchecktype(LDBL_EPSILON, "LDBL_EPSILON", long double);\r | |
1776 | #else\r | |
1777 | fmissing("LDBL_EPSILON");\r | |
1778 | #endif\r | |
1779 | #ifdef LDBL_MIN_EXP\r | |
1780 | checktype(LDBL_MIN_EXP, "LDBL_MIN_EXP", Signed, int);\r | |
1781 | #else\r | |
1782 | fmissing("LDBL_MIN_EXP");\r | |
1783 | #endif\r | |
1784 | #ifdef LDBL_MIN\r | |
1785 | fchecktype(LDBL_MIN, "LDBL_MIN", long double);\r | |
1786 | #else\r | |
1787 | fmissing("LDBL_MIN");\r | |
1788 | #endif\r | |
1789 | #ifdef LDBL_MIN_10_EXP\r | |
1790 | checktype(LDBL_MIN_10_EXP, "LDBL_MIN_10_EXP", Signed, int);\r | |
1791 | #else\r | |
1792 | fmissing("LDBL_MIN_10_EXP");\r | |
1793 | #endif\r | |
1794 | #ifdef LDBL_MAX_EXP\r | |
1795 | checktype(LDBL_MAX_EXP, "LDBL_MAX_EXP", Signed, int);\r | |
1796 | #else\r | |
1797 | fmissing("LDBL_MAX_EXP");\r | |
1798 | #endif\r | |
1799 | #ifdef LDBL_MAX\r | |
1800 | fchecktype(LDBL_MAX, "LDBL_MAX", long double);\r | |
1801 | #else\r | |
1802 | fmissing("LDBL_MAX");\r | |
1803 | #endif\r | |
1804 | #ifdef LDBL_MAX_10_EXP\r | |
1805 | checktype(LDBL_MAX_10_EXP, "LDBL_MAX_10_EXP", Signed, int);\r | |
1806 | #else\r | |
1807 | fmissing("LDBL_MAX_10_EXP");\r | |
1808 | #endif\r | |
1809 | #endif /* STDC */\r | |
1810 | } /* if (F) */\r | |
1811 | #endif /* VERIFY */\r | |
1812 | }\r | |
1813 | \r | |
1814 | #ifdef VERIFY\r | |
1815 | #ifndef SCHAR_MAX\r | |
1816 | #define SCHAR_MAX char_max\r | |
1817 | #endif\r | |
1818 | #ifndef SCHAR_MIN\r | |
1819 | #define SCHAR_MIN char_min\r | |
1820 | #endif\r | |
1821 | #ifndef UCHAR_MAX\r | |
1822 | #define UCHAR_MAX char_max\r | |
1823 | #endif\r | |
1824 | #endif /* VERIFY */\r | |
1825 | \r | |
1826 | #ifndef CHAR_BIT\r | |
1827 | #define CHAR_BIT char_bit\r | |
1828 | #endif\r | |
1829 | #ifndef CHAR_MAX\r | |
1830 | #define CHAR_MAX char_max\r | |
1831 | #endif\r | |
1832 | #ifndef CHAR_MIN\r | |
1833 | #define CHAR_MIN char_min\r | |
1834 | #endif\r | |
1835 | #ifndef SCHAR_MAX\r | |
1836 | #define SCHAR_MAX char_max\r | |
1837 | #endif\r | |
1838 | #ifndef SCHAR_MIN\r | |
1839 | #define SCHAR_MIN char_min\r | |
1840 | #endif\r | |
1841 | #ifndef UCHAR_MAX\r | |
1842 | #define UCHAR_MAX char_max\r | |
1843 | #endif\r | |
1844 | \r | |
1845 | int cprop( void )\r | |
1846 | {\r | |
1847 | /* Properties of type char */\r | |
1848 | Volatile char c, char_max, char_min;\r | |
1849 | Volatile int byte_size, c_signed;\r | |
1850 | long char_bit;\r | |
1851 | \r | |
1852 | Unexpected(2);\r | |
1853 | \r | |
1854 | /* Calculate number of bits per character *************************/\r | |
1855 | c=1; byte_size=0;\r | |
1856 | do { c=c<<1; byte_size++; } while(c!=0);\r | |
1857 | c= (char)(-1);\r | |
1858 | if (((int)c)<0) c_signed=1;\r | |
1859 | else c_signed=0;\r | |
1860 | Vprintf("%schar = %d bits, %ssigned%s\n",\r | |
1861 | co, (int)sizeof(c)*byte_size, (c_signed?"":"un"), oc);\r | |
1862 | char_bit=(long)(sizeof(c)*byte_size);\r | |
1863 | if (L) i_define(D_CHAR_BIT, "", "CHAR", "_BIT",\r | |
1864 | char_bit, 0L, (long) CHAR_BIT, "");\r | |
1865 | \r | |
1866 | c=0; char_max=0;\r | |
1867 | c++;\r | |
1868 | if (setjmp(lab)==0) { /* Yields char_max */\r | |
1869 | while (c>char_max) {\r | |
1870 | char_max=c;\r | |
1871 | c=(char)(c*2+1);\r | |
1872 | }\r | |
1873 | } else {\r | |
1874 | Vprintf("%sCharacter overflow generates a trap!%s\n", co, oc);\r | |
1875 | }\r | |
1876 | c=0; char_min=0;\r | |
1877 | c--;\r | |
1878 | if (c<char_min) /* then the min char < 0 */ {\r | |
1879 | /* Minimum value: assume either two's or one's complement *********/\r | |
1880 | char_min= -char_max;\r | |
1881 | if (setjmp(lab)==0) { /* Yields char_min */\r | |
1882 | if (char_min-1 < char_min) char_min--;\r | |
1883 | }\r | |
1884 | }\r | |
1885 | Unexpected(8);\r | |
1886 | if (c_signed && char_min == 0) {\r | |
1887 | Vprintf("%sBEWARE! Chars are pseudo-unsigned:%s\n", co, oc);\r | |
1888 | Vprintf("%s %s%s%s\n",\r | |
1889 | "They contain only nonnegative values, ",\r | |
1890 | "but sign extend when used as integers.", co, oc);\r | |
1891 | }\r | |
1892 | Unexpected(3);\r | |
1893 | \r | |
1894 | if (L) {\r | |
1895 | /* Because of the integer promotions, you must use a U after\r | |
1896 | the MAX_CHARS in the following cases */\r | |
1897 | if ((sizeof(char) == sizeof(int)) && !c_signed) {\r | |
1898 | u_define(D_CHAR_MAX, "", "CHAR", "_MAX",\r | |
1899 | (ulong) char_max,\r | |
1900 | (ulong) CHAR_MAX, "");\r | |
1901 | } else {\r | |
1902 | i_define(D_CHAR_MAX, "", "CHAR", "_MAX",\r | |
1903 | (long) char_max, 0L,\r | |
1904 | (long) CHAR_MAX, "");\r | |
1905 | }\r | |
1906 | i_define(D_CHAR_MIN, "", "CHAR", "_MIN",\r | |
1907 | (long) char_min, (long) maxint,\r | |
1908 | (long) CHAR_MIN, "");\r | |
1909 | if (c_signed) {\r | |
1910 | i_define(D_SCHAR_MAX, "", "SCHAR", "_MAX",\r | |
1911 | (long) char_max, 0L,\r | |
1912 | (long) SCHAR_MAX, "");\r | |
1913 | i_define(D_SCHAR_MIN, "", "SCHAR", "_MIN",\r | |
1914 | (long) char_min, (long) maxint,\r | |
1915 | (long) SCHAR_MIN, "");\r | |
1916 | } else {\r | |
1917 | if (sizeof(char) == sizeof(int)) {\r | |
1918 | u_define(D_UCHAR_MAX, "", "UCHAR", "_MAX",\r | |
1919 | (ulong) char_max,\r | |
1920 | (ulong) UCHAR_MAX, "");\r | |
1921 | } else {\r | |
1922 | i_define(D_UCHAR_MAX, "", "UCHAR", "_MAX",\r | |
1923 | (long) char_max, 0L,\r | |
1924 | (long) UCHAR_MAX, "");\r | |
1925 | }\r | |
1926 | }\r | |
1927 | \r | |
1928 | if (c_signed) {\r | |
1929 | #ifndef NO_UC\r | |
1930 | /* Syntax error? Define NO_UC */ Volatile unsigned char c1, char_max;\r | |
1931 | c1=0; char_max=0;\r | |
1932 | c1++;\r | |
1933 | if (setjmp(lab)==0) { /* Yields char_max */\r | |
1934 | while (c1>char_max) {\r | |
1935 | char_max=c1;\r | |
1936 | c1++;\r | |
1937 | }\r | |
1938 | }\r | |
1939 | Unexpected(4);\r | |
1940 | if (sizeof(char) == sizeof(int)) {\r | |
1941 | u_define(D_UCHAR_MAX, "", "UCHAR", "_MAX",\r | |
1942 | (ulong) char_max,\r | |
1943 | (ulong) UCHAR_MAX, "");\r | |
1944 | } else {\r | |
1945 | i_define(D_UCHAR_MAX, "", "UCHAR", "_MAX",\r | |
1946 | (long) char_max, 0L,\r | |
1947 | (long) UCHAR_MAX, "");\r | |
1948 | }\r | |
1949 | #endif\r | |
1950 | } else {\r | |
1951 | #ifndef NO_SC\r | |
1952 | /* Syntax error? Define NO_SC */ Volatile signed char c1, char_max, char_min;\r | |
1953 | c1=0; char_max=0;\r | |
1954 | c1++;\r | |
1955 | if (setjmp(lab)==0) { /* Yields char_max */\r | |
1956 | while (c1>char_max) {\r | |
1957 | char_max=c1;\r | |
1958 | c1++;\r | |
1959 | }\r | |
1960 | }\r | |
1961 | c1=0; char_min=0;\r | |
1962 | c1--;\r | |
1963 | if (setjmp(lab)==0) { /* Yields char_min */\r | |
1964 | while (c1<char_min) {\r | |
1965 | char_min=c1;\r | |
1966 | c1--;\r | |
1967 | }\r | |
1968 | }\r | |
1969 | Unexpected(5);\r | |
1970 | i_define(D_SCHAR_MIN, "", "SCHAR", "_MIN",\r | |
1971 | (long) char_min, (long) maxint,\r | |
1972 | (long) SCHAR_MIN, "");\r | |
1973 | i_define(D_SCHAR_MAX, "", "SCHAR", "_MAX",\r | |
1974 | (long) char_max, 0L,\r | |
1975 | (long) SCHAR_MAX, "");\r | |
1976 | #endif /* NO_SC */\r | |
1977 | }\r | |
1978 | }\r | |
1979 | return byte_size;\r | |
1980 | }\r | |
1981 | \r | |
1982 | int basic( void )\r | |
1983 | {\r | |
1984 | /* The properties of the basic types.\r | |
1985 | Returns number of bits per sizeof unit */\r | |
1986 | Volatile int byte_size;\r | |
1987 | typedef int function ();\r | |
1988 | int variable;\r | |
1989 | char *cp; int *ip; function *fp;\r | |
1990 | int *p, *q;\r | |
1991 | \r | |
1992 | Vprintf("%sSIZES%s\n", co, oc);\r | |
1993 | byte_size= cprop();\r | |
1994 | \r | |
1995 | /* Shorts, ints and longs *****************************************/\r | |
1996 | Vprintf("%sshort=%d int=%d long=%d float=%d double=%d bits %s\n",\r | |
1997 | co,\r | |
1998 | (int) sizeof(short)*byte_size,\r | |
1999 | (int) sizeof(int)*byte_size,\r | |
2000 | (int) sizeof(long)*byte_size,\r | |
2001 | (int) sizeof(float)*byte_size,\r | |
2002 | (int) sizeof(double)*byte_size, oc);\r | |
2003 | if (stdc) {\r | |
2004 | Vprintf("%slong double=%d bits%s\n",\r | |
2005 | co, (int) sizeof(Long_double)*byte_size, oc);\r | |
2006 | }\r | |
2007 | Vprintf("%schar*=%d bits%s%s\n",\r | |
2008 | co, (int)sizeof(char *)*byte_size,\r | |
2009 | sizeof(char *)>sizeof(int)?" BEWARE! larger than int!":"",\r | |
2010 | oc);\r | |
2011 | Vprintf("%sint* =%d bits%s%s\n",\r | |
2012 | co, (int)sizeof(int *)*byte_size,\r | |
2013 | sizeof(int *)>sizeof(int)?" BEWARE! larger than int!":"",\r | |
2014 | oc);\r | |
2015 | Vprintf("%sfunc*=%d bits%s%s\n",\r | |
2016 | co, (int)sizeof(function *)*byte_size,\r | |
2017 | sizeof(function *)>sizeof(int)?" BEWARE! larger than int!":"",\r | |
2018 | oc);\r | |
2019 | \r | |
2020 | showtype("Type size_t is", sizeof(0));\r | |
2021 | #ifdef STDC\r | |
2022 | showtype("Type wchar_t is", L'x');\r | |
2023 | #endif\r | |
2024 | \r | |
2025 | /* Alignment constants ********************************************/\r | |
2026 | \r | |
2027 | #define alignment(TYPE) \\r | |
2028 | ((long)((char *)&((struct{char c; TYPE d;}*)0)->d - (char *)0))\r | |
2029 | \r | |
2030 | Vprintf("\n%sALIGNMENTS%s\n", co, oc);\r | |
2031 | \r | |
2032 | Vprintf("%schar=%ld short=%ld int=%ld long=%ld%s\n",\r | |
2033 | co,\r | |
2034 | alignment(char), alignment(short),\r | |
2035 | alignment(int), alignment(long),\r | |
2036 | oc);\r | |
2037 | \r | |
2038 | Vprintf("%sfloat=%ld double=%ld%s\n",\r | |
2039 | co,\r | |
2040 | alignment(float), alignment(double),\r | |
2041 | oc);\r | |
2042 | \r | |
2043 | if (stdc) {\r | |
2044 | Vprintf("%slong double=%ld%s\n",\r | |
2045 | co,\r | |
2046 | alignment(Long_double),\r | |
2047 | oc);\r | |
2048 | }\r | |
2049 | Vprintf("%schar*=%ld int*=%ld func*=%ld%s\n",\r | |
2050 | co,\r | |
2051 | alignment(char *), alignment(int *), alignment(function *),\r | |
2052 | oc);\r | |
2053 | \r | |
2054 | Vprintf("\n");\r | |
2055 | \r | |
2056 | /* Ten little endians *********************************************/\r | |
2057 | \r | |
2058 | endian(byte_size);\r | |
2059 | \r | |
2060 | /* Pointers *******************************************************/\r | |
2061 | \r | |
2062 | Vprintf("\n%sPROPERTIES OF POINTERS%s\n", co, oc);\r | |
2063 | cp= (char *) &variable;\r | |
2064 | ip= (int *) &variable;\r | |
2065 | fp= (function *) &variable;\r | |
2066 | \r | |
2067 | Vprintf("%sChar and int pointer formats ", co);\r | |
2068 | if (memeq((char *) &cp, sizeof(cp), (char *) &ip, sizeof(ip))) {\r | |
2069 | Vprintf("seem identical%s\n", oc);\r | |
2070 | } else {\r | |
2071 | Vprintf("are different%s\n", oc);\r | |
2072 | }\r | |
2073 | Vprintf("%sChar and function pointer formats ", co);\r | |
2074 | if (memeq((char *) &cp, sizeof(cp), (char *) &fp, sizeof(fp))) {\r | |
2075 | Vprintf("seem identical%s\n", oc);\r | |
2076 | } else {\r | |
2077 | Vprintf("are different%s\n", oc);\r | |
2078 | }\r | |
2079 | \r | |
2080 | if (V) {\r | |
2081 | if ((VOID *)"abcd" == (VOID *)"abcd")\r | |
2082 | printf("%sStrings are shared%s\n", co, oc);\r | |
2083 | else printf("%sStrings are not shared%s\n", co, oc);\r | |
2084 | }\r | |
2085 | \r | |
2086 | p=0; q=0;\r | |
2087 | showtype("Type ptrdiff_t is", p-q);\r | |
2088 | \r | |
2089 | //if (setjmp(mlab) == 0) {\r | |
2090 | // variable= *p;\r | |
2091 | // Vprintf("%sBEWARE! Dereferencing NULL doesn't cause a trap%s\n",\r | |
2092 | // co, oc);\r | |
2093 | //} else {\r | |
2094 | // Vprintf("%sDereferencing NULL causes a trap%s\n", co, oc);\r | |
2095 | //}\r | |
2096 | if (setjmp(mlab)!=0) croak(-2);\r | |
2097 | \r | |
2098 | Vprintf("\n%sPROPERTIES OF INTEGRAL TYPES%s\n", co, oc);\r | |
2099 | \r | |
2100 | sprop();\r | |
2101 | iprop();\r | |
2102 | lprop();\r | |
2103 | usprop();\r | |
2104 | uiprop();\r | |
2105 | ulprop();\r | |
2106 | \r | |
2107 | promotions();\r | |
2108 | \r | |
2109 | Unexpected(6);\r | |
2110 | \r | |
2111 | return byte_size;\r | |
2112 | }\r | |
2113 | \r | |
2114 | #else /* not PASS0 */\r | |
2115 | \r | |
2116 | #ifdef SEP\r | |
2117 | /* The global variables used by several passes */\r | |
2118 | extern jmp_buf lab;\r | |
2119 | extern int V, L, F, bugs, bits_per_byte;\r | |
2120 | extern int maxint, flt_radix, flt_rounds;\r | |
2121 | extern Volatile int trapped;\r | |
2122 | extern char co[], oc[];\r | |
2123 | extern char *f_rep();\r | |
2124 | extern Void trap1();\r | |
2125 | #endif /* SEP */\r | |
2126 | #endif /* ifdef PASS0 */\r | |
2127 | \r | |
2128 | /* As I said, I apologise for the contortions below. The functions are\r | |
2129 | expanded by the preprocessor twice or three times (for float and double,\r | |
2130 | and maybe for long double, and for short, int and long). That way,\r | |
2131 | I never make a change to one that I forget to make to the other.\r | |
2132 | You can look on it as C's fault for not supporting multi-line macros.\r | |
2133 | This whole file is read 3 times by the preprocessor, with PASSn set for\r | |
2134 | n=1, 2 or 3, to decide which parts to reprocess.\r | |
2135 | */\r | |
2136 | \r | |
2137 | /* #undef on an already undefined thing is (wrongly) flagged as an error\r | |
2138 | by some compilers, therefore the #ifdef that follows:\r | |
2139 | */\r | |
2140 | #ifdef Number\r | |
2141 | #undef Number\r | |
2142 | #undef THING\r | |
2143 | #undef Thing\r | |
2144 | #undef thing\r | |
2145 | #undef FPROP\r | |
2146 | #undef Fname\r | |
2147 | #undef Store\r | |
2148 | #undef Sum\r | |
2149 | #undef Diff\r | |
2150 | #undef Mul\r | |
2151 | #undef Div\r | |
2152 | #undef ZERO\r | |
2153 | #undef HALF\r | |
2154 | #undef ONE\r | |
2155 | #undef TWO\r | |
2156 | #undef THREE\r | |
2157 | #undef FOUR\r | |
2158 | #undef Self\r | |
2159 | #undef F_check\r | |
2160 | #undef Verify\r | |
2161 | #undef EPROP\r | |
2162 | #undef MARK\r | |
2163 | \r | |
2164 | /* These are the float.h constants */\r | |
2165 | #undef F_RADIX\r | |
2166 | #undef F_MANT_DIG\r | |
2167 | #undef F_DIG\r | |
2168 | #undef F_ROUNDS\r | |
2169 | #undef F_EPSILON\r | |
2170 | #undef F_MIN_EXP\r | |
2171 | #undef F_MIN\r | |
2172 | #undef F_MIN_10_EXP\r | |
2173 | #undef F_MAX_EXP\r | |
2174 | #undef F_MAX\r | |
2175 | #undef F_MAX_10_EXP\r | |
2176 | #endif\r | |
2177 | \r | |
2178 | #ifdef Integer\r | |
2179 | #undef Integer\r | |
2180 | #undef INT\r | |
2181 | #undef IPROP\r | |
2182 | #undef Iname\r | |
2183 | #undef UPROP\r | |
2184 | #undef Uname\r | |
2185 | #undef OK_UI\r | |
2186 | #undef IMARK\r | |
2187 | \r | |
2188 | #undef I_MAX\r | |
2189 | #undef I_MIN\r | |
2190 | #undef U_MAX\r | |
2191 | #endif\r | |
2192 | \r | |
2193 | #ifdef PASS1\r | |
2194 | \r | |
2195 | /* Define the things we're going to use this pass */\r | |
2196 | \r | |
2197 | #define Number float\r | |
2198 | #define THING "FLOAT"\r | |
2199 | #define Thing "Float"\r | |
2200 | #define thing "float"\r | |
2201 | #define Fname "FLT"\r | |
2202 | #define FPROP fprop\r | |
2203 | #define Store fStore\r | |
2204 | #define Sum fSum\r | |
2205 | #define Diff fDiff\r | |
2206 | #define Mul fMul\r | |
2207 | #define Div fDiv\r | |
2208 | #define ZERO 0.0\r | |
2209 | #define HALF 0.5\r | |
2210 | #define ONE 1.0\r | |
2211 | #define TWO 2.0\r | |
2212 | #define THREE 3.0\r | |
2213 | #define FOUR 4.0\r | |
2214 | #define Self fSelf\r | |
2215 | #define F_check fCheck\r | |
2216 | #define MARK "F"\r | |
2217 | #ifdef VERIFY\r | |
2218 | #define Verify fVerify\r | |
2219 | #endif\r | |
2220 | \r | |
2221 | #define EPROP efprop\r | |
2222 | \r | |
2223 | #define Integer short\r | |
2224 | #define INT "short"\r | |
2225 | #define IPROP sprop\r | |
2226 | #define Iname "SHRT"\r | |
2227 | #ifndef NO_UI\r | |
2228 | #define OK_UI 1\r | |
2229 | #endif\r | |
2230 | #define IMARK ""\r | |
2231 | \r | |
2232 | #define UPROP usprop\r | |
2233 | #define Uname "USHRT"\r | |
2234 | \r | |
2235 | #ifdef VERIFY\r | |
2236 | #ifdef SHRT_MAX\r | |
2237 | #define I_MAX SHRT_MAX\r | |
2238 | #endif\r | |
2239 | #ifdef SHRT_MIN\r | |
2240 | #define I_MIN SHRT_MIN\r | |
2241 | #endif\r | |
2242 | #ifdef USHRT_MAX\r | |
2243 | #define U_MAX USHRT_MAX\r | |
2244 | #endif\r | |
2245 | \r | |
2246 | #ifdef FLT_RADIX\r | |
2247 | #define F_RADIX FLT_RADIX\r | |
2248 | #endif\r | |
2249 | #ifdef FLT_MANT_DIG\r | |
2250 | #define F_MANT_DIG FLT_MANT_DIG\r | |
2251 | #endif\r | |
2252 | #ifdef FLT_DIG\r | |
2253 | #define F_DIG FLT_DIG\r | |
2254 | #endif\r | |
2255 | #ifdef FLT_ROUNDS\r | |
2256 | #define F_ROUNDS FLT_ROUNDS\r | |
2257 | #endif\r | |
2258 | #ifdef FLT_EPSILON\r | |
2259 | #define F_EPSILON FLT_EPSILON\r | |
2260 | #endif\r | |
2261 | #ifdef FLT_MIN_EXP\r | |
2262 | #define F_MIN_EXP FLT_MIN_EXP\r | |
2263 | #endif\r | |
2264 | #ifdef FLT_MIN\r | |
2265 | #define F_MIN FLT_MIN\r | |
2266 | #endif\r | |
2267 | #ifdef FLT_MIN_10_EXP\r | |
2268 | #define F_MIN_10_EXP FLT_MIN_10_EXP\r | |
2269 | #endif\r | |
2270 | #ifdef FLT_MAX_EXP\r | |
2271 | #define F_MAX_EXP FLT_MAX_EXP\r | |
2272 | #endif\r | |
2273 | #ifdef FLT_MAX\r | |
2274 | #define F_MAX FLT_MAX\r | |
2275 | #endif\r | |
2276 | #ifdef FLT_MAX_10_EXP\r | |
2277 | #define F_MAX_10_EXP FLT_MAX_10_EXP\r | |
2278 | #endif\r | |
2279 | #endif /* VERIFY */\r | |
2280 | \r | |
2281 | #endif /* PASS1 */\r | |
2282 | \r | |
2283 | #ifdef PASS2\r | |
2284 | \r | |
2285 | #define Number double\r | |
2286 | #define THING "DOUBLE"\r | |
2287 | #define Thing "Double"\r | |
2288 | #define thing "double"\r | |
2289 | #define Fname "DBL"\r | |
2290 | #define FPROP dprop\r | |
2291 | #define Store dStore\r | |
2292 | #define Sum dSum\r | |
2293 | #define Diff dDiff\r | |
2294 | #define Mul dMul\r | |
2295 | #define Div dDiv\r | |
2296 | #define ZERO 0.0\r | |
2297 | #define HALF 0.5\r | |
2298 | #define ONE 1.0\r | |
2299 | #define TWO 2.0\r | |
2300 | #define THREE 3.0\r | |
2301 | #define FOUR 4.0\r | |
2302 | #define Self dSelf\r | |
2303 | #define F_check dCheck\r | |
2304 | #define MARK ""\r | |
2305 | #ifdef VERIFY\r | |
2306 | #define Verify dVerify\r | |
2307 | #endif\r | |
2308 | \r | |
2309 | #define EPROP edprop\r | |
2310 | \r | |
2311 | #define Integer int\r | |
2312 | #define INT "int"\r | |
2313 | #define IPROP iprop\r | |
2314 | #define Iname "INT"\r | |
2315 | #define OK_UI 1 /* Unsigned int is always possible */\r | |
2316 | #define IMARK ""\r | |
2317 | \r | |
2318 | #define UPROP uiprop\r | |
2319 | #define Uname "UINT"\r | |
2320 | \r | |
2321 | #ifdef VERIFY\r | |
2322 | #ifdef INT_MAX\r | |
2323 | #define I_MAX INT_MAX\r | |
2324 | #endif\r | |
2325 | #ifdef INT_MIN\r | |
2326 | #define I_MIN INT_MIN\r | |
2327 | #endif\r | |
2328 | #ifdef UINT_MAX\r | |
2329 | #define U_MAX UINT_MAX\r | |
2330 | #endif\r | |
2331 | \r | |
2332 | #ifdef DBL_MANT_DIG\r | |
2333 | #define F_MANT_DIG DBL_MANT_DIG\r | |
2334 | #endif\r | |
2335 | #ifdef DBL_DIG\r | |
2336 | #define F_DIG DBL_DIG\r | |
2337 | #endif\r | |
2338 | #ifdef DBL_EPSILON\r | |
2339 | #define F_EPSILON DBL_EPSILON\r | |
2340 | #endif\r | |
2341 | #ifdef DBL_MIN_EXP\r | |
2342 | #define F_MIN_EXP DBL_MIN_EXP\r | |
2343 | #endif\r | |
2344 | #ifdef DBL_MIN\r | |
2345 | #define F_MIN DBL_MIN\r | |
2346 | #endif\r | |
2347 | #ifdef DBL_MIN_10_EXP\r | |
2348 | #define F_MIN_10_EXP DBL_MIN_10_EXP\r | |
2349 | #endif\r | |
2350 | #ifdef DBL_MAX_EXP\r | |
2351 | #define F_MAX_EXP DBL_MAX_EXP\r | |
2352 | #endif\r | |
2353 | #ifdef DBL_MAX\r | |
2354 | #define F_MAX DBL_MAX\r | |
2355 | #endif\r | |
2356 | #ifdef DBL_MAX_10_EXP\r | |
2357 | #define F_MAX_10_EXP DBL_MAX_10_EXP\r | |
2358 | #endif\r | |
2359 | #endif /* VERIFY */\r | |
2360 | \r | |
2361 | #endif /* PASS2 */\r | |
2362 | \r | |
2363 | #ifdef PASS3\r | |
2364 | \r | |
2365 | #ifdef STDC\r | |
2366 | #define Number long double\r | |
2367 | \r | |
2368 | #define ZERO 0.0L\r | |
2369 | #define HALF 0.5L\r | |
2370 | #define ONE 1.0L\r | |
2371 | #define TWO 2.0L\r | |
2372 | #define THREE 3.0L\r | |
2373 | #define FOUR 4.0L\r | |
2374 | #endif\r | |
2375 | \r | |
2376 | #define THING "LONG DOUBLE"\r | |
2377 | #define Thing "Long double"\r | |
2378 | #define thing "long double"\r | |
2379 | #define Fname "LDBL"\r | |
2380 | #define FPROP ldprop\r | |
2381 | #define Store ldStore\r | |
2382 | #define Sum ldSum\r | |
2383 | #define Diff ldDiff\r | |
2384 | #define Mul ldMul\r | |
2385 | #define Div ldDiv\r | |
2386 | #define Self ldSelf\r | |
2387 | #define F_check ldCheck\r | |
2388 | #define MARK "L"\r | |
2389 | #ifdef VERIFY\r | |
2390 | #define Verify ldVerify\r | |
2391 | #endif\r | |
2392 | \r | |
2393 | #define EPROP eldprop\r | |
2394 | \r | |
2395 | #define Integer long\r | |
2396 | #define INT "long"\r | |
2397 | #define IPROP lprop\r | |
2398 | #define Iname "LONG"\r | |
2399 | #ifndef NO_UI\r | |
2400 | #define OK_UI 1\r | |
2401 | #endif\r | |
2402 | #define IMARK "L"\r | |
2403 | \r | |
2404 | #define UPROP ulprop\r | |
2405 | #define Uname "ULONG"\r | |
2406 | \r | |
2407 | #ifdef VERIFY\r | |
2408 | #ifdef LONG_MAX\r | |
2409 | #define I_MAX LONG_MAX\r | |
2410 | #endif\r | |
2411 | #ifdef LONG_MIN\r | |
2412 | #define I_MIN LONG_MIN\r | |
2413 | #endif\r | |
2414 | #ifdef ULONG_MAX\r | |
2415 | #define U_MAX ULONG_MAX\r | |
2416 | #endif\r | |
2417 | \r | |
2418 | #ifdef LDBL_MANT_DIG\r | |
2419 | #define F_MANT_DIG LDBL_MANT_DIG\r | |
2420 | #endif\r | |
2421 | #ifdef LDBL_DIG\r | |
2422 | #define F_DIG LDBL_DIG\r | |
2423 | #endif\r | |
2424 | #ifdef LDBL_EPSILON\r | |
2425 | #define F_EPSILON LDBL_EPSILON\r | |
2426 | #endif\r | |
2427 | #ifdef LDBL_MIN_EXP\r | |
2428 | #define F_MIN_EXP LDBL_MIN_EXP\r | |
2429 | #endif\r | |
2430 | #ifdef LDBL_MIN\r | |
2431 | #define F_MIN LDBL_MIN\r | |
2432 | #endif\r | |
2433 | #ifdef LDBL_MIN_10_EXP\r | |
2434 | #define F_MIN_10_EXP LDBL_MIN_10_EXP\r | |
2435 | #endif\r | |
2436 | #ifdef LDBL_MAX_EXP\r | |
2437 | #define F_MAX_EXP LDBL_MAX_EXP\r | |
2438 | #endif\r | |
2439 | #ifdef LDBL_MAX\r | |
2440 | #define F_MAX LDBL_MAX\r | |
2441 | #endif\r | |
2442 | #ifdef LDBL_MAX_10_EXP\r | |
2443 | #define F_MAX_10_EXP LDBL_MAX_10_EXP\r | |
2444 | #endif\r | |
2445 | #endif /* VERIFY */\r | |
2446 | \r | |
2447 | #endif /* PASS3 */\r | |
2448 | \r | |
2449 | /* The rest of the file gets read all three times;\r | |
2450 | the differences are encoded in the things #defined above.\r | |
2451 | */\r | |
2452 | \r | |
2453 | #ifndef I_MAX\r | |
2454 | #define I_MAX int_max\r | |
2455 | #endif\r | |
2456 | #ifndef I_MIN\r | |
2457 | #define I_MIN int_min\r | |
2458 | #endif\r | |
2459 | #ifndef U_MAX\r | |
2460 | #define U_MAX u_max\r | |
2461 | #endif\r | |
2462 | \r | |
2463 | #ifndef F_RADIX\r | |
2464 | #define F_RADIX f_radix\r | |
2465 | #endif\r | |
2466 | #ifndef F_MANT_DIG\r | |
2467 | #define F_MANT_DIG f_mant_dig\r | |
2468 | #endif\r | |
2469 | #ifndef F_DIG\r | |
2470 | #define F_DIG f_dig\r | |
2471 | #endif\r | |
2472 | #ifndef F_ROUNDS\r | |
2473 | #define F_ROUNDS f_rounds\r | |
2474 | #endif\r | |
2475 | #ifndef F_EPSILON\r | |
2476 | #define F_EPSILON f_epsilon\r | |
2477 | #endif\r | |
2478 | #ifndef F_MIN_EXP\r | |
2479 | #define F_MIN_EXP f_min_exp\r | |
2480 | #endif\r | |
2481 | #ifndef F_MIN\r | |
2482 | #define F_MIN f_min\r | |
2483 | #endif\r | |
2484 | #ifndef F_MIN_10_EXP\r | |
2485 | #define F_MIN_10_EXP f_min_10_exp\r | |
2486 | #endif\r | |
2487 | #ifndef F_MAX_EXP\r | |
2488 | #define F_MAX_EXP f_max_exp\r | |
2489 | #endif\r | |
2490 | #ifndef F_MAX\r | |
2491 | #define F_MAX f_max\r | |
2492 | #endif\r | |
2493 | #ifndef F_MAX_10_EXP\r | |
2494 | #define F_MAX_10_EXP f_max_10_exp\r | |
2495 | #endif\r | |
2496 | \r | |
2497 | #ifndef VERIFY\r | |
2498 | #define Verify(prec, val, req, same, same1) {;}\r | |
2499 | #endif\r | |
2500 | \r | |
2501 | #ifdef Integer\r | |
2502 | \r | |
2503 | Void IPROP( void )\r | |
2504 | {\r | |
2505 | /* the properties of short, int, and long */\r | |
2506 | Volatile Integer newi, int_max, maxeri, int_min, minneri;\r | |
2507 | Volatile int ibits, ipower, two=2;\r | |
2508 | \r | |
2509 | /* Calculate max short/int/long ***********************************/\r | |
2510 | /* Calculate 2**n-1 until overflow - then use the previous value */\r | |
2511 | \r | |
2512 | newi=1; int_max=0;\r | |
2513 | \r | |
2514 | if (setjmp(lab)==0) { /* Yields int_max */\r | |
2515 | for(ipower=0; newi>int_max; ipower++) {\r | |
2516 | int_max=newi;\r | |
2517 | newi=newi*two+1;\r | |
2518 | }\r | |
2519 | Vprintf("%sOverflow of a%s %s does not generate a trap%s\n",\r | |
2520 | co, INT[0]=='i'?"n":"", INT, oc);\r | |
2521 | } else {\r | |
2522 | Vprintf("%sOverflow of a%s %s generates a trap%s\n",\r | |
2523 | co, INT[0]=='i'?"n":"", INT, oc);\r | |
2524 | }\r | |
2525 | Unexpected(7);\r | |
2526 | \r | |
2527 | /* Minimum value: assume either two's or one's complement *********/\r | |
2528 | int_min= -int_max;\r | |
2529 | if (setjmp(lab)==0) { /* Yields int_min */\r | |
2530 | if (int_min-1 < int_min) int_min--;\r | |
2531 | }\r | |
2532 | Unexpected(8);\r | |
2533 | \r | |
2534 | /* Now for those daft Cybers */\r | |
2535 | \r | |
2536 | maxeri=0; newi=int_max;\r | |
2537 | \r | |
2538 | if (setjmp(lab)==0) { /* Yields maxeri */\r | |
2539 | for(ibits=ipower; newi>maxeri; ibits++) {\r | |
2540 | maxeri=newi;\r | |
2541 | newi=newi+newi+1;\r | |
2542 | }\r | |
2543 | }\r | |
2544 | Unexpected(9);\r | |
2545 | \r | |
2546 | minneri= -maxeri;\r | |
2547 | if (setjmp(lab)==0) { /* Yields minneri */\r | |
2548 | if (minneri-1 < minneri) minneri--;\r | |
2549 | }\r | |
2550 | Unexpected(10);\r | |
2551 | \r | |
2552 | Vprintf("%sMaximum %s = %ld (= 2**%d-1)%s\n",\r | |
2553 | co, INT, (long)int_max, ipower, oc);\r | |
2554 | Vprintf("%sMinimum %s = %ld%s\n", co, INT, (long)int_min, oc);\r | |
2555 | \r | |
2556 | if (L) i_define(D_INT_MAX, INT, Iname, "_MAX",\r | |
2557 | (long) int_max, 0L,\r | |
2558 | (long) I_MAX, IMARK);\r | |
2559 | if (L) i_define(D_INT_MIN, INT, Iname, "_MIN",\r | |
2560 | (long) int_min, (long) (PASS==1?maxint:int_max),\r | |
2561 | (long) I_MIN, IMARK);\r | |
2562 | \r | |
2563 | if(int_max < 0) { /* It has happened (on a Cray) */\r | |
2564 | eek_a_bug("signed integral comparison faulty?");\r | |
2565 | }\r | |
2566 | \r | |
2567 | if (maxeri>int_max) {\r | |
2568 | Vprintf("%sThere is a larger %s, %ld (= 2**%d-1), %s %s%s\n",\r | |
2569 | co, INT, (long)maxeri, ibits,\r | |
2570 | "but only for addition, not multiplication",\r | |
2571 | "(I smell a Cyber!)",\r | |
2572 | oc);\r | |
2573 | }\r | |
2574 | \r | |
2575 | if (minneri<int_min) {\r | |
2576 | Vprintf("%sThere is a smaller %s, %ld, %s %s%s\n",\r | |
2577 | co, INT, (long)minneri,\r | |
2578 | "but only for addition, not multiplication",\r | |
2579 | "(I smell a Cyber!)",\r | |
2580 | oc);\r | |
2581 | }\r | |
2582 | }\r | |
2583 | \r | |
2584 | Void UPROP ( void )\r | |
2585 | {\r | |
2586 | /* The properties of unsigned short/int/long */\r | |
2587 | #ifdef OK_UI\r | |
2588 | Volatile unsigned Integer u_max, newi, two;\r | |
2589 | newi=1; u_max=0; two=2;\r | |
2590 | \r | |
2591 | if (setjmp(lab)==0) { /* Yields u_max */\r | |
2592 | while(newi>u_max) {\r | |
2593 | u_max=newi;\r | |
2594 | newi=newi*two+1;\r | |
2595 | }\r | |
2596 | }\r | |
2597 | Unexpected(11);\r | |
2598 | Vprintf("%sMaximum unsigned %s = %lu%s\n",\r | |
2599 | co, INT, (unsigned long) u_max, oc);\r | |
2600 | \r | |
2601 | /* Oh woe: new standard C defines value preserving promotions:\r | |
2602 | 3.2.1.1: "If an int can represent all values of the original type,\r | |
2603 | the value is converted to an int;\r | |
2604 | otherwise it is converted to an unsigned int."\r | |
2605 | */\r | |
2606 | if (L) {\r | |
2607 | if (PASS == 1 /* we're dealing with short */\r | |
2608 | && u_max <= maxint /* an int can represent all values */\r | |
2609 | )\r | |
2610 | { /* the value is converted to an int */\r | |
2611 | i_define(D_UINT_MAX, INT, Uname, "_MAX",\r | |
2612 | (long) u_max, 0L,\r | |
2613 | (long) U_MAX, IMARK);\r | |
2614 | } else { /* it is converted to an unsigned int */\r | |
2615 | u_define(D_UINT_MAX, INT, Uname, "_MAX",\r | |
2616 | (unsigned long) u_max,\r | |
2617 | (unsigned long) U_MAX, IMARK);\r | |
2618 | }\r | |
2619 | }\r | |
2620 | #endif\r | |
2621 | }\r | |
2622 | \r | |
2623 | #endif /* Integer */\r | |
2624 | \r | |
2625 | #ifdef Number\r | |
2626 | \r | |
2627 | /* The following routines are intended to defeat any attempt at optimisation\r | |
2628 | or use of extended precision, and to defeat faulty narrowing casts.\r | |
2629 | The weird prototypes are because of widening incompatibilities.\r | |
2630 | */\r | |
2631 | #if defined(STDC) || defined(_MSC_VER)\r | |
2632 | #define ARGS1(A, a) (A a)\r | |
2633 | #define ARGS2(A, a, B, b) (A a, B b)\r | |
2634 | #define ARGS5(A, a, B, b, C, c, D, d, E, e) (A a, B b, C c, D d, E e)\r | |
2635 | #else\r | |
2636 | #define ARGS1(A, a) (a) A a;\r | |
2637 | #define ARGS2(A, a, B, b) (a, b) A a; B b;\r | |
2638 | #define ARGS5(A, a, B, b, C, c, D, d, E, e) (a,b,c,d,e)A a; B b; C c; D d; E e;\r | |
2639 | #endif\r | |
2640 | \r | |
2641 | Void Store ARGS2(Number, a, Number *, b) { *b=a; }\r | |
2642 | Number Sum ARGS2(Number, a, Number, b) {Number r; Store(a+b, &r); return r; }\r | |
2643 | Number Diff ARGS2(Number, a, Number, b){Number r; Store(a-b, &r); return r; }\r | |
2644 | Number Mul ARGS2(Number, a, Number, b) {Number r; Store(a*b, &r); return r; }\r | |
2645 | Number Div ARGS2(Number, a, Number, b) {Number r; Store(a/b, &r); return r; }\r | |
2646 | Number Self ARGS1(Number, a) {Number r; Store(a, &r); return r; }\r | |
2647 | \r | |
2648 | Void F_check ARGS((int precision, Long_double val1));\r | |
2649 | \r | |
2650 | Void F_check(int precision, Long_double val1)\r | |
2651 | {\r | |
2652 | /* You don't think I'm going to go to all the trouble of writing\r | |
2653 | a program that works out what all sorts of values are, only to\r | |
2654 | have printf go and print the wrong values out, do you?\r | |
2655 | No, you're right, so this function tries to see if printf\r | |
2656 | has written the right value, by reading it back again.\r | |
2657 | This introduces a new problem of course: suppose printf writes\r | |
2658 | the correct value, and scanf reads it back wrong... oh well.\r | |
2659 | But I'm adamant about this: the precision given is enough\r | |
2660 | to uniquely identify the printed number, therefore I insist\r | |
2661 | that sscanf read the number back identically. Harsh yes, but\r | |
2662 | sometimes you've got to be cruel to be kind.\r | |
2663 | */\r | |
2664 | Long_double new1, rem;\r | |
2665 | Number val, new, diff;\r | |
2666 | int e;\r | |
2667 | char *rep, *f2;\r | |
2668 | \r | |
2669 | if (sizeof(double) == sizeof(Long_double)) {\r | |
2670 | /* Assume they're the same, and use non-stdc format */\r | |
2671 | /* This is for stdc compilers using non-stdc libraries */\r | |
2672 | f2= "%le"; /* Input */\r | |
2673 | } else {\r | |
2674 | /* It had better support Le then */\r | |
2675 | f2= "%Le";\r | |
2676 | }\r | |
2677 | val= (Number) val1;\r | |
2678 | rep= f_rep(precision, (Long_double) val);\r | |
2679 | if (setjmp(lab)==0) {\r | |
2680 | sscanf(rep, f2, &new1);\r | |
2681 | } else {\r | |
2682 | eek_a_bug("sscanf caused a trap");\r | |
2683 | printf("%s scanning: %s format: %s%s\n\n", co, rep, f2, oc);\r | |
2684 | Unexpected(12);\r | |
2685 | return;\r | |
2686 | }\r | |
2687 | \r | |
2688 | if (setjmp(lab)==0) { /* See if new is usable */\r | |
2689 | new= new1;\r | |
2690 | if (new != 0.0) {\r | |
2691 | diff= val/new - 1.0;\r | |
2692 | if (diff < 0.1) diff= 1.0;\r | |
2693 | /* That should be enough to generate a trap */\r | |
2694 | }\r | |
2695 | } else {\r | |
2696 | eek_a_bug("sscanf returned an unusable number");\r | |
2697 | printf("%s scanning: %s with format: %s%s\n\n",\r | |
2698 | co, rep, f2, oc);\r | |
2699 | Unexpected(13);\r | |
2700 | return;\r | |
2701 | }\r | |
2702 | \r | |
2703 | Unexpected(14);\r | |
2704 | if (new != val) {\r | |
2705 | eek_a_bug("Possibly bad output from printf above");\r | |
2706 | if (!exponent((Long_double)val, &rem, &e)) {\r | |
2707 | printf("%s but value was an unusable number%s\n\n",\r | |
2708 | co, oc);\r | |
2709 | return;\r | |
2710 | }\r | |
2711 | printf("%s expected value around ", co);\r | |
2712 | //if (sizeof(double) == sizeof(Long_double)) {\r | |
2713 | /* Assume they're the same, and use non-stdc format */\r | |
2714 | /* This is for stdc compilers using non-stdc libraries */\r | |
2715 | //printf("%.*fe%d, bit pattern:\n ", precision, rem, e);\r | |
2716 | //} else {\r | |
2717 | /* It had better support Lfe then */\r | |
2718 | printf("%.*Lfe%d, bit pattern:\n ", precision, rem, e);\r | |
2719 | //}\r | |
2720 | bitpattern((char *) &val, (unsigned)sizeof(val));\r | |
2721 | printf ("%s\n", oc);\r | |
2722 | printf("%s sscanf gave %s, bit pattern:\n ",\r | |
2723 | co, f_rep(precision, (Long_double) new));\r | |
2724 | bitpattern((char *) &new, (unsigned)sizeof(new));\r | |
2725 | printf ("%s\n", oc);\r | |
2726 | if (setjmp(lab) == 0) {\r | |
2727 | diff= val-new;\r | |
2728 | printf("%s difference= %s%s\n\n",\r | |
2729 | co, f_rep(precision, (Long_double) diff), oc);\r | |
2730 | } /* else forget it */\r | |
2731 | Unexpected(15);\r | |
2732 | }\r | |
2733 | }\r | |
2734 | \r | |
2735 | #ifdef VERIFY\r | |
2736 | Void Verify ARGS5(int, prec, Number, val, Number, req, int, same, int, same1)\r | |
2737 | {\r | |
2738 | /* Check that the compiler has read a #define value correctly */\r | |
2739 | Unexpected(16);\r | |
2740 | if (!same) {\r | |
2741 | printf("%s*** Verify failed for above #define!\n", co);\r | |
2742 | if (setjmp(lab) == 0) { /* for the case that req == nan */\r | |
2743 | printf(" Compiler has %s for value\n",\r | |
2744 | f_rep(prec, req));\r | |
2745 | } else {\r | |
2746 | printf(" Compiler has %s for value\n",\r | |
2747 | "an unusable number");\r | |
2748 | }\r | |
2749 | if (setjmp(lab) == 0) {\r | |
2750 | F_check(prec, (Long_double) req);\r | |
2751 | } /*else forget it*/\r | |
2752 | if (setjmp(lab) == 0) {\r | |
2753 | if (req > 0.0 && val > 0.0) {\r | |
2754 | printf(" difference= %s\n",\r | |
2755 | f_rep(prec, val-req));\r | |
2756 | }\r | |
2757 | } /*else forget it*/\r | |
2758 | Unexpected(17);\r | |
2759 | printf("%s\n", oc);\r | |
2760 | bugs++;\r | |
2761 | } else if (!same1) {\r | |
2762 | if (stdc) eek_a_bug("constant has the wrong precision");\r | |
2763 | else eek_a_bug("the cast didn't work");\r | |
2764 | printf("\n");\r | |
2765 | }\r | |
2766 | }\r | |
2767 | #endif /* VERIFY */\r | |
2768 | \r | |
2769 | int FPROP(int byte_size)\r | |
2770 | {\r | |
2771 | /* Properties of floating types, using algorithms by Cody and Waite\r | |
2772 | from MA Malcolm, as modified by WM Gentleman and SB Marovich.\r | |
2773 | Further extended by S Pemberton.\r | |
2774 | \r | |
2775 | Returns the number of digits in the fraction.\r | |
2776 | */\r | |
2777 | \r | |
2778 | Volatile int\r | |
2779 | i, f_radix, iexp, irnd, mrnd, f_rounds, f_mant_dig,\r | |
2780 | iz, k, inf, machep, f_max_exp, f_min_exp, mx, negeps,\r | |
2781 | mantbits, digs, f_dig, trap,\r | |
2782 | hidden, normal, f_min_10_exp, f_max_10_exp;\r | |
2783 | Volatile Number\r | |
2784 | a, b, base, basein, basem1, f_epsilon, epsneg,\r | |
2785 | eps, epsp1, etop, ebot,\r | |
2786 | f_max, newxmax, f_min, xminner, y, y1, z, z1, z2;\r | |
2787 | \r | |
2788 | Unexpected(18);\r | |
2789 | \r | |
2790 | Vprintf("%sPROPERTIES OF %s%s\n", co, THING, oc);\r | |
2791 | \r | |
2792 | /* Base and size of significand **************************************/\r | |
2793 | /* First repeatedly double until adding 1 has no effect. */\r | |
2794 | /* For instance, if base is 10, with 3 significant digits */\r | |
2795 | /* it will try 1, 2, 4, 8, ... 512, 1024, and stop there, */\r | |
2796 | /* since 1024 is only representable as 1020. */\r | |
2797 | a=1.0;\r | |
2798 | if (setjmp(lab)==0) { /* inexact trap? */\r | |
2799 | do { a=Sum(a, a); }\r | |
2800 | while (Diff(Diff(Sum(a, ONE), a), ONE) == ZERO);\r | |
2801 | } else {\r | |
2802 | fprintf(stderr, "*** Program got loss-of-precision trap!\n");\r | |
2803 | /* And supporting those is just TOO much trouble! */\r | |
2804 | farewell(bugs+1);\r | |
2805 | }\r | |
2806 | Unexpected(19);\r | |
2807 | /* Now double until you find a number that can be added to the */\r | |
2808 | /* above number. For 1020 this is 8 or 16, depending whether the */\r | |
2809 | /* result is rounded or truncated. */\r | |
2810 | /* In either case the result is 1030. 1030-1020= the base, 10. */\r | |
2811 | b=1.0;\r | |
2812 | do { b=Sum(b, b); } while ((base=Diff(Sum(a, b), a)) == ZERO);\r | |
2813 | f_radix=base;\r | |
2814 | Vprintf("%sBase = %d%s\n", co, f_radix, oc);\r | |
2815 | \r | |
2816 | /* Sanity check; if base<2, I can't guarantee the rest will work */\r | |
2817 | if (f_radix < 2) {\r | |
2818 | eek_a_bug("Function return or parameter passing faulty? (This is a guess.)");\r | |
2819 | printf("\n");\r | |
2820 | return(0);\r | |
2821 | }\r | |
2822 | \r | |
2823 | if (PASS == 1) { /* only for FLT */\r | |
2824 | flt_radix= f_radix;\r | |
2825 | if (F) i_define(D_FLT_RADIX, "", "FLT", "_RADIX",\r | |
2826 | (long) f_radix, 0L, (long) F_RADIX, "");\r | |
2827 | } else if (f_radix != flt_radix) {\r | |
2828 | printf("\n%s*** WARNING: %s %s (%d) %s%s\n",\r | |
2829 | co, thing, "arithmetic has a different radix",\r | |
2830 | f_radix, "from float", oc);\r | |
2831 | bugs++;\r | |
2832 | }\r | |
2833 | \r | |
2834 | /* Now the number of digits precision */\r | |
2835 | f_mant_dig=0; b=1.0;\r | |
2836 | do { f_mant_dig++; b=Mul(b, base); }\r | |
2837 | while (Diff(Diff(Sum(b, ONE), b), ONE) == ZERO);\r | |
2838 | f_dig=floor_log(10, (Long_double)(b/base)) + (base==10?1:0);\r | |
2839 | Vprintf("%sSignificant base digits = %d %s %d %s%s\n",\r | |
2840 | co, f_mant_dig, "(= at least", f_dig, "decimal digits)", oc);\r | |
2841 | if (F) i_define(D_MANT_DIG, thing, Fname, "_MANT_DIG",\r | |
2842 | (long) f_mant_dig, 0L, (long) F_MANT_DIG, "");\r | |
2843 | if (F) i_define(D_DIG, thing, Fname, "_DIG",\r | |
2844 | (long) f_dig, 0L, (long) F_DIG, "");\r | |
2845 | digs= ceil_log(10, (Long_double)b); /* the number of digits to printf */\r | |
2846 | \r | |
2847 | /* Rounding *******************************************************/\r | |
2848 | basem1=Diff(base, HALF);\r | |
2849 | if (Diff(Sum(a, basem1), a) != ZERO) {\r | |
2850 | if (f_radix == 2) basem1=0.375;\r | |
2851 | else basem1=1.0;\r | |
2852 | if (Diff(Sum(a, basem1), a) != ZERO) irnd=2; /* away from 0 */\r | |
2853 | else irnd=1; /* to nearest */\r | |
2854 | } else irnd=0; /* towards 0 */\r | |
2855 | \r | |
2856 | basem1=Diff(base, HALF);\r | |
2857 | \r | |
2858 | if (Diff(Diff(-a, basem1), -a) != ZERO) {\r | |
2859 | if (f_radix == 2) basem1=0.375;\r | |
2860 | else basem1=1.0;\r | |
2861 | if (Diff(Diff(-a, basem1), -a) != ZERO) mrnd=2; /* away from 0*/\r | |
2862 | else mrnd=1; /* to nearest */\r | |
2863 | } else mrnd=0; /* towards 0 */\r | |
2864 | \r | |
2865 | f_rounds= -1; /* Unknown rounding */\r | |
2866 | if (irnd==0 && mrnd==0) f_rounds=0; /* zero = chops */\r | |
2867 | if (irnd==1 && mrnd==1) f_rounds=1; /* nearest */\r | |
2868 | if (irnd==2 && mrnd==0) f_rounds=2; /* +inf */\r | |
2869 | if (irnd==0 && mrnd==2) f_rounds=3; /* -inf */\r | |
2870 | \r | |
2871 | if (f_rounds != -1) {\r | |
2872 | Vprintf("%sArithmetic rounds towards ", co);\r | |
2873 | switch (f_rounds) {\r | |
2874 | case 0: Vprintf("zero (i.e. it chops)"); break;\r | |
2875 | case 1: Vprintf("nearest"); break;\r | |
2876 | case 2: Vprintf("+infinity"); break;\r | |
2877 | case 3: Vprintf("-infinity"); break;\r | |
2878 | default: Vprintf("???"); break;\r | |
2879 | }\r | |
2880 | Vprintf("%s\n", oc);\r | |
2881 | } else { /* Hmm, try to give some help here */\r | |
2882 | Vprintf("%sArithmetic rounds oddly: %s\n", co, oc);\r | |
2883 | Vprintf("%s Negative numbers %s%s\n",\r | |
2884 | co, mrnd==0 ? "towards zero" :\r | |
2885 | mrnd==1 ? "to nearest" :\r | |
2886 | "away from zero",\r | |
2887 | oc);\r | |
2888 | Vprintf("%s Positive numbers %s%s\n",\r | |
2889 | co, irnd==0 ? "towards zero" :\r | |
2890 | irnd==1 ? "to nearest" :\r | |
2891 | "away from zero",\r | |
2892 | oc);\r | |
2893 | }\r | |
2894 | /* An extra goody */\r | |
2895 | if (f_radix == 2 && f_rounds == 1) {\r | |
2896 | if (Diff(Sum(a, ONE), a) != ZERO) {\r | |
2897 | Vprintf("%s Tie breaking rounds up%s\n", co, oc);\r | |
2898 | } else if (Diff(Sum(a, THREE), a) == FOUR) {\r | |
2899 | Vprintf("%s Tie breaking rounds to even%s\n", co, oc);\r | |
2900 | } else {\r | |
2901 | Vprintf("%s Tie breaking rounds down%s\n", co, oc);\r | |
2902 | }\r | |
2903 | }\r | |
2904 | if (PASS == 1) { /* only for FLT */\r | |
2905 | flt_rounds= f_rounds;\r | |
2906 | if (F)\r | |
2907 | i_define(D_FLT_ROUNDS, "", "FLT", "_ROUNDS",\r | |
2908 | (long) f_rounds, 1L, (long) F_ROUNDS, "");\r | |
2909 | } else if (f_rounds != flt_rounds) {\r | |
2910 | printf("\n%s*** WARNING: %s %s (%d) %s%s\n\n",\r | |
2911 | co, thing, "arithmetic rounds differently",\r | |
2912 | f_rounds, "from float", oc);\r | |
2913 | bugs++;\r | |
2914 | }\r | |
2915 | \r | |
2916 | /* Various flavours of epsilon ************************************/\r | |
2917 | negeps=f_mant_dig+f_mant_dig;\r | |
2918 | basein=1.0/base;\r | |
2919 | a=1.0;\r | |
2920 | for(i=1; i<=negeps; i++) a*=basein;\r | |
2921 | \r | |
2922 | b=a;\r | |
2923 | while (Diff(Diff(ONE, a), ONE) == ZERO) {\r | |
2924 | a*=base;\r | |
2925 | negeps--;\r | |
2926 | }\r | |
2927 | negeps= -negeps;\r | |
2928 | Vprintf("%sSmallest x such that 1.0-base**x != 1.0 = %d%s\n",\r | |
2929 | co, negeps, oc);\r | |
2930 | \r | |
2931 | etop = ONE;\r | |
2932 | ebot = ZERO;\r | |
2933 | eps = Sum(ebot, Div(Diff(etop, ebot), TWO));\r | |
2934 | /* find the smallest epsneg (1-epsneg != 1) by binary search.\r | |
2935 | ebot and etop are the current bounds */\r | |
2936 | while (eps != ebot && eps != etop) {\r | |
2937 | epsp1 = Diff(ONE, eps);\r | |
2938 | if (epsp1 < ONE) etop = eps;\r | |
2939 | else ebot = eps;\r | |
2940 | eps = Sum(ebot, Div(Diff(etop, ebot), TWO));\r | |
2941 | }\r | |
2942 | eps= etop;\r | |
2943 | /* Sanity check */\r | |
2944 | if (Diff(ONE, etop) >= ONE || Diff(ONE, ebot) != ONE) {\r | |
2945 | eek_a_bug("internal error calculating epsneg");\r | |
2946 | }\r | |
2947 | Vprintf("%sSmallest x such that 1.0-x != 1.0 = %s%s\n",\r | |
2948 | co, f_rep(digs, (Long_double) eps), oc);\r | |
2949 | if (V) F_check(digs, (Long_double) eps);\r | |
2950 | \r | |
2951 | epsneg=a;\r | |
2952 | if ((f_radix!=2) && irnd) {\r | |
2953 | /* a=(a*(1.0+a))/(1.0+1.0); => */\r | |
2954 | a=Div(Mul(a, Sum(ONE, a)), Sum(ONE, ONE));\r | |
2955 | /* if ((1.0-a)-1.0 != 0.0) epsneg=a; => */\r | |
2956 | if (Diff(Diff(ONE, a), ONE) != ZERO) epsneg=a;\r | |
2957 | }\r | |
2958 | /* epsneg is used later */\r | |
2959 | Unexpected(20);\r | |
2960 | \r | |
2961 | machep= -f_mant_dig-f_mant_dig;\r | |
2962 | a=b;\r | |
2963 | while (Diff(Sum(ONE, a), ONE) == ZERO) { a*=base; machep++; }\r | |
2964 | Vprintf("%sSmallest x such that 1.0+base**x != 1.0 = %d%s\n",\r | |
2965 | co, machep, oc);\r | |
2966 | \r | |
2967 | etop = ONE;\r | |
2968 | ebot = ZERO;\r | |
2969 | eps = Sum(ebot, Div(Diff(etop, ebot), TWO));\r | |
2970 | /* find the smallest eps (1+eps != 1) by binary search.\r | |
2971 | ebot and etop are the current bounds */\r | |
2972 | while (eps != ebot && eps != etop) {\r | |
2973 | epsp1 = Sum(ONE, eps);\r | |
2974 | if (epsp1 > ONE) etop = eps;\r | |
2975 | else ebot = eps;\r | |
2976 | eps = Sum(ebot, Div(Diff(etop, ebot), TWO));\r | |
2977 | }\r | |
2978 | /* Sanity check */\r | |
2979 | if (Sum(ONE, etop) <= ONE || Sum(ONE, ebot) != ONE) {\r | |
2980 | eek_a_bug("internal error calculating eps");\r | |
2981 | }\r | |
2982 | f_epsilon=etop;\r | |
2983 | \r | |
2984 | Vprintf("%sSmallest x such that 1.0+x != 1.0 = %s%s\n",\r | |
2985 | co, f_rep(digs, (Long_double) f_epsilon), oc);\r | |
2986 | \r | |
2987 | f_epsilon= Diff(Sum(ONE, f_epsilon), ONE); /* New C standard defn */\r | |
2988 | Vprintf("%s(Above number + 1.0) - 1.0 = %s%s\n",\r | |
2989 | co, f_rep(digs, (Long_double) (f_epsilon)), oc);\r | |
2990 | \r | |
2991 | /* Possible loss of precision warnings here from non-stdc compilers */\r | |
2992 | if (F) f_define(D_EPSILON, thing,\r | |
2993 | Fname, "_EPSILON", digs, (Long_double) f_epsilon, MARK);\r | |
2994 | if (V || F) F_check(digs, (Long_double) f_epsilon);\r | |
2995 | Unexpected(21);\r | |
2996 | if (F) Verify(digs, f_epsilon, F_EPSILON,\r | |
2997 | f_epsilon == Self(F_EPSILON),\r | |
2998 | (Long_double) f_epsilon == (Long_double) F_EPSILON);\r | |
2999 | Unexpected(22);\r | |
3000 | \r | |
3001 | /* Extra chop info *************************************************/\r | |
3002 | if (f_rounds == 0) {\r | |
3003 | if (Diff(Mul(Sum(ONE,f_epsilon),ONE),ONE) != ZERO) {\r | |
3004 | Vprintf("%sAlthough arithmetic chops, it uses guard digits%s\n", co, oc);\r | |
3005 | }\r | |
3006 | }\r | |
3007 | \r | |
3008 | /* Size of and minimum normalised exponent ************************/\r | |
3009 | y=0; i=0; k=1; z=basein; z1=(1.0+f_epsilon)/base;\r | |
3010 | \r | |
3011 | /* Coarse search for the largest power of two */\r | |
3012 | if (setjmp(lab)==0) { /* for underflow trap */ /* Yields i, k, y, y1 */\r | |
3013 | do {\r | |
3014 | y=z; y1=z1;\r | |
3015 | z=Mul(y,y); z1=Mul(z1, y);\r | |
3016 | a=Mul(z,ONE);\r | |
3017 | z2=Div(z1,y);\r | |
3018 | if (z2 != y1) break;\r | |
3019 | if ((Sum(a,a) == ZERO) || (fabs(z) >= y)) break;\r | |
3020 | i++;\r | |
3021 | k+=k;\r | |
3022 | } while(1);\r | |
3023 | } else {\r | |
3024 | Vprintf("%s%s underflow generates a trap%s\n", co, Thing, oc);\r | |
3025 | }\r | |
3026 | Unexpected(23);\r | |
3027 | \r | |
3028 | if (f_radix != 10) {\r | |
3029 | iexp=i+1; /* for the sign */\r | |
3030 | mx=k+k;\r | |
3031 | } else {\r | |
3032 | iexp=2;\r | |
3033 | iz=f_radix;\r | |
3034 | while (k >= iz) { iz*=f_radix; iexp++; }\r | |
3035 | mx=iz+iz-1;\r | |
3036 | }\r | |
3037 | \r | |
3038 | /* Fine tune starting with y and y1 */\r | |
3039 | if (setjmp(lab)==0) { /* for underflow trap */ /* Yields k, f_min */\r | |
3040 | do {\r | |
3041 | f_min=y; z1=y1;\r | |
3042 | y=Div(y,base); y1=Div(y1,base);\r | |
3043 | a=Mul(y,ONE);\r | |
3044 | z2=Mul(y1,base);\r | |
3045 | if (z2 != z1) break;\r | |
3046 | if ((Sum(a,a) == ZERO) || (fabs(y) >= f_min)) break;\r | |
3047 | k++;\r | |
3048 | } while (1);\r | |
3049 | }\r | |
3050 | Unexpected(24);\r | |
3051 | \r | |
3052 | f_min_exp=(-k)+1;\r | |
3053 | \r | |
3054 | if ((mx <= k+k-3) && (f_radix != 10)) { mx+=mx; iexp+=1; }\r | |
3055 | Vprintf("%sNumber of bits used for exponent = %d%s\n", co, iexp, oc);\r | |
3056 | Vprintf("%sMinimum normalised exponent = %d%s\n", co, f_min_exp-1, oc);\r | |
3057 | if (F)\r | |
3058 | i_define(D_MIN_EXP, thing, Fname, "_MIN_EXP",\r | |
3059 | (long) f_min_exp, (long) maxint, (long) F_MIN_EXP, "");\r | |
3060 | \r | |
3061 | if (setjmp(lab)==0) {\r | |
3062 | Vprintf("%sMinimum normalised positive number = %s%s\n",\r | |
3063 | co, f_rep(digs, (Long_double) f_min), oc);\r | |
3064 | } else {\r | |
3065 | eek_a_bug("printf can't print the smallest normalised number");\r | |
3066 | printf("\n");\r | |
3067 | }\r | |
3068 | Unexpected(25);\r | |
3069 | /* Possible loss of precision warnings here from non-stdc compilers */\r | |
3070 | if (setjmp(lab) == 0) {\r | |
3071 | if (F) f_define(D_MIN, thing,\r | |
3072 | Fname, "_MIN", digs, (Long_double) f_min, MARK);\r | |
3073 | if (V || F) F_check(digs, (Long_double) f_min);\r | |
3074 | } else {\r | |
3075 | eek_a_bug("xxx_MIN caused a trap");\r | |
3076 | printf("\n");\r | |
3077 | }\r | |
3078 | \r | |
3079 | if (setjmp(lab) == 0) {\r | |
3080 | if (F) Verify(digs, f_min, F_MIN,\r | |
3081 | f_min == Self(F_MIN),\r | |
3082 | (Long_double) f_min == (Long_double) F_MIN);\r | |
3083 | } else {\r | |
3084 | printf("%s*** Verify failed for above #define!\n %s %s\n\n",\r | |
3085 | co, "Compiler has an unusable number for value", oc);\r | |
3086 | bugs++;\r | |
3087 | }\r | |
3088 | Unexpected(26);\r | |
3089 | \r | |
3090 | a=1.0; f_min_10_exp=0;\r | |
3091 | while (a > f_min*10.0) { a/=10.0; f_min_10_exp--; }\r | |
3092 | if (F) i_define(D_MIN_10_EXP, thing, Fname, "_MIN_10_EXP",\r | |
3093 | (long) f_min_10_exp, (long) maxint,\r | |
3094 | (long) F_MIN_10_EXP, "");\r | |
3095 | \r | |
3096 | /* Minimum exponent ************************************************/\r | |
3097 | if (setjmp(lab)==0) { /* for underflow trap */ /* Yields xminner */\r | |
3098 | do {\r | |
3099 | xminner=y;\r | |
3100 | y=Div(y,base);\r | |
3101 | a=Mul(y,ONE);\r | |
3102 | if ((Sum(a,a) == ZERO) || (fabs(y) >= xminner)) break;\r | |
3103 | } while (1);\r | |
3104 | }\r | |
3105 | Unexpected(27);\r | |
3106 | \r | |
3107 | if (xminner != 0.0 && xminner != f_min) {\r | |
3108 | normal= 0;\r | |
3109 | Vprintf("%sThe smallest numbers are not kept normalised%s\n",\r | |
3110 | co, oc);\r | |
3111 | if (setjmp(lab)==0) {\r | |
3112 | Vprintf("%sSmallest unnormalised positive number = %s%s\n",\r | |
3113 | co, f_rep(digs, (Long_double) xminner), oc);\r | |
3114 | if (V) F_check(digs, (Long_double) xminner);\r | |
3115 | } else {\r | |
3116 | eek_a_bug("printf can't print the smallest unnormalised number.");\r | |
3117 | printf("\n");\r | |
3118 | }\r | |
3119 | Unexpected(28);\r | |
3120 | } else {\r | |
3121 | normal= 1;\r | |
3122 | Vprintf("%sThe smallest numbers are normalised%s\n", co, oc);\r | |
3123 | }\r | |
3124 | \r | |
3125 | /* Maximum exponent ************************************************/\r | |
3126 | f_max_exp=2; f_max=1.0; newxmax=base+1.0;\r | |
3127 | inf=0; trap=0;\r | |
3128 | while (f_max<newxmax) {\r | |
3129 | f_max=newxmax;\r | |
3130 | if (setjmp(lab) == 0) { /* Yields inf, f_max_exp */\r | |
3131 | newxmax=Mul(newxmax, base);\r | |
3132 | } else {\r | |
3133 | trap=1;\r | |
3134 | break;\r | |
3135 | }\r | |
3136 | if (Div(newxmax, base) != f_max) {\r | |
3137 | if (newxmax > f_max) inf=1; /* ieee infinity */\r | |
3138 | break;\r | |
3139 | }\r | |
3140 | f_max_exp++;\r | |
3141 | }\r | |
3142 | Unexpected(29);\r | |
3143 | Vprintf("%sMaximum exponent = %d%s\n", co, f_max_exp, oc);\r | |
3144 | if (F) i_define(D_MAX_EXP, thing, Fname, "_MAX_EXP",\r | |
3145 | (long) f_max_exp, 0L, (long) F_MAX_EXP, "");\r | |
3146 | \r | |
3147 | /* Largest number ***************************************************/\r | |
3148 | f_max=Diff(ONE, epsneg);\r | |
3149 | if (Mul(f_max,ONE) != f_max) f_max=Diff(ONE, Mul(base,epsneg));\r | |
3150 | for (i=1; i<=f_max_exp; i++) f_max=Mul(f_max, base);\r | |
3151 | \r | |
3152 | if (setjmp(lab)==0) {\r | |
3153 | Vprintf("%sMaximum number = %s%s\n",\r | |
3154 | co, f_rep(digs, (Long_double) f_max), oc);\r | |
3155 | } else {\r | |
3156 | eek_a_bug("printf can't print the largest double.");\r | |
3157 | printf("\n");\r | |
3158 | }\r | |
3159 | if (setjmp(lab)==0) {\r | |
3160 | /* Possible loss of precision warnings here from non-stdc compilers */\r | |
3161 | if (F) f_define(D_MAX, thing,\r | |
3162 | Fname, "_MAX", digs, (Long_double) f_max, MARK);\r | |
3163 | if (V || F) F_check(digs, (Long_double) f_max);\r | |
3164 | } else {\r | |
3165 | eek_a_bug("xxx_MAX caused a trap");\r | |
3166 | printf("\n");\r | |
3167 | }\r | |
3168 | if (setjmp(lab)==0) {\r | |
3169 | if (F) Verify(digs, f_max, F_MAX,\r | |
3170 | f_max == Self(F_MAX),\r | |
3171 | (Long_double) f_max == (Long_double) F_MAX);\r | |
3172 | } else {\r | |
3173 | printf("%s*** Verify failed for above #define!\n %s %s\n\n",\r | |
3174 | co, "Compiler has an unusable number for value", oc);\r | |
3175 | bugs++;\r | |
3176 | }\r | |
3177 | Unexpected(30);\r | |
3178 | \r | |
3179 | a=1.0; f_max_10_exp=0;\r | |
3180 | while (a < f_max/10.0) { a*=10.0; f_max_10_exp++; }\r | |
3181 | if (F) i_define(D_MAX_10_EXP, thing, Fname, "_MAX_10_EXP",\r | |
3182 | (long) f_max_10_exp, 0L, (long) F_MAX_10_EXP, "");\r | |
3183 | \r | |
3184 | /* Traps and infinities ********************************************/\r | |
3185 | if (trap) {\r | |
3186 | Vprintf("%sOverflow generates a trap%s\n", co, oc);\r | |
3187 | } else {\r | |
3188 | Vprintf("%sOverflow doesn't seem to generate a trap%s\n",\r | |
3189 | co, oc);\r | |
3190 | }\r | |
3191 | \r | |
3192 | if (inf) { Vprintf("%sThere is an 'infinite' value%s\n", co, oc); }\r | |
3193 | \r | |
3194 | #ifdef SIGFPE\r | |
3195 | signal(SIGFPE, trap1);\r | |
3196 | #endif\r | |
3197 | if (setjmp(lab) == 0) {\r | |
3198 | trapped= 0; /* A global variable */\r | |
3199 | b= 0.0;\r | |
3200 | a= (1.0/b)/b;\r | |
3201 | if (!trapped) {\r | |
3202 | Vprintf("%sDivide by zero doesn't generate a trap%s\n",\r | |
3203 | co, oc);\r | |
3204 | } else {\r | |
3205 | Vprintf("%sDivide by zero generates a trap%s\n",\r | |
3206 | co, oc);\r | |
3207 | Vprintf("%sFP signal handlers return safely%s\n",\r | |
3208 | co, oc);\r | |
3209 | }\r | |
3210 | } else {\r | |
3211 | Vprintf("%sDivide by zero generates a trap%s\n", co, oc);\r | |
3212 | Vprintf("%sBEWARE! FP signal handlers can NOT return%s\n",\r | |
3213 | co, oc);\r | |
3214 | }\r | |
3215 | setsignals();\r | |
3216 | Unexpected(31);\r | |
3217 | \r | |
3218 | /* Hidden bit + sanity check ****************************************/\r | |
3219 | if (f_radix != 10) {\r | |
3220 | hidden=0;\r | |
3221 | mantbits=floor_log(2, (Long_double)f_radix)*f_mant_dig;\r | |
3222 | if (mantbits+iexp == (int)sizeof(Number)*byte_size) {\r | |
3223 | hidden=1;\r | |
3224 | Vprintf("%sArithmetic uses a hidden bit%s\n", co, oc);\r | |
3225 | } else if (mantbits+iexp+1 == (int)sizeof(Number)*byte_size) {\r | |
3226 | Vprintf("%sArithmetic doesn't use a hidden bit%s\n",\r | |
3227 | co, oc);\r | |
3228 | } else if (mantbits+iexp+1 < (int)sizeof(Number)*byte_size) {\r | |
3229 | Vprintf("%sOnly %d of the %d bits of a %s %s%s\n",\r | |
3230 | co,\r | |
3231 | mantbits+iexp,\r | |
3232 | (int)sizeof(Number)*byte_size,\r | |
3233 | thing,\r | |
3234 | "are actually used",\r | |
3235 | oc);\r | |
3236 | } else {\r | |
3237 | printf("\n%s%s\n %s (%d) %s (%d) %s %s (%d)!%s\n\n",\r | |
3238 | co,\r | |
3239 | "*** Something fishy here!",\r | |
3240 | "Exponent size",\r | |
3241 | iexp,\r | |
3242 | "+ significand size",\r | |
3243 | mantbits,\r | |
3244 | "doesn't match with the size of a",\r | |
3245 | thing,\r | |
3246 | (int)sizeof(Number)*byte_size,\r | |
3247 | oc);\r | |
3248 | }\r | |
3249 | if (hidden && f_radix == 2 && f_max_exp+f_min_exp==3) {\r | |
3250 | Vprintf("%sIt looks like %s length IEEE format%s\n",\r | |
3251 | co, f_mant_dig==24 ? "single" :\r | |
3252 | f_mant_dig==53 ? "double" :\r | |
3253 | f_mant_dig >53 ? "extended" :\r | |
3254 | "some", oc);\r | |
3255 | if (f_rounds != 1 || normal) {\r | |
3256 | Vprintf("%s though ", co);\r | |
3257 | if (f_rounds != 1) {\r | |
3258 | Vprintf("the rounding is unusual");\r | |
3259 | if (normal) { Vprintf(" and "); }\r | |
3260 | }\r | |
3261 | if (normal) {\r | |
3262 | Vprintf("the normalisation is unusual");\r | |
3263 | }\r | |
3264 | Vprintf("%s\n", oc);\r | |
3265 | }\r | |
3266 | } else {\r | |
3267 | Vprintf("%sIt doesn't look like IEEE format%s\n",\r | |
3268 | co, oc);\r | |
3269 | }\r | |
3270 | }\r | |
3271 | printf("\n"); /* regardless of verbosity */\r | |
3272 | return f_mant_dig;\r | |
3273 | }\r | |
3274 | \r | |
3275 | Void EPROP(int fprec, int dprec, int lprec)\r | |
3276 | {\r | |
3277 | /* See if expressions are evaluated in extended precision.\r | |
3278 | Some compilers optimise even if you don't want it,\r | |
3279 | and then this function fails to produce the right result.\r | |
3280 | We try to diagnose this if it happens.\r | |
3281 | */\r | |
3282 | Volatile int eprec;\r | |
3283 | Volatile double a, b, base, old;\r | |
3284 | Volatile Number d, oldd, dbase, one, zero;\r | |
3285 | Volatile int bad=0;\r | |
3286 | \r | |
3287 | /* Size of significand **************************************/\r | |
3288 | a=1.0;\r | |
3289 | if (setjmp(lab) == 0) { /* Yields nothing */\r | |
3290 | do { old=a; a=a+a; }\r | |
3291 | while ((((a+1.0)-a)-1.0) == 0.0 && a>old);\r | |
3292 | } else bad=1;\r | |
3293 | if (!bad && a <= old) bad=1;\r | |
3294 | \r | |
3295 | if (!bad) {\r | |
3296 | b=1.0;\r | |
3297 | if (setjmp(lab) == 0) { /* Yields nothing */\r | |
3298 | do { old=b; b=b+b; }\r | |
3299 | while ((base=((a+b)-a)) == 0.0 && b>old);\r | |
3300 | if (b <= old) bad=1;\r | |
3301 | } else bad=1;\r | |
3302 | }\r | |
3303 | \r | |
3304 | if (!bad) {\r | |
3305 | eprec=0; d=1.0; dbase=base; one=1.0; zero=0.0;\r | |
3306 | if (setjmp(lab) == 0) { /* Yields nothing */\r | |
3307 | do { eprec++; oldd=d; d=d*dbase; }\r | |
3308 | while ((((d+one)-d)-one) == zero && d>oldd);\r | |
3309 | if (d <= oldd) bad=1;\r | |
3310 | } else bad=1;\r | |
3311 | }\r | |
3312 | \r | |
3313 | Unexpected(32);\r | |
3314 | \r | |
3315 | if (bad) {\r | |
3316 | Vprintf("%sCan't determine precision for %s expressions:\n%s%s\n",\r | |
3317 | co, thing, " check that you compiled without optimisation!",\r | |
3318 | oc);\r | |
3319 | } else if (eprec==dprec) {\r | |
3320 | Vprintf("%s%s expressions are evaluated in double precision%s\n",\r | |
3321 | co, Thing, oc);\r | |
3322 | } else if (eprec==fprec) {\r | |
3323 | Vprintf("%s%s expressions are evaluated in float precision%s\n",\r | |
3324 | co, Thing, oc);\r | |
3325 | } else if (eprec==lprec) {\r | |
3326 | Vprintf("%s%s expressions are evaluated in long double precision%s\n",\r | |
3327 | co, Thing, oc);\r | |
3328 | } else {\r | |
3329 | Vprintf("%s%s expressions are evaluated in a %s %s %d %s%s\n",\r | |
3330 | co, Thing, eprec>dprec ? "higher" : "lower",\r | |
3331 | "precision than double,\n using",\r | |
3332 | eprec, "base digits",\r | |
3333 | oc);\r | |
3334 | }\r | |
3335 | }\r | |
3336 | \r | |
3337 | #else /* not Number */\r | |
3338 | \r | |
3339 | #ifdef FPROP /* Then create dummy routines for long double */\r | |
3340 | /* ARGSUSED */\r | |
3341 | int FPROP(int byte_size) { return 0; }\r | |
3342 | #endif\r | |
3343 | #ifdef EPROP\r | |
3344 | /* ARGSUSED */\r | |
3345 | Void EPROP(int fprec, int dprec, int lprec) {}\r | |
3346 | #endif\r | |
3347 | \r | |
3348 | #endif /* ifdef Number */\r | |
3349 | \r | |
3350 | /* Increment the pass number */\r | |
3351 | #undef PASS\r | |
3352 | \r | |
3353 | #ifdef PASS2\r | |
3354 | #undef PASS2\r | |
3355 | #define PASS 3\r | |
3356 | #define PASS3 1\r | |
3357 | #endif\r | |
3358 | \r | |
3359 | #ifdef PASS1\r | |
3360 | #undef PASS1\r | |
3361 | #define PASS 2\r | |
3362 | #define PASS2 1\r | |
3363 | #endif\r | |
3364 | \r | |
3365 | #ifdef PASS0\r | |
3366 | #undef PASS0\r | |
3367 | #endif\r | |
3368 | \r | |
3369 | #ifndef SEP\r | |
3370 | #ifdef PASS /* then rescan this file */\r | |
3371 | #ifdef BAD_CPP\r | |
3372 | #include "enquire.c"\r | |
3373 | #else\r | |
3374 | #include FILENAME /* if this line fails to compile, define BAD_CPP */\r | |
3375 | #endif\r | |
3376 | #endif /* PASS */\r | |
3377 | #endif /* SEP */\r |