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