|
|
1.1 root 1: #undef V9
2: #define NOPAUSE
3: /* A C version of Kahan's Floating Point Test "Paranoia"
4:
5: Thos Sumner, UCSF, Feb. 1985
6: David Gay, BTL, Jan. 1986
7:
8: This is a rewrite from the Pascal version by
9:
10: B. A. Wichmann, 18 Jan. 1985
11:
12: (and does NOT exhibit good C programming style).
13:
14: (C) Apr 19 1983 in BASIC version by:
15: Professor W. M. Kahan,
16: 567 Evans Hall
17: Electrical Engineering & Computer Science Dept.
18: University of California
19: Berkeley, California 94720
20: USA
21:
22: converted to Pascal by:
23: B. A. Wichmann
24: National Physical Laboratory
25: Teddington Middx
26: TW11 OLW
27: UK
28:
29: converted to C by:
30:
31: David M. Gay and Thos Sumner
32: AT&T Bell Labs Computer Center, Rm. U-76
33: 600 Mountain Avenue University of California
34: Murray Hill, NJ 07974 San Francisco, CA 94143
35: USA USA
36:
37: with simultaneous corrections to the Pascal source (reflected
38: in the Pascal source available over netlib).
39: [A couple of bug fixes from dgh = sun!dhough incorporated 31 July 1986.]
40:
41: Reports of results on various systems from all the versions
42: of Paranoia are being collected by Richard Karpinski at the
43: same address as Thos Sumner. This includes sample outputs,
44: bug reports, and criticisms.
45:
46: You may copy this program freely if you acknowledge its source.
47: Comments on the Pascal version to NPL, please.
48:
49:
50: The C version catches signals from floating-point exceptions.
51: If signal(SIGFPE,...) is unavailable in your environment, you may
52: #define NOSIGNAL to comment out the invocations of signal.
53:
54: This source file is too big for some C compilers, but may be split
55: into pieces. Comments containing "SPLIT" suggest convenient places
56: for this splitting. At the end of these comments is an "ed script"
57: (for the UNIX(tm) editor ed) that will do this splitting.
58:
59: By #defining Single when you compile this source, you may obtain
60: a single-precision C version of Paranoia.
61:
62:
63: The following is from the introductory commentary from Wichmann's work:
64:
65: The BASIC program of Kahan is written in Microsoft BASIC using many
66: facilities which have no exact analogy in Pascal. The Pascal
67: version below cannot therefore be exactly the same. Rather than be
68: a minimal transcription of the BASIC program, the Pascal coding
69: follows the conventional style of block-structured languages. Hence
70: the Pascal version could be useful in producing versions in other
71: structured languages.
72:
73: Rather than use identifiers of minimal length (which therefore have
74: little mnemonic significance), the Pascal version uses meaningful
75: identifiers as follows [Note: A few changes have been made for C]:
76:
77:
78: BASIC C BASIC C BASIC C
79:
80: A J S StickyBit
81: A1 AInverse J0 NoErrors T
82: B Radix [Failure] T0 Underflow
83: B1 BInverse J1 NoErrors T2 ThirtyTwo
84: B2 RadixD2 [SeriousDefect] T5 OneAndHalf
85: B9 BMinusU2 J2 NoErrors T7 TwentySeven
86: C [Defect] T8 TwoForty
87: C1 CInverse J3 NoErrors U OneUlp
88: D [Flaw] U0 UnderflowThreshold
89: D4 FourD K PageNo U1
90: E0 L Milestone U2
91: E1 M V
92: E2 Exp2 N V0
93: E3 N1 V8
94: E5 MinSqEr O Zero V9
95: E6 SqEr O1 One W
96: E7 MaxSqEr O2 Two X
97: E8 O3 Three X1
98: E9 O4 Four X8
99: F1 MinusOne O5 Five X9 Random1
100: F2 Half O8 Eight Y
101: F3 Third O9 Nine Y1
102: F6 P Precision Y2
103: F9 Q Y9 Random2
104: G1 GMult Q8 Z
105: G2 GDiv Q9 Z0 PseudoZero
106: G3 GAddSub R Z1
107: H R1 RMult Z2
108: H1 HInverse R2 RDiv Z9
109: I R3 RAddSub
110: IO NoTrials R4 RSqrt
111: I3 IEEE R9 Random9
112:
113: SqRWrng
114:
115: All the variables in BASIC are true variables and in consequence,
116: the program is more difficult to follow since the "constants" must
117: be determined (the glossary is very helpful). The Pascal version
118: uses Real constants, but checks are added to ensure that the values
119: are correctly converted by the compiler.
120:
121: The major textual change to the Pascal version apart from the
122: identifiersis that named procedures are used, inserting parameters
123: wherehelpful. New procedures are also introduced. The
124: correspondence is as follows:
125:
126:
127: BASIC Pascal
128: lines
129:
130: 90- 140 Pause
131: 170- 250 Instructions
132: 380- 460 Heading
133: 480- 670 Characteristics
134: 690- 870 History
135: 2940-2950 Random
136: 3710-3740 NewD
137: 4040-4080 DoesYequalX
138: 4090-4110 PrintIfNPositive
139: 4640-4850 TestPartialUnderflow
140:
141: =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
142:
143: Below is an "ed script" that splits para.c into 10 files
144: of the form part[1-8].c, subs.c, and msgs.c, plus a header
145: file, paranoia.h, that these files require.
146:
147: r paranoia.c
148: $
149: ?SPLIT
150: +,$w msgs.c
151: .,$d
152: ?SPLIT
153: .d
154: +d
155: -,$w subs.c
156: -,$d
157: ?part8
158: +d
159: ?include
160: .,$w part8.c
161: .,$d
162: -d
163: ?part7
164: +d
165: ?include
166: .,$w part7.c
167: .,$d
168: -d
169: ?part6
170: +d
171: ?include
172: .,$w part6.c
173: .,$d
174: -d
175: ?part5
176: +d
177: ?include
178: .,$w part5.c
179: .,$d
180: -d
181: ?part4
182: +d
183: ?include
184: .,$w part4.c
185: .,$d
186: -d
187: ?part3
188: +d
189: ?include
190: .,$w part3.c
191: .,$d
192: -d
193: ?part2
194: +d
195: ?include
196: .,$w part2.c
197: .,$d
198: ?SPLIT
199: .d
200: 1,/^#include/-1d
201: 1,$w part1.c
202: /Computed constants/,$d
203: 1,$s/^int/extern &/
204: 1,$s/^FLOAT/extern &/
205: 1,$s/^char/extern &/
206: 1,$s! = .*!;!
207: /^Guard/,/^Round/s/^/extern /
208: /^jmp_buf/s/^/extern /
209: /^Sig_type/s/^/extern /
210: s/$/\
211: extern void sigfpe();/
212: w paranoia.h
213: q
214:
215: */
216:
217: #include <stdio.h>
218: #ifndef NOSIGNAL
219: #include <signal.h>
220: #endif
221: #include <setjmp.h>
222:
223: extern double fabs(), floor(), log(), pow(), sqrt();
224:
225: #ifdef Single
226: #define FLOAT float
227: #define FABS(x) (float)fabs((double)(x))
228: #define FLOOR(x) (float)floor((double)(x))
229: #define LOG(x) (float)log((double)(x))
230: #define POW(x,y) (float)pow((double)(x),(double)(y))
231: #define SQRT(x) (float)sqrt((double)(x))
232: #else
233: #define FLOAT double
234: #define FABS(x) fabs(x)
235: #define FLOOR(x) floor(x)
236: #define LOG(x) log(x)
237: #define POW(x,y) pow(x,y)
238: #define SQRT(x) sqrt(x)
239: #endif
240:
241: jmp_buf ovfl_buf;
242: typedef void (*Sig_type)();
243: Sig_type sigsave;
244:
245: #define KEYBOARD 0
246:
247: FLOAT Radix, BInvrse, RadixD2, BMinusU2;
248: FLOAT Sign(), Random();
249:
250: /*Small floating point constants.*/
251: FLOAT Zero = 0.0;
252: FLOAT Half = 0.5;
253: FLOAT One = 1.0;
254: FLOAT Two = 2.0;
255: FLOAT Three = 3.0;
256: FLOAT Four = 4.0;
257: FLOAT Five = 5.0;
258: FLOAT Eight = 8.0;
259: FLOAT Nine = 9.0;
260: FLOAT TwentySeven = 27.0;
261: FLOAT ThirtyTwo = 32.0;
262: FLOAT TwoForty = 240.0;
263: FLOAT MinusOne = -1.0;
264: FLOAT OneAndHalf = 1.5;
265: /*Integer constants*/
266: int NoTrials = 20; /*Number of tests for commutativity. */
267: #define False 0
268: #define True 1
269:
270: /* Definitions for declared types
271: Guard == (Yes, No);
272: Rounding == (Chopped, Rounded, Other);
273: Message == packed array [1..40] of char;
274: Class == (Flaw, Defect, Serious, Failure);
275: */
276: #define Yes 1
277: #define No 0
278: #define Chopped 2
279: #define Rounded 1
280: #define Other 0
281: #define Flaw 3
282: #define Defect 2
283: #define Serious 1
284: #define Failure 0
285: typedef int Guard, Rounding, Class;
286: typedef char Message;
287:
288: /* Declarations of Variables */
289: int Indx;
290: char ch[8];
291: FLOAT AInvrse, A1;
292: FLOAT C, CInvrse;
293: FLOAT D, FourD;
294: FLOAT E0, E1, Exp2, E3, MinSqEr;
295: FLOAT SqEr, MaxSqEr, E9;
296: FLOAT Third;
297: FLOAT F6, F9;
298: FLOAT H, HInvrse;
299: int I;
300: FLOAT StickyBit, J;
301: FLOAT MyZero;
302: FLOAT Precision;
303: FLOAT Q, Q9;
304: FLOAT R, Random9;
305: FLOAT T, Underflow, S;
306: FLOAT OneUlp, UfThold, U1, U2;
307: FLOAT V, V0, V9;
308: FLOAT W;
309: FLOAT X, X1, X2, X8, Random1;
310: FLOAT Y, Y1, Y2, Random2;
311: FLOAT Z, PseudoZero, Z1, Z2, Z9;
312: int ErrCnt[4];
313: int fpecount;
314: int Milestone;
315: int PageNo;
316: int M, N, N1;
317: Guard GMult, GDiv, GAddSub;
318: Rounding RMult, RDiv, RAddSub, RSqrt;
319: int Break, Done, NotMonot, Monot, Anomaly, IEEE,
320: SqRWrng, UfNGrad;
321: /* Computed constants. */
322: /*U1 gap below 1.0, i.e, 1.0-U1 is next number below 1.0 */
323: /*U2 gap above 1.0, i.e, 1.0+U2 is next number above 1.0 */
324:
325: /* floating point exception receiver */
326: void
327: sigfpe(i)
328: {
329: fpecount++;
330: printf("\n* * * FLOATING-POINT ERROR * * *\n");
331: fflush(stdout);
332: if (sigsave) {
333: #ifndef NOSIGNAL
334: signal(SIGFPE, sigsave);
335: #endif
336: sigsave = 0;
337: longjmp(ovfl_buf, 1);
338: }
339: abort();
340: }
341:
342: main()
343: {
344: #ifdef mc
345: char *out;
346: ieee_flags("set", "precision", "double", &out);
347: #endif
348: /* First two assignments use integer right-hand sides. */
349: Zero = 0;
350: One = 1;
351: Two = One + One;
352: Three = Two + One;
353: Four = Three + One;
354: Five = Four + One;
355: Eight = Four + Four;
356: Nine = Three * Three;
357: TwentySeven = Nine * Three;
358: ThirtyTwo = Four * Eight;
359: TwoForty = Four * Five * Three * Four;
360: MinusOne = -One;
361: Half = One / Two;
362: OneAndHalf = One + Half;
363: ErrCnt[Failure] = 0;
364: ErrCnt[Serious] = 0;
365: ErrCnt[Defect] = 0;
366: ErrCnt[Flaw] = 0;
367: PageNo = 1;
368: /*=============================================*/
369: Milestone = 0;
370: /*=============================================*/
371: #ifndef NOSIGNAL
372: signal(SIGFPE, sigfpe);
373: #endif
374: Instructions();
375: Pause();
376: Heading();
377: Pause();
378: Characteristics();
379: Pause();
380: History();
381: Pause();
382: /*=============================================*/
383: Milestone = 7;
384: /*=============================================*/
385: printf("Program is now RUNNING tests on small integers:\n");
386:
387: TstCond (Failure, (Zero + Zero == Zero) && (One - One == Zero)
388: && (One > Zero) && (One + One == Two),
389: "0+0 != 0, 1-1 != 0, 1 <= 0, or 1+1 != 2");
390: Z = - Zero;
391: if (Z != 0.0) {
392: ErrCnt[Failure] = ErrCnt[Failure] + 1;
393: printf("Comparison alleges that -0.0 is Non-zero!\n");
394: U1 = 0.001;
395: Radix = 1;
396: TstPtUf();
397: }
398: TstCond (Failure, (Three == Two + One) && (Four == Three + One)
399: && (Four + Two * (- Two) == Zero)
400: && (Four - Three - One == Zero),
401: "3 != 2+1, 4 != 3+1, 4+2*(-2) != 0, or 4-3-1 != 0");
402: TstCond (Failure, (MinusOne == (0 - One))
403: && (MinusOne + One == Zero ) && (One + MinusOne == Zero)
404: && (MinusOne + FABS(One) == Zero)
405: && (MinusOne + MinusOne * MinusOne == Zero),
406: "-1+1 != 0, (-1)+abs(1) != 0, or -1+(-1)*(-1) != 0");
407: TstCond (Failure, Half + MinusOne + Half == Zero,
408: "1/2 + (-1) + 1/2 != 0");
409: /*=============================================*/
410: /*SPLIT
411: part2();
412: part3();
413: part4();
414: part5();
415: part6();
416: part7();
417: part8();
418: }
419: #include "paranoia.h"
420: part2(){
421: */
422: Milestone = 10;
423: /*=============================================*/
424: TstCond (Failure, (Nine == Three * Three)
425: && (TwentySeven == Nine * Three) && (Eight == Four + Four)
426: && (ThirtyTwo == Eight * Four)
427: && (ThirtyTwo - TwentySeven - Four - One == Zero),
428: "9 != 3*3, 27 != 9*3, 32 != 8*4, or 32-27-4-1 != 0");
429: TstCond (Failure, (Five == Four + One) &&
430: (TwoForty == Four * Five * Three * Four)
431: && (TwoForty / Three - Four * Four * Five == Zero)
432: && ( TwoForty / Four - Five * Three * Four == Zero)
433: && ( TwoForty / Five - Four * Three * Four == Zero),
434: "5 != 4+1, 240/3 != 80, 240/4 != 60, or 240/5 != 48");
435: if (ErrCnt[Failure] == 0) {
436: printf("-1, 0, 1/2, 1, 2, 3, 4, 5, 9, 27, 32 & 240 are O.K.\n");
437: printf("\n");
438: }
439: printf("Searching for Radix and Precision.\n");
440: W = One;
441: do {
442: W = W + W;
443: Y = W + One;
444: Z = Y - W;
445: Y = Z - One;
446: } while (MinusOne + FABS(Y) < Zero);
447: /*.. now W is just big enough that |((W+1)-W)-1| >= 1 ...*/
448: Precision = Zero;
449: Y = One;
450: do {
451: Radix = W + Y;
452: Y = Y + Y;
453: Radix = Radix - W;
454: } while ( Radix == Zero);
455: if (Radix < Two) Radix = One;
456: printf("Radix = %f .\n", Radix);
457: if (Radix != 1) {
458: W = One;
459: do {
460: Precision = Precision + One;
461: W = W * Radix;
462: Y = W + One;
463: } while ((Y - W) == One);
464: }
465: /*... now W == Radix^Precision is barely too big to satisfy (W+1)-W == 1
466: ...*/
467: U1 = One / W;
468: U2 = Radix * U1;
469: printf("Closest relative separation found is U1 = %.7e .\n\n", U1);
470: printf("Recalculating radix and precision\n ");
471:
472: /*save old values*/
473: E0 = Radix;
474: E1 = U1;
475: E9 = U2;
476: E3 = Precision;
477:
478: X = Four / Three;
479: Third = X - One;
480: F6 = Half - Third;
481: X = F6 + F6;
482: X = FABS(X - Third);
483: if (X < U2) X = U2;
484:
485: /*... now X = (unknown no.) ulps of 1+...*/
486: do {
487: U2 = X;
488: Y = Half * U2 + ThirtyTwo * U2 * U2;
489: Y = One + Y;
490: X = Y - One;
491: } while ( ! ((U2 <= X) || (X <= Zero)));
492:
493: /*... now U2 == 1 ulp of 1 + ... */
494: X = Two / Three;
495: F6 = X - Half;
496: Third = F6 + F6;
497: X = Third - Half;
498: X = FABS(X + F6);
499: if (X < U1) X = U1;
500:
501: /*... now X == (unknown no.) ulps of 1 -... */
502: do {
503: U1 = X;
504: Y = Half * U1 + ThirtyTwo * U1 * U1;
505: Y = Half - Y;
506: X = Half + Y;
507: Y = Half - X;
508: X = Half + Y;
509: } while ( ! ((U1 <= X) || (X <= Zero)));
510: /*... now U1 == 1 ulp of 1 - ... */
511: if (U1 == E1) printf("confirms closest relative separation U1 .\n");
512: else printf("gets better closest relative separation U1 = %.7e .\n", U1);
513: W = One / U1;
514: F9 = (Half - U1) + Half;
515: Radix = FLOOR(0.01 + U2 / U1);
516: if (Radix == E0) printf("Radix confirmed.\n");
517: else printf("MYSTERY: recalculated Radix = %.7e .\n", Radix);
518: TstCond (Defect, Radix <= Eight + Eight,
519: "Radix is too big: roundoff problems");
520: TstCond (Flaw, (Radix == Two) || (Radix == 10)
521: || (Radix == One), "Radix is not as good as 2 or 10");
522: /*=============================================*/
523: Milestone = 20;
524: /*=============================================*/
525: TstCond (Failure, F9 - Half < Half,
526: "(1-U1)-1/2 < 1/2 is FALSE, prog. fails?");
527: X = F9;
528: I = 1;
529: Y = X - Half;
530: Z = Y - Half;
531: TstCond (Failure, (X != One)
532: || (Z == Zero), "Comparison is fuzzy,X=1 but X-1/2-1/2 != 0");
533: X = One + U2;
534: I = 0;
535: /*=============================================*/
536: Milestone = 25;
537: /*=============================================*/
538: /*... BMinusU2 = nextafter(Radix, 0) */
539: BMinusU2 = Radix - One;
540: BMinusU2 = (BMinusU2 - U2) + One;
541: /* Purify Integers */
542: if (Radix != One) {
543: X = - TwoForty * LOG(U1) / LOG(Radix);
544: Y = FLOOR(Half + X);
545: if (FABS(X - Y) * Four < One) X = Y;
546: Precision = X / TwoForty;
547: Y = FLOOR(Half + Precision);
548: if (FABS(Precision - Y) * TwoForty < Half) Precision = Y;
549: }
550: if ((Precision != FLOOR(Precision)) || (Radix == One)) {
551: printf("Precision cannot be characterized by an Integer number\n");
552: printf("of significant digits but, by itself, this is a minor flaw.\n");
553: }
554: if (Radix == One)
555: printf("logarithmic encoding has precision characterized solely by U1.\n");
556: else printf("The number of significant digits of the Radix is %f .\n",
557: Precision);
558: TstCond (Serious, U2 * Nine * Nine * TwoForty < One,
559: "Precision worse than 5 decimal figures ");
560: /*=============================================*/
561: Milestone = 30;
562: /*=============================================*/
563: /* Test for extra-precise subepressions */
564: X = FABS(((Four / Three - One) - One / Four) * Three - One / Four);
565: do {
566: Z2 = X;
567: X = (One + (Half * Z2 + ThirtyTwo * Z2 * Z2)) - One;
568: } while ( ! ((Z2 <= X) || (X <= Zero)));
569: X = Y = Z = FABS((Three / Four - Two / Three) * Three - One / Four);
570: do {
571: Z1 = Z;
572: Z = (One / Two - ((One / Two - (Half * Z1 + ThirtyTwo * Z1 * Z1))
573: + One / Two)) + One / Two;
574: } while ( ! ((Z1 <= Z) || (Z <= Zero)));
575: do {
576: do {
577: Y1 = Y;
578: Y = (Half - ((Half - (Half * Y1 + ThirtyTwo * Y1 * Y1)) + Half
579: )) + Half;
580: } while ( ! ((Y1 <= Y) || (Y <= Zero)));
581: X1 = X;
582: X = ((Half * X1 + ThirtyTwo * X1 * X1) - F9) + F9;
583: } while ( ! ((X1 <= X) || (X <= Zero)));
584: if ((X1 != Y1) || (X1 != Z1)) {
585: BadCond(Serious, "Disagreements among the values X1, Y1, Z1,\n");
586: printf("respectively %.7e, %.7e, %.7e,\n", X1, Y1, Z1);
587: printf("are symptoms of inconsistencies introduced\n");
588: printf("by extra-precise evaluation of arithmetic subexpressions.\n");
589: notify("Possibly some part of this");
590: if ((X1 == U1) || (Y1 == U1) || (Z1 == U1)) printf(
591: "That feature is not tested further by this program.\n") ;
592: }
593: else {
594: if ((Z1 != U1) || (Z2 != U2)) {
595: if ((Z1 >= U1) || (Z2 >= U2)) {
596: BadCond(Failure, "");
597: notify("Precision");
598: printf("\tU1 = %.7e, Z1 - U1 = %.7e\n",U1,Z1-U1);
599: printf("\tU2 = %.7e, Z2 - U2 = %.7e\n",U2,Z2-U2);
600: }
601: else {
602: if ((Z1 <= Zero) || (Z2 <= Zero)) {
603: printf("Because of unusual Radix = %f", Radix);
604: printf(", or exact rational arithmetic a result\n");
605: printf("Z1 = %.7e, or Z2 = %.7e ", Z1, Z2);
606: notify("of an\nextra-precision");
607: }
608: if (Z1 != Z2 || Z1 > Zero) {
609: X = Z1 / U1;
610: Y = Z2 / U2;
611: if (Y > X) X = Y;
612: Q = - LOG(X);
613: printf("Some subexpressions appear to be calculated extra\n");
614: printf("precisely with about %g extra B-digits, i.e.\n",
615: (Q / LOG(Radix)));
616: printf("roughly %g extra significant decimals.\n",
617: Q / LOG(10.));
618: }
619: printf("That feature is not tested further by this program.\n");
620: }
621: }
622: }
623: Pause();
624: /*=============================================*/
625: /*SPLIT
626: }
627: #include "paranoia.h"
628: part3(){
629: */
630: Milestone = 35;
631: /*=============================================*/
632: if (Radix >= Two) {
633: X = W / (Radix * Radix);
634: Y = X + One;
635: Z = Y - X;
636: T = Z + U2;
637: X = T - Z;
638: TstCond (Failure, X == U2,
639: "Subtraction is not normalized X=Y,X+Z != Y+Z!");
640: if (X == U2) printf(
641: "Subtraction appears to be normalized, as it should be.");
642: }
643: printf("\nChecking for guard digit in *, /, and -.\n");
644: Y = F9 * One;
645: Z = One * F9;
646: X = F9 - Half;
647: Y = (Y - Half) - X;
648: Z = (Z - Half) - X;
649: X = One + U2;
650: T = X * Radix;
651: R = Radix * X;
652: X = T - Radix;
653: X = X - Radix * U2;
654: T = R - Radix;
655: T = T - Radix * U2;
656: X = X * (Radix - One);
657: T = T * (Radix - One);
658: if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero)) GMult = Yes;
659: else {
660: GMult = No;
661: TstCond (Serious, False,
662: "* lacks a Guard Digit, so 1*X != X");
663: }
664: Z = Radix * U2;
665: X = One + Z;
666: Y = FABS((X + Z) - X * X) - U2;
667: X = One - U2;
668: Z = FABS((X - U2) - X * X) - U1;
669: TstCond (Failure, (Y <= Zero)
670: && (Z <= Zero), "* gets too many final digits wrong.\n");
671: Y = One - U2;
672: X = One + U2;
673: Z = One / Y;
674: Y = Z - X;
675: X = One / Three;
676: Z = Three / Nine;
677: X = X - Z;
678: T = Nine / TwentySeven;
679: Z = Z - T;
680: TstCond(Defect, X == Zero && Y == Zero && Z == Zero,
681: "Division lacks a Guard Digit, so error can exceed 1 ulp\nor 1/3 and 3/9 and 9/27 may disagree");
682: Y = F9 / One;
683: X = F9 - Half;
684: Y = (Y - Half) - X;
685: X = One + U2;
686: T = X / One;
687: X = T - X;
688: if ((X == Zero) && (Y == Zero) && (Z == Zero)) GDiv = Yes;
689: else {
690: GDiv = No;
691: TstCond (Serious, False,
692: "Division lacks a Guard Digit, so X/1 != X");
693: }
694: X = One / (One + U2);
695: Y = X - Half - Half;
696: TstCond (Serious, Y < Zero,
697: "Computed value of 1/1.000..1 >= 1");
698: X = One - U2;
699: Y = One + Radix * U2;
700: Z = X * Radix;
701: T = Y * Radix;
702: R = Z / Radix;
703: StickyBit = T / Radix;
704: X = R - X;
705: Y = StickyBit - Y;
706: TstCond (Failure, X == Zero && Y == Zero,
707: "* and/or / gets too many last digits wrong");
708: Y = One - U1;
709: X = One - F9;
710: Y = One - Y;
711: T = Radix - U2;
712: Z = Radix - BMinusU2;
713: T = Radix - T;
714: if ((X == U1) && (Y == U1) && (Z == U2) && (T == U2)) GAddSub = Yes;
715: else {
716: GAddSub = No;
717: TstCond (Serious, False,
718: "- lacks Guard Digit, so cancellation is obscured");
719: }
720: if (F9 != One && F9 - One >= Zero) {
721: BadCond(Serious, "comparison alleges (1-U1) < 1 although\n");
722: printf(" subtraction yields (1-U1) - 1 = 0 , thereby vitiating\n");
723: printf(" such precautions against division by zero as\n");
724: printf(" ... if (X == 1.0) {.....} else {.../(X-1.0)...}\n");
725: }
726: if (GMult == Yes && GDiv == Yes && GAddSub == Yes) printf(
727: " *, /, and - appear to have guard digits, as they should.\n");
728: /*=============================================*/
729: Milestone = 40;
730: /*=============================================*/
731: Pause();
732: printf("Checking rounding on multiply, divide and add/subtract.\n");
733: RMult = Other;
734: RDiv = Other;
735: RAddSub = Other;
736: RadixD2 = Radix / Two;
737: A1 = Two;
738: Done = False;
739: do {
740: AInvrse = Radix;
741: do {
742: X = AInvrse;
743: AInvrse = AInvrse / A1;
744: } while ( ! (FLOOR(AInvrse) != AInvrse));
745: Done = (X == One) || (A1 > Three);
746: if (! Done) A1 = Nine + One;
747: } while ( ! (Done));
748: if (X == One) A1 = Radix;
749: AInvrse = One / A1;
750: X = A1;
751: Y = AInvrse;
752: Done = False;
753: do {
754: Z = X * Y - Half;
755: TstCond (Failure, Z == Half,
756: "X * (1/X) differs from 1");
757: Done = X == Radix;
758: X = Radix;
759: Y = One / X;
760: } while ( ! (Done));
761: Y2 = One + U2;
762: Y1 = One - U2;
763: X = OneAndHalf - U2;
764: Y = OneAndHalf + U2;
765: Z = (X - U2) * Y2;
766: T = Y * Y1;
767: Z = Z - X;
768: T = T - X;
769: X = X * Y2;
770: Y = (Y + U2) * Y1;
771: X = X - OneAndHalf;
772: Y = Y - OneAndHalf;
773: if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T <= Zero)) {
774: X = (OneAndHalf + U2) * Y2;
775: Y = OneAndHalf - U2 - U2;
776: Z = OneAndHalf + U2 + U2;
777: T = (OneAndHalf - U2) * Y1;
778: X = X - (Z + U2);
779: StickyBit = Y * Y1;
780: S = Z * Y2;
781: T = T - Y;
782: Y = (U2 - Y) + StickyBit;
783: Z = S - (Z + U2 + U2);
784: StickyBit = (Y2 + U2) * Y1;
785: Y1 = Y2 * Y1;
786: StickyBit = StickyBit - Y2;
787: Y1 = Y1 - Half;
788: if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero)
789: && ( StickyBit == Zero) && (Y1 == Half)) {
790: RMult = Rounded;
791: printf("Multiplication appears to round correctly.\n");
792: }
793: else if ((X + U2 == Zero) && (Y < Zero) && (Z + U2 == Zero)
794: && (T < Zero) && (StickyBit + U2 == Zero)
795: && (Y1 < Half)) {
796: RMult = Chopped;
797: printf("Multiplication appears to chop.\n");
798: }
799: else printf("* is neither chopped nor correctly rounded.\n");
800: if ((RMult == Rounded) && (GMult == No)) notify("Multiplication");
801: }
802: else printf("* is neither chopped nor correctly rounded.\n");
803: /*=============================================*/
804: Milestone = 45;
805: /*=============================================*/
806: Y2 = One + U2;
807: Y1 = One - U2;
808: Z = OneAndHalf + U2 + U2;
809: X = Z / Y2;
810: T = OneAndHalf - U2 - U2;
811: Y = (T - U2) / Y1;
812: Z = (Z + U2) / Y2;
813: X = X - OneAndHalf;
814: Y = Y - T;
815: T = T / Y1;
816: Z = Z - (OneAndHalf + U2);
817: T = (U2 - OneAndHalf) + T;
818: if (! ((X > Zero) || (Y > Zero) || (Z > Zero) || (T > Zero))) {
819: X = OneAndHalf / Y2;
820: Y = OneAndHalf - U2;
821: Z = OneAndHalf + U2;
822: X = X - Y;
823: T = OneAndHalf / Y1;
824: Y = Y / Y1;
825: T = T - (Z + U2);
826: Y = Y - Z;
827: Z = Z / Y2;
828: Y1 = (Y2 + U2) / Y2;
829: Z = Z - OneAndHalf;
830: Y2 = Y1 - Y2;
831: Y1 = (F9 - U1) / F9;
832: if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero)
833: && (Y2 == Zero) && (Y2 == Zero)
834: && (Y1 - Half == F9 - Half )) {
835: RDiv = Rounded;
836: printf("Division appears to round correctly.\n");
837: if (GDiv == No) notify("Division");
838: }
839: else if ((X < Zero) && (Y < Zero) && (Z < Zero) && (T < Zero)
840: && (Y2 < Zero) && (Y1 - Half < F9 - Half)) {
841: RDiv = Chopped;
842: printf("Division appears to chop.\n");
843: }
844: }
845: if (RDiv == Other) printf("/ is neither chopped nor correctly rounded.\n");
846: BInvrse = One / Radix;
847: TstCond (Failure, (BInvrse * Radix - Half == Half),
848: "Radix * ( 1 / Radix ) differs from 1");
849: /*=============================================*/
850: /*SPLIT
851: }
852: #include "paranoia.h"
853: part4(){
854: */
855: Milestone = 50;
856: /*=============================================*/
857: TstCond (Failure, ((F9 + U1) - Half == Half)
858: && ((BMinusU2 + U2 ) - One == Radix - One),
859: "Incomplete carry-propagation in Addition");
860: X = One - U1 * U1;
861: Y = One + U2 * (One - U2);
862: Z = F9 - Half;
863: X = (X - Half) - Z;
864: Y = Y - One;
865: if ((X == Zero) && (Y == Zero)) {
866: RAddSub = Chopped;
867: printf("Add/Subtract appears to be chopped.\n");
868: }
869: if (GAddSub == Yes) {
870: X = (Half + U2) * U2;
871: Y = (Half - U2) * U2;
872: X = One + X;
873: Y = One + Y;
874: X = (One + U2) - X;
875: Y = One - Y;
876: if ((X == Zero) && (Y == Zero)) {
877: X = (Half + U2) * U1;
878: Y = (Half - U2) * U1;
879: X = One - X;
880: Y = One - Y;
881: X = F9 - X;
882: Y = One - Y;
883: if ((X == Zero) && (Y == Zero)) {
884: RAddSub = Rounded;
885: printf("Addition/Subtraction appears to round correctly.\n");
886: if (GAddSub == No) notify("Add/Subtract");
887: }
888: else printf("Addition/Subtraction neither rounds nor chops.\n");
889: }
890: else printf("Addition/Subtraction neither rounds nor chops.\n");
891: }
892: else printf("Addition/Subtraction neither rounds nor chops.\n");
893: S = One;
894: X = One + Half * (One + Half);
895: Y = (One + U2) * Half;
896: Z = X - Y;
897: T = Y - X;
898: StickyBit = Z + T;
899: if (StickyBit != Zero) {
900: S = Zero;
901: BadCond(Flaw, "(X - Y) + (Y - X) is non zero!\n");
902: }
903: StickyBit = Zero;
904: if ((GMult == Yes) && (GDiv == Yes) && (GAddSub == Yes)
905: && (RMult == Rounded) && (RDiv == Rounded)
906: && (RAddSub == Rounded) && (FLOOR(RadixD2) == RadixD2)) {
907: printf("Checking for sticky bit.\n");
908: X = (Half + U1) * U2;
909: Y = Half * U2;
910: Z = One + Y;
911: T = One + X;
912: if ((Z - One <= Zero) && (T - One >= U2)) {
913: Z = T + Y;
914: Y = Z - X;
915: if ((Z - T >= U2) && (Y - T == Zero)) {
916: X = (Half + U1) * U1;
917: Y = Half * U1;
918: Z = One - Y;
919: T = One - X;
920: if ((Z - One == Zero) && (T - F9 == Zero)) {
921: Z = (Half - U1) * U1;
922: T = F9 - Z;
923: Q = F9 - Y;
924: if ((T - F9 == Zero) && (F9 - U1 - Q == Zero)) {
925: Z = (One + U2) * OneAndHalf;
926: T = (OneAndHalf + U2) - Z + U2;
927: X = One + Half / Radix;
928: Y = One + Radix * U2;
929: Z = X * Y;
930: if (T == Zero && X + Radix * U2 - Z == Zero) {
931: if (Radix != Two) {
932: X = Two + U2;
933: Y = X / Two;
934: if ((Y - One == Zero)) StickyBit = S;
935: }
936: else StickyBit = S;
937: }
938: }
939: }
940: }
941: }
942: }
943: if (StickyBit == One) printf("Sticky bit apparently used correctly.\n");
944: else printf("Sticky bit used incorrectly or not at all.\n");
945: TstCond (Flaw, !(GMult == No || GDiv == No || GAddSub == No ||
946: RMult == Other || RDiv == Other || RAddSub == Other),
947: "lack(s) of guard digits or failure(s) to correctly round or chop\n(noted above) count as one flaw in the final tally below");
948: /*=============================================*/
949: Milestone = 60;
950: /*=============================================*/
951: printf("\n");
952: printf("Does Multiplication commute? ");
953: printf("Testing on %d random pairs.\n", NoTrials);
954: Random9 = SQRT(3.0);
955: Random1 = Third;
956: I = 1;
957: do {
958: X = Random();
959: Y = Random();
960: Z9 = Y * X;
961: Z = X * Y;
962: Z9 = Z - Z9;
963: I = I + 1;
964: } while ( ! ((I > NoTrials) || (Z9 != Zero)));
965: if (I == NoTrials) {
966: Random1 = One + Half / Three;
967: Random2 = (U2 + U1) + One;
968: Z = Random1 * Random2;
969: Y = Random2 * Random1;
970: Z9 = (One + Half / Three) * ((U2 + U1) + One) - (One + Half /
971: Three) * ((U2 + U1) + One);
972: }
973: if (! ((I == NoTrials) || (Z9 == Zero)))
974: BadCond(Defect, "X * Y == Y * X trial fails.\n");
975: else printf(" No failures found in %d integer pairs.\n", NoTrials);
976: /*=============================================*/
977: Milestone = 70;
978: /*=============================================*/
979: printf("\nRunning test of square root(x).\n");
980: TstCond (Failure, (Zero == SQRT(Zero))
981: && (- Zero == SQRT(- Zero))
982: && (One == SQRT(One)), "Square root of 0.0, -0.0 or 1.0 wrong");
983: MinSqEr = Zero;
984: MaxSqEr = Zero;
985: J = Zero;
986: X = Radix;
987: OneUlp = U2;
988: SqXMinX (Serious);
989: X = BInvrse;
990: OneUlp = BInvrse * U1;
991: SqXMinX (Serious);
992: X = U1;
993: OneUlp = U1 * U1;
994: SqXMinX (Serious);
995: if (J != Zero) Pause();
996: printf("Testing if sqrt(X * X) == X for %d Integers X.\n", NoTrials);
997: J = Zero;
998: X = Two;
999: Y = Radix;
1000: if ((Radix != One)) do {
1001: X = Y;
1002: Y = Radix * Y;
1003: } while ( ! ((Y - X >= NoTrials)));
1004: OneUlp = X * U2;
1005: I = 1;
1006: while (I <= NoTrials) {
1007: X = X + One;
1008: SqXMinX (Defect);
1009: if (J > Zero) break;
1010: I = I + 1;
1011: }
1012: printf("Test for sqrt monotonicity.\n");
1013: I = - 1;
1014: X = BMinusU2;
1015: Y = Radix;
1016: Z = Radix + Radix * U2;
1017: NotMonot = False;
1018: Monot = False;
1019: while ( ! (NotMonot || Monot)) {
1020: I = I + 1;
1021: X = SQRT(X);
1022: Q = SQRT(Y);
1023: Z = SQRT(Z);
1024: if ((X > Q) || (Q > Z)) NotMonot = True;
1025: else {
1026: Q = FLOOR(Q + Half);
1027: if ((I > 0) || (Radix == Q * Q)) Monot = True;
1028: else if (I > 0) {
1029: if (I > 1) Monot = True;
1030: else {
1031: Y = Y * BInvrse;
1032: X = Y - U1;
1033: Z = Y + U1;
1034: }
1035: }
1036: else {
1037: Y = Q;
1038: X = Y - U2;
1039: Z = Y + U2;
1040: }
1041: }
1042: }
1043: if (Monot) printf("sqrt has passed a test for Monotonicity.\n");
1044: else {
1045: BadCond(Defect, "");
1046: printf("sqrt(X) is non-monotonic for X near %.7e .\n", Y);
1047: }
1048: /*=============================================*/
1049: /*SPLIT
1050: }
1051: #include "paranoia.h"
1052: part5(){
1053: */
1054: Milestone = 80;
1055: /*=============================================*/
1056: MinSqEr = MinSqEr + Half;
1057: MaxSqEr = MaxSqEr - Half;
1058: Y = (SQRT(One + U2) - One) / U2;
1059: SqEr = (Y - One) + U2 / Eight;
1060: if (SqEr > MaxSqEr) MaxSqEr = SqEr;
1061: SqEr = Y + U2 / Eight;
1062: if (SqEr < MinSqEr) MinSqEr = SqEr;
1063: Y = ((SQRT(F9) - U2) - (One - U2)) / U1;
1064: SqEr = Y + U1 / Eight;
1065: if (SqEr > MaxSqEr) MaxSqEr = SqEr;
1066: SqEr = (Y + One) + U1 / Eight;
1067: if (SqEr < MinSqEr) MinSqEr = SqEr;
1068: OneUlp = U2;
1069: X = OneUlp;
1070: for( Indx = 1; Indx <= 3; ++Indx) {
1071: Y = SQRT((X + U1 + X) + F9);
1072: Y = ((Y - U2) - ((One - U2) + X)) / OneUlp;
1073: Z = ((U1 - X) + F9) * Half * X * X / OneUlp;
1074: SqEr = (Y + Half) + Z;
1075: if (SqEr < MinSqEr) MinSqEr = SqEr;
1076: SqEr = (Y - Half) + Z;
1077: if (SqEr > MaxSqEr) MaxSqEr = SqEr;
1078: if (((Indx == 1) || (Indx == 3)))
1079: X = OneUlp * Sign (X) * FLOOR(Eight / (Nine * SQRT(OneUlp)));
1080: else {
1081: OneUlp = U1;
1082: X = - OneUlp;
1083: }
1084: }
1085: /*=============================================*/
1086: Milestone = 85;
1087: /*=============================================*/
1088: SqRWrng = False;
1089: Anomaly = False;
1090: RSqrt = Other; /* ~dgh */
1091: if (Radix != One) {
1092: printf("Testing whether sqrt is rounded or chopped.\n");
1093: D = FLOOR(Half + POW(Radix, One + Precision - FLOOR(Precision)));
1094: /* ... == Radix^(1 + fract) if (Precision == Integer + fract. */
1095: X = D / Radix;
1096: Y = D / A1;
1097: if ((X != FLOOR(X)) || (Y != FLOOR(Y))) {
1098: Anomaly = True;
1099: }
1100: else {
1101: X = Zero;
1102: Z2 = X;
1103: Y = One;
1104: Y2 = Y;
1105: Z1 = Radix - One;
1106: FourD = Four * D;
1107: do {
1108: if (Y2 > Z2) {
1109: Q = Radix;
1110: Y1 = Y;
1111: do {
1112: X1 = FABS(Q + FLOOR(Half - Q / Y1) * Y1);
1113: Q = Y1;
1114: Y1 = X1;
1115: } while ( ! (X1 <= Zero));
1116: if (Q <= One) {
1117: Z2 = Y2;
1118: Z = Y;
1119: }
1120: }
1121: Y = Y + Two;
1122: X = X + Eight;
1123: Y2 = Y2 + X;
1124: if (Y2 >= FourD) Y2 = Y2 - FourD;
1125: } while ( ! (Y >= D));
1126: X8 = FourD - Z2;
1127: Q = (X8 + Z * Z) / FourD;
1128: X8 = X8 / Eight;
1129: if (Q != FLOOR(Q)) Anomaly = True;
1130: else {
1131: Break = False;
1132: do {
1133: X = Z1 * Z;
1134: X = X - FLOOR(X / Radix) * Radix;
1135: if (X == One)
1136: Break = True;
1137: else
1138: Z1 = Z1 - One;
1139: } while ( ! (Break || (Z1 <= Zero)));
1140: if ((Z1 <= Zero) && (! Break)) Anomaly = True;
1141: else {
1142: if (Z1 > RadixD2) Z1 = Z1 - Radix;
1143: do {
1144: NewD();
1145: } while ( ! (U2 * D >= F9));
1146: if (D * Radix - D != W - D) Anomaly = True;
1147: else {
1148: Z2 = D;
1149: I = 0;
1150: Y = D + (One + Z) * Half;
1151: X = D + Z + Q;
1152: SR3750();
1153: Y = D + (One - Z) * Half + D;
1154: X = D - Z + D;
1155: X = X + Q + X;
1156: SR3750();
1157: NewD();
1158: if (D - Z2 != W - Z2) Anomaly = True;
1159: else {
1160: Y = (D - Z2) + (Z2 + (One - Z) * Half);
1161: X = (D - Z2) + (Z2 - Z + Q);
1162: SR3750();
1163: Y = (One + Z) * Half;
1164: X = Q;
1165: SR3750();
1166: if (I == 0) Anomaly = True;
1167: }
1168: }
1169: }
1170: }
1171: }
1172: if ((I == 0) || Anomaly) {
1173: BadCond(Failure, "Anomalous arithmetic with Integer < ");
1174: printf("Radix^Precision = %.7e\n", W);
1175: printf(" fails test whether sqrt rounds or chops.\n");
1176: SqRWrng = True;
1177: }
1178: }
1179: if (! Anomaly) {
1180: if (! ((MinSqEr < Zero) || (MaxSqEr > Zero))) {
1181: RSqrt = Rounded;
1182: printf("Square root appears to be correctly rounded.\n");
1183: }
1184: else {
1185: if ((MaxSqEr + U2 > U2 - Half) || (MinSqEr > Half)
1186: || (MinSqEr + Radix < Half)) SqRWrng = True;
1187: else {
1188: RSqrt = Chopped;
1189: printf("Square root appears to be chopped.\n");
1190: }
1191: }
1192: }
1193: if (SqRWrng) {
1194: printf("Square root is neither chopped nor correctly rounded.\n");
1195: printf("Observed errors run from %.7e ", MinSqEr - Half);
1196: printf("to %.7e ulps.\n", Half + MaxSqEr);
1197: TstCond (Serious, MaxSqEr - MinSqEr < Radix * Radix,
1198: "sqrt gets too many last digits wrong");
1199: }
1200: /*=============================================*/
1201: Milestone = 90;
1202: /*=============================================*/
1203: Pause();
1204: printf("Testing powers Z^i for small Integers Z and i.\n");
1205: N = 0;
1206: /* ... test powers of zero. */
1207: I = 0;
1208: Z = -Zero;
1209: M = 3.0;
1210: Break = False;
1211: do {
1212: X = One;
1213: SR3980();
1214: if (I <= 10) {
1215: I = 1023;
1216: SR3980();
1217: }
1218: if (Z == MinusOne) Break = True;
1219: else {
1220: Z = MinusOne;
1221: PrintIfNPositive();
1222: N = 0;
1223: /* .. if(-1)^N is invalid, replace MinusOne by One. */
1224: I = - 4;
1225: }
1226: } while ( ! Break);
1227: PrintIfNPositive();
1228: N1 = N;
1229: N = 0;
1230: Z = A1;
1231: M = FLOOR(Two * LOG(W) / LOG(A1));
1232: Break = False;
1233: do {
1234: X = Z;
1235: I = 1;
1236: SR3980();
1237: if (Z == AInvrse) Break = True;
1238: else Z = AInvrse;
1239: } while ( ! (Break));
1240: /*=============================================*/
1241: Milestone = 100;
1242: /*=============================================*/
1243: /* Powers of Radix have been tested, */
1244: /* next try a few primes */
1245: M = NoTrials;
1246: Z = Three;
1247: do {
1248: X = Z;
1249: I = 1;
1250: SR3980();
1251: do {
1252: Z = Z + Two;
1253: } while ( Three * FLOOR(Z / Three) == Z );
1254: } while ( Z < Eight * Three );
1255: if (N > 0) {
1256: printf("Errors like this may invalidate financial calculations\n");
1257: printf("\tinvolving interest rates.\n");
1258: }
1259: PrintIfNPositive();
1260: N += N1;
1261: if (N == 0) printf("... no discrepancis found.\n");
1262: if (N > 0) Pause();
1263: else printf("\n");
1264: /*=============================================*/
1265: /*SPLIT
1266: }
1267: #include "paranoia.h"
1268: part6(){
1269: */
1270: Milestone = 110;
1271: /*=============================================*/
1272: printf("Seeking Underflow thresholds UfThold and E0.\n");
1273: D = U1;
1274: if (Precision != FLOOR(Precision)) {
1275: D = BInvrse;
1276: X = Precision;
1277: do {
1278: D = D * BInvrse;
1279: X = X - One;
1280: } while ( X > Zero);
1281: }
1282: Y = One;
1283: Z = D;
1284: /* ... D is power of 1/Radix < 1. */
1285: do {
1286: C = Y;
1287: Y = Z;
1288: Z = Y * Y;
1289: } while ((Y > Z) && (Z + Z > Z));
1290: Y = C;
1291: Z = Y * D;
1292: do {
1293: C = Y;
1294: Y = Z;
1295: Z = Y * D;
1296: } while ((Y > Z) && (Z + Z > Z));
1297: if (Radix < Two) HInvrse = Two;
1298: else HInvrse = Radix;
1299: H = One / HInvrse;
1300: /* ... 1/HInvrse == H == Min(1/Radix, 1/2) */
1301: CInvrse = One / C;
1302: E0 = C;
1303: Z = E0 * H;
1304: /* ...1/Radix^(BIG Integer) << 1 << CInvrse == 1/C */
1305: do {
1306: Y = E0;
1307: E0 = Z;
1308: Z = E0 * H;
1309: } while ((E0 > Z) && (Z + Z > Z));
1310: UfThold = E0;
1311: E1 = Zero;
1312: Q = Zero;
1313: E9 = U2;
1314: S = One + E9;
1315: D = C * S;
1316: if (D <= C) {
1317: E9 = Radix * U2;
1318: S = One + E9;
1319: D = C * S;
1320: if (D <= C) {
1321: BadCond(Failure, "multiplication gets too many last digits wrong.\n");
1322: Underflow = E0;
1323: Y1 = Zero;
1324: PseudoZero = Z;
1325: Pause();
1326: }
1327: }
1328: else {
1329: Underflow = D;
1330: PseudoZero = Underflow * H;
1331: UfThold = Zero;
1332: do {
1333: Y1 = Underflow;
1334: Underflow = PseudoZero;
1335: if (E1 + E1 <= E1) {
1336: Y2 = Underflow * HInvrse;
1337: E1 = FABS(Y1 - Y2);
1338: Q = Y1;
1339: if ((UfThold == Zero) && (Y1 != Y2)) UfThold = Y1;
1340: }
1341: PseudoZero = PseudoZero * H;
1342: } while ((Underflow > PseudoZero)
1343: && (PseudoZero + PseudoZero > PseudoZero));
1344: }
1345: /* Comment line 4530 .. 4560 */
1346: if (PseudoZero != Zero) {
1347: printf("\n");
1348: Z = PseudoZero;
1349: /* ... Test PseudoZero for "phoney- zero" violates */
1350: /* ... PseudoZero < Underflow or PseudoZero < PseudoZero + PseudoZero
1351: ... */
1352: if (PseudoZero <= Zero) {
1353: BadCond(Failure, "Positive expressions can underflow to an\n");
1354: printf("allegedly negative value\n");
1355: printf("PseudoZero that prints out as: %g .\n", PseudoZero);
1356: X = - PseudoZero;
1357: if (X <= Zero) {
1358: printf("But -PseudoZero, which should be\n");
1359: printf("positive, isn't; it prints out as %g .\n", X);
1360: }
1361: }
1362: else {
1363: BadCond(Flaw, "Underflow can stick at an allegedly positive\n");
1364: printf("value PseudoZero that prints out as %g .\n", PseudoZero);
1365: }
1366: TstPtUf();
1367: }
1368: /*=============================================*/
1369: Milestone = 120;
1370: /*=============================================*/
1371: if (CInvrse * Y > CInvrse * Y1) {
1372: S = H * S;
1373: E0 = Underflow;
1374: }
1375: if (! ((E1 == Zero) || (E1 == E0))) {
1376: BadCond(Defect, "");
1377: if (E1 < E0) {
1378: printf("Products underflow at a higher");
1379: printf(" threshold than differences.\n");
1380: if (PseudoZero == Zero)
1381: E0 = E1;
1382: }
1383: else {
1384: printf("Difference underflows at a higher");
1385: printf(" threshold than products.\n");
1386: }
1387: }
1388: printf("Smallest strictly positive number found is E0 = %g .\n", E0);
1389: Z = E0;
1390: TstPtUf();
1391: Underflow = E0;
1392: if (N == 1) Underflow = Y;
1393: I = 4;
1394: if (E1 == Zero) I = 3;
1395: if (UfThold == Zero) I = I - 2;
1396: UfNGrad = True;
1397: switch (I) {
1398: case 1:
1399: UfThold = Underflow;
1400: if ((CInvrse * Q) != ((CInvrse * Y) * S)) {
1401: UfThold = Y;
1402: BadCond(Failure, "Either accuracy deteriorates as numbers\n");
1403: printf("approach a threshold = %.17e\n", UfThold);;
1404: printf(" coming down from %.17e\n", C);
1405: printf(" or else multiplication gets too many last digits wrong.\n");
1406: }
1407: Pause();
1408: break;
1409:
1410: case 2:
1411: BadCond(Failure, "Underflow confuses Comparison, which alleges that\n");
1412: printf("Q == Y while denying that |Q - Y| == 0; these values\n");
1413: printf("print out as Q = %.17e, Y = %.17e .\n", Q, Y2);
1414: printf ("|Q - Y| = %.17e .\n" , FABS(Q - Y2));
1415: UfThold = Q;
1416: break;
1417:
1418: case 3:
1419: X = X;
1420: break;
1421:
1422: case 4:
1423: if ((Q == UfThold) && (E1 == E0)
1424: && (FABS( UfThold - E1 / E9) <= E1)) {
1425: UfNGrad = False;
1426: printf("Underflow is gradual; it incurs Absolute Error =\n");
1427: printf("(roundoff in UfThold) < E0.\n");
1428: Y = E0 * CInvrse;
1429: Y = Y * (OneAndHalf + U2);
1430: X = CInvrse * (One + U2);
1431: Y = Y / X;
1432: IEEE = (Y == E0);
1433: }
1434: }
1435: if (UfNGrad) {
1436: printf("\n");
1437: sigsave = sigfpe;
1438: if (setjmp(ovfl_buf)) {
1439: printf("Underflow / UfThold failed!\n");
1440: R = H + H;
1441: }
1442: else R = SQRT(Underflow / UfThold);
1443: sigsave = 0;
1444: if (R <= H) {
1445: Z = R * UfThold;
1446: X = Z * (One + R * H * (One + H));
1447: }
1448: else {
1449: Z = UfThold;
1450: X = Z * (One + H * H * (One + H));
1451: }
1452: if (! ((X == Z) || (X - Z != Zero))) {
1453: BadCond(Flaw, "");
1454: printf("X = %.17e\n\tis not equal to Z = %.17e .\n", X, Z);
1455: Z9 = X - Z;
1456: printf("yet X - Z yields %.17e .\n", Z9);
1457: printf(" Should this NOT signal Underflow, ");
1458: printf("this is a SERIOUS DEFECT\nthat causes ");
1459: printf("confusion when innocent statements like\n");;
1460: printf(" if (X == Z) ... else");
1461: printf(" ... (f(X) - f(Z)) / (X - Z) ...\n");
1462: printf("encounter Division by Zero although actually\n");
1463: sigsave = sigfpe;
1464: if (setjmp(ovfl_buf)) printf("X / Z fails!\n");
1465: else printf("X / Z = 1 + %g .\n", (X / Z - Half) - Half);
1466: sigsave = 0;
1467: }
1468: }
1469: printf("The Underflow threshold is %.17e, %s\n", UfThold,
1470: " below which");
1471: printf("calculation may suffer larger Relative error than ");
1472: printf("merely roundoff.\n");
1473: Y2 = U1 * U1;
1474: Y = Y2 * Y2;
1475: Y2 = Y * U1;
1476: if (Y2 <= UfThold) {
1477: if (Y > E0) {
1478: BadCond(Defect, "");
1479: I = 5;
1480: }
1481: else {
1482: BadCond(Serious, "");
1483: I = 4;
1484: }
1485: printf("Range is too narrow; U1^%d Underflows.\n", I);
1486: }
1487: /*=============================================*/
1488: /*SPLIT
1489: }
1490: #include "paranoia.h"
1491: part7(){
1492: */
1493: Milestone = 130;
1494: /*=============================================*/
1495: Y = - FLOOR(Half - TwoForty * LOG(UfThold) / LOG(HInvrse)) / TwoForty;
1496: Y2 = Y + Y;
1497: printf("Since underflow occurs below the threshold\n");
1498: printf("UfThold = (%.17e) ^ (%.17e)\nonly underflow ", HInvrse, Y);
1499: printf("should afflict the expression\n\t(%.17e) ^ (%.17e);\n", HInvrse, Y);
1500: V9 = POW(HInvrse, Y2);
1501: printf("actually calculating yields: %.17e .\n", V9);
1502: if (! ((V9 >= Zero) && (V9 <= (Radix + Radix + E9) * UfThold))) {
1503: BadCond(Serious, "this is not between 0 and underflow\n");
1504: printf(" threshold = %.17e .\n", UfThold);
1505: }
1506: else if (! (V9 > UfThold * (One + E9)))
1507: printf("This computed value is O.K.\n");
1508: else {
1509: BadCond(Defect, "this is not between 0 and underflow\n");
1510: printf(" threshold = %.17e .\n", UfThold);
1511: }
1512: /*=============================================*/
1513: Milestone = 140;
1514: /*=============================================*/
1515: printf("\n");
1516: /* ...calculate Exp2 == exp(2) == 7.389056099... */
1517: X = Zero;
1518: I = 2;
1519: Y = Two * Three;
1520: Q = Zero;
1521: N = 0;
1522: do {
1523: Z = X;
1524: I = I + 1;
1525: Y = Y / (I + I);
1526: R = Y + Q;
1527: X = Z + R;
1528: Q = (Z - X) + R;
1529: } while(X > Z);
1530: Z = (OneAndHalf + One / Eight) + X / (OneAndHalf * ThirtyTwo);
1531: X = Z * Z;
1532: Exp2 = X * X;
1533: X = F9;
1534: Y = X - U1;
1535: printf("Testing X^((X + 1) / (X - 1)) vs. exp(2) = %.17e as X -> 1.\n",
1536: Exp2);
1537: for(I = 1;;) {
1538: Z = X - BInvrse;
1539: Z = (X + One) / (Z - (One - BInvrse));
1540: Q = POW(X, Z) - Exp2;
1541: if (FABS(Q) > TwoForty * U2) {
1542: N = 1;
1543: V9 = (X - BInvrse) - (One - BInvrse);
1544: BadCond(Defect, "Calculated");
1545: printf(" %.17e for\n", POW(X,Z));
1546: printf("\t(1 + (%.17e) ^ (%.17e);\n", V9, Z);
1547: printf("\tdiffers from correct value by %.17e .\n", Q);
1548: printf("\tThis much error may spoil financial\n");
1549: printf("\tcalculations involving tiny interest rates.\n");
1550: break;
1551: }
1552: else {
1553: Z = (Y - X) * Two + Y;
1554: X = Y;
1555: Y = Z;
1556: Z = One + (X - F9)*(X - F9);
1557: if (Z > One && I < NoTrials) I++;
1558: else {
1559: if (X > One) {
1560: if (N == 0)
1561: printf("Accuracy seems adequate.\n");
1562: break;
1563: }
1564: else {
1565: X = One + U2;
1566: Y = U2 + U2;
1567: Y += X;
1568: I = 1;
1569: }
1570: }
1571: }
1572: }
1573: /*=============================================*/
1574: Milestone = 150;
1575: /*=============================================*/
1576: printf("Testing powers Z^Q at four nearly extreme values.\n");
1577: N = 0;
1578: Z = A1;
1579: Q = FLOOR(Half - LOG(C) / LOG(A1));
1580: Break = False;
1581: do {
1582: X = CInvrse;
1583: Y = POW(Z, Q);
1584: IsYeqX();
1585: Q = - Q;
1586: X = C;
1587: Y = POW(Z, Q);
1588: IsYeqX();
1589: if (Z < One) Break = True;
1590: else Z = AInvrse;
1591: } while ( ! (Break));
1592: PrintIfNPositive();
1593: if (N == 0) printf(" ... no discrepancies found.\n");
1594: printf("\n");
1595:
1596: /*=============================================*/
1597: Milestone = 160;
1598: /*=============================================*/
1599: Pause();
1600: printf("Searching for Overflow threshold:\n");
1601: printf("This may generate an error.\n");
1602: Y = - CInvrse;
1603: V9 = HInvrse * Y;
1604: sigsave = sigfpe;
1605: if (setjmp(ovfl_buf)) { I = 0; V9 = Y; goto overflow; }
1606: do {
1607: V = Y;
1608: Y = V9;
1609: V9 = HInvrse * Y;
1610: } while(V9 < Y);
1611: I = 1;
1612: overflow:
1613: sigsave = 0;
1614: Z = V9;
1615: printf("Can `Z = -Y' overflow?\n");
1616: printf("Trying it on Y = %.17e .\n", Y);
1617: V9 = - Y;
1618: V0 = V9;
1619: if (V - Y == V + V0) printf("Seems O.K.\n");
1620: else {
1621: printf("finds a ");
1622: BadCond(Flaw, "-(-Y) differs from Y.\n");
1623: }
1624: if (Z != Y) {
1625: BadCond(Serious, "");
1626: printf("overflow past %.17e\n\tshrinks to %.17e .\n", Y, Z);
1627: }
1628: if (I) {
1629: Y = V * (HInvrse * U2 - HInvrse);
1630: Z = Y + ((One - HInvrse) * U2) * V;
1631: if (Z < V0) Y = Z;
1632: if (Y < V0) V = Y;
1633: if (V0 - V < V0) V = V0;
1634: }
1635: else {
1636: V = Y * (HInvrse * U2 - HInvrse);
1637: V = V + ((One - HInvrse) * U2) * Y;
1638: }
1639: printf("Overflow threshold is V = %.17e .\n", V);
1640: if (I) printf("Overflow saturates at V0 = %.17e .\n", V0);
1641: else printf("There is no saturation value because the system traps on overflow.\n");
1642: V9 = V * One;
1643: printf("No Overflow should be signaled for V * 1 = %.17e\n", V9);
1644: V9 = V / One;
1645: printf(" nor for V / 1 = %.17e .\n", V9);
1646: printf("Any overflow signal separating this * from the one\n");
1647: printf("above is a DEFECT.\n");
1648: /*=============================================*/
1649: Milestone = 170;
1650: /*=============================================*/
1651: if (!(-V < V && -V0 < V0 && -UfThold < V && UfThold < V)) {
1652: BadCond(Failure, "Comparisons involving ");
1653: printf("+-%g, +-%g\nand +-%g are confused by Overflow.",
1654: V, V0, UfThold);
1655: }
1656: /*=============================================*/
1657: Milestone = 175;
1658: /*=============================================*/
1659: printf("\n");
1660: for(Indx = 1; Indx <= 3; ++Indx) {
1661: switch (Indx) {
1662: case 1: Z = UfThold; break;
1663: case 2: Z = E0; break;
1664: case 3: Z = PseudoZero; break;
1665: }
1666: if (Z != Zero) {
1667: V9 = SQRT(Z);
1668: Y = V9 * V9;
1669: if (Y / (One - Radix * E9) < Z
1670: || Y > (One + Radix * E9) * Z) { /* dgh: + E9 --> * E9 */
1671: if (V9 > U1) BadCond(Serious, "");
1672: else BadCond(Defect, "");
1673: printf("Comparison alleges that what prints as Z = %.17e\n", Z);
1674: printf(" is too far from sqrt(Z) ^ 2 = %.17e .\n", Y);
1675: }
1676: }
1677: }
1678: /*=============================================*/
1679: Milestone = 180;
1680: /*=============================================*/
1681: for(Indx = 1; Indx <= 2; ++Indx) {
1682: if (Indx == 1) Z = V;
1683: else Z = V0;
1684: V9 = SQRT(Z);
1685: X = (One - Radix * E9) * V9;
1686: V9 = V9 * X;
1687: if (((V9 < (One - Two * Radix * E9) * Z) || (V9 > Z))) {
1688: Y = V9;
1689: if (X < W) BadCond(Serious, "");
1690: else BadCond(Defect, "");
1691: printf("Comparison alleges that Z = %17e\n", Z);
1692: printf(" is too far from sqrt(Z) ^ 2 (%.17e) .\n", Y);
1693: }
1694: }
1695: /*=============================================*/
1696: /*SPLIT
1697: }
1698: #include "paranoia.h"
1699: part8(){
1700: */
1701: Milestone = 190;
1702: /*=============================================*/
1703: Pause();
1704: X = UfThold * V;
1705: Y = Radix * Radix;
1706: if (X*Y < One || X > Y) {
1707: if (X * Y < U1 || X > Y/U1) BadCond(Defect, "Badly");
1708: else BadCond(Flaw, "");
1709:
1710: printf(" unbalanced range; UfThold * V = %.17e\n\t%s\n",
1711: X, "is too far from 1.\n");
1712: }
1713: /*=============================================*/
1714: Milestone = 200;
1715: /*=============================================*/
1716: for (Indx = 1; Indx <= 5; ++Indx) {
1717: X = F9;
1718: switch (Indx) {
1719: case 2: X = One + U2; break;
1720: case 3: X = V; break;
1721: case 4: X = UfThold; break;
1722: case 5: X = Radix;
1723: }
1724: Y = X;
1725: sigsave = sigfpe;
1726: if (setjmp(ovfl_buf))
1727: printf(" X / X traps when X = %g\n", X);
1728: else {
1729: V9 = (Y / X - Half) - Half;
1730: if (V9 == Zero) continue;
1731: if (V9 == - U1 && Indx < 5) BadCond(Flaw, "");
1732: else BadCond(Serious, "");
1733: printf(" X / X differs from 1 when X = %.17e\n", X);
1734: printf(" instead, X / X - 1/2 - 1/2 = %.17e .\n", V9);
1735: }
1736: sigsave = 0;
1737: }
1738: /*=============================================*/
1739: Milestone = 210;
1740: /*=============================================*/
1741: MyZero = Zero;
1742: printf("\n");
1743: printf("What message and/or values does Division by Zero produce?\n") ;
1744: #ifndef NOPAUSE
1745: printf("This can interupt your program. You can ");
1746: printf("skip this part if you wish.\n");
1747: printf("Do you wish to compute 1 / 0? ");
1748: fflush(stdout);
1749: read (KEYBOARD, ch, 8);
1750: if ((ch[0] == 'Y') || (ch[0] == 'y')) {
1751: #endif
1752: sigsave = sigfpe;
1753: printf(" Trying to compute 1 / 0 produces ...");
1754: if (!setjmp(ovfl_buf)) printf(" %.7e .\n", One / MyZero);
1755: sigsave = 0;
1756: #ifndef NOPAUSE
1757: }
1758: else printf("O.K.\n");
1759: printf("\nDo you wish to compute 0 / 0? ");
1760: fflush(stdout);
1761: read (KEYBOARD, ch, 80);
1762: if ((ch[0] == 'Y') || (ch[0] == 'y')) {
1763: #endif
1764: sigsave = sigfpe;
1765: printf("\n Trying to compute 0 / 0 produces ...");
1766: if (!setjmp(ovfl_buf)) printf(" %.7e .\n", Zero / MyZero);
1767: sigsave = 0;
1768: #ifndef NOPAUSE
1769: }
1770: else printf("O.K.\n");
1771: #endif
1772: /*=============================================*/
1773: Milestone = 220;
1774: /*=============================================*/
1775: Pause();
1776: printf("\n");
1777: {
1778: static char *msg[] = {
1779: "FAILUREs encountered =",
1780: "SERIOUS DEFECTs discovered =",
1781: "DEFECTs discovered =",
1782: "FLAWs discovered =" };
1783: int i;
1784: for(i = 0; i < 4; i++) if (ErrCnt[i])
1785: printf("The number of %-29s %d.\n",
1786: msg[i], ErrCnt[i]);
1787: }
1788: printf("\n");
1789: if ((ErrCnt[Failure] + ErrCnt[Serious] + ErrCnt[Defect]
1790: + ErrCnt[Flaw]) > 0) {
1791: if ((ErrCnt[Failure] + ErrCnt[Serious] + ErrCnt[
1792: Defect] == 0) && (ErrCnt[Flaw] > 0)) {
1793: printf("The arithmetic diagnosed seems ");
1794: printf("Satisfactory though flawed.\n");
1795: }
1796: if ((ErrCnt[Failure] + ErrCnt[Serious] == 0)
1797: && ( ErrCnt[Defect] > 0)) {
1798: printf("The arithmetic diagnosed may be Acceptable\n");
1799: printf("despite inconvenient Defects.\n");
1800: }
1801: if ((ErrCnt[Failure] + ErrCnt[Serious]) > 0) {
1802: printf("The arithmetic diagnosed has ");
1803: printf("unacceptable Serious Defects.\n");
1804: }
1805: if (ErrCnt[Failure] > 0) {
1806: printf("Potentially fatal FAILURE may have spoiled this");
1807: printf(" program's subsequent diagnoses.\n");
1808: }
1809: }
1810: else {
1811: printf("No failures, defects nor flaws have been discovered.\n");
1812: if (! ((RMult == Rounded) && (RDiv == Rounded)
1813: && (RAddSub == Rounded) && (RSqrt == Rounded)))
1814: printf("The arithmetic diagnosed seems Satisfactory.\n");
1815: else {
1816: if (StickyBit >= One &&
1817: (Radix - Two) * (Radix - Nine - One) == Zero) {
1818: printf("Rounding appears to conform to ");
1819: printf("the proposed IEEE standard P");
1820: if ((Radix == Two) &&
1821: ((Precision - Four * Three * Two) *
1822: ( Precision - TwentySeven -
1823: TwentySeven + One) == Zero))
1824: printf("754");
1825: else printf("854");
1826: if (IEEE) printf(".\n");
1827: else {
1828: printf(",\nexcept for possibly Double Rounding");
1829: printf(" during Gradual Underflow.\n");
1830: }
1831: }
1832: printf("The arithmetic diagnosed appears to be Excellent!\n");
1833: }
1834: }
1835: if (fpecount)
1836: printf("\nA total of %d floating point exceptions were registered.\n",
1837: fpecount);
1838: printf("END OF TEST.\n");
1839: }
1840:
1841: /*SPLIT subs.c
1842: #include "paranoia.h"
1843: */
1844:
1845: /* Sign */
1846:
1847: FLOAT Sign (X)
1848: FLOAT X;
1849: { return X >= 0. ? 1.0 : -1.0; }
1850:
1851: /* Pause */
1852:
1853: Pause()
1854: {
1855: #ifndef NOPAUSE
1856: char ch[8];
1857:
1858: printf("\nTo continue, press RETURN");
1859: fflush(stdout);
1860: read(KEYBOARD, ch, 8);
1861: #endif
1862: printf("\nDiagnosis resumes after milestone Number %d", Milestone);
1863: printf(" Page: %d\n\n", PageNo);
1864: ++Milestone;
1865: ++PageNo;
1866: }
1867:
1868: /* TstCond */
1869:
1870: TstCond (K, Valid, T)
1871: int K, Valid;
1872: char *T;
1873: { if (! Valid) { BadCond(K,T); printf(".\n"); } }
1874:
1875: BadCond(K, T)
1876: int K;
1877: char *T;
1878: {
1879: static char *msg[] = { "FAILURE", "SERIOUS DEFECT", "DEFECT", "FLAW" };
1880:
1881: ErrCnt [K] = ErrCnt [K] + 1;
1882: printf("%s: %s", msg[K], T);
1883: }
1884:
1885: /* Random */
1886: /* Random computes
1887: X = (Random1 + Random9)^5
1888: Random1 = X - FLOOR(X) + 0.000005 * X;
1889: and returns the new value of Random1
1890: */
1891:
1892: FLOAT Random()
1893: {
1894: FLOAT X, Y;
1895:
1896: X = Random1 + Random9;
1897: Y = X * X;
1898: Y = Y * Y;
1899: X = X * Y;
1900: Y = X - FLOOR(X);
1901: Random1 = Y + X * 0.000005;
1902: return(Random1);
1903: }
1904:
1905: /* SqXMinX */
1906:
1907: SqXMinX (ErrKind)
1908: int ErrKind;
1909: {
1910: FLOAT XA, XB;
1911:
1912: XB = X * BInvrse;
1913: XA = X - XB;
1914: SqEr = ((SQRT(X * X) - XB) - XA) / OneUlp;
1915: if (SqEr != Zero) {
1916: if (SqEr < MinSqEr) MinSqEr = SqEr;
1917: if (SqEr > MaxSqEr) MaxSqEr = SqEr;
1918: J = J + 1.0;
1919: BadCond(ErrKind, "\n");
1920: printf("sqrt( %.17e) - %.17e = %.17e\n", X * X, X, OneUlp * SqEr);
1921: printf("\tinstead of correct value 0 .\n");
1922: }
1923: }
1924:
1925: /* NewD */
1926:
1927: NewD()
1928: {
1929: X = Z1 * Q;
1930: X = FLOOR(Half - X / Radix) * Radix + X;
1931: Q = (Q - X * Z) / Radix + X * X * (D / Radix);
1932: Z = Z - Two * X * D;
1933: if (Z <= Zero) {
1934: Z = - Z;
1935: Z1 = - Z1;
1936: }
1937: D = Radix * D;
1938: }
1939:
1940: /* SR3750 */
1941:
1942: SR3750()
1943: {
1944: if (! ((X - Radix < Z2 - Radix) || (X - Z2 > W - Z2))) {
1945: I = I + 1;
1946: X2 = SQRT(X * D);
1947: Y2 = (X2 - Z2) - (Y - Z2);
1948: X2 = X8 / (Y - Half);
1949: X2 = X2 - Half * X2 * X2;
1950: SqEr = (Y2 + Half) + (Half - X2);
1951: if (SqEr < MinSqEr) MinSqEr = SqEr;
1952: SqEr = Y2 - X2;
1953: if (SqEr > MaxSqEr) MaxSqEr = SqEr;
1954: }
1955: }
1956:
1957: /* IsYeqX */
1958:
1959: IsYeqX()
1960: {
1961: if (Y != X) {
1962: if (N <= 0) {
1963: if (Z == Zero && Q <= Zero)
1964: printf("WARNING: computing\n");
1965: else BadCond(Defect, "computing\n");
1966: printf("\t(%.17e) ^ (%.17e)\n", Z, Q);
1967: printf("\tyielded %.17e;\n", Y);
1968: printf("\twhich compared unequal to correct %.17e ;\n",
1969: X);
1970: printf("\t\tthey differ by %.17e .\n", Y - X);
1971: }
1972: N = N + 1; /* ... count discrepancies. */
1973: }
1974: }
1975:
1976: /* SR3980 */
1977:
1978: SR3980()
1979: {
1980: do {
1981: Q = (FLOAT) I;
1982: Y = POW(Z, Q);
1983: IsYeqX();
1984: if (++I > M) break;
1985: X = Z * X;
1986: } while ( X < W );
1987: }
1988:
1989: /* PrintIfNPositive */
1990:
1991: PrintIfNPositive()
1992: {
1993: if (N > 0) printf("Similar discrepancies have occurred %d times.\n", N);
1994: }
1995:
1996: /* TstPtUf */
1997:
1998: TstPtUf()
1999: {
2000: N = 0;
2001: if (Z != Zero) {
2002: printf("Since comparison denies Z = 0, evaluating ");
2003: printf("(Z + Z) / Z should be safe.\n");
2004: sigsave = sigfpe;
2005: if (setjmp(ovfl_buf)) goto very_serious;
2006: Q9 = (Z + Z) / Z;
2007: printf("What the machine gets for (Z + Z) / Z is %.17e .\n",
2008: Q9);
2009: if (FABS(Q9 - Two) < Radix * U2) {
2010: printf("This is O.K., provided Over/Underflow");
2011: printf(" has NOT just been signaled.\n");
2012: }
2013: else {
2014: if ((Q9 < One) || (Q9 > Two)) {
2015: very_serious:
2016: N = 1;
2017: ErrCnt [Serious] = ErrCnt [Serious] + 1;
2018: printf("This is a VERY SERIOUS DEFECT!\n");
2019: }
2020: else {
2021: N = 1;
2022: ErrCnt [Defect] = ErrCnt [Defect] + 1;
2023: printf("This is a DEFECT!\n");
2024: }
2025: }
2026: sigsave = 0;
2027: V9 = Z * One;
2028: Random1 = V9;
2029: V9 = One * Z;
2030: Random2 = V9;
2031: V9 = Z / One;
2032: if ((Z == Random1) && (Z == Random2) && (Z == V9)) {
2033: if (N > 0) Pause();
2034: }
2035: else {
2036: N = 1;
2037: BadCond(Defect, "What prints as Z = ");
2038: printf("%.17e\n\tcompares different from ", Z);
2039: if (Z != Random1) printf("Z * 1 = %.17e ", Random1);
2040: if (! ((Z == Random2)
2041: || (Random2 == Random1)))
2042: printf("1 * Z == %g\n", Random2);
2043: if (! (Z == V9)) printf("Z / 1 = %.17e\n", V9);
2044: if (Random2 != Random1) {
2045: ErrCnt [Defect] = ErrCnt [Defect] + 1;
2046: BadCond(Defect, "Multiplication does not commute!\n");
2047: printf("\tComparison alleges that 1 * Z = %.17e\n",
2048: Random2);
2049: printf("\tdiffers from Z * 1 = %.17e\n", Random1);
2050: }
2051: Pause();
2052: }
2053: }
2054: }
2055:
2056: notify(s)
2057: char *s;
2058: {
2059: printf("%s test appears to be inconsistent...\n", s);
2060: printf(" PLEASE NOTIFY KARPINKSI!\n");
2061: }
2062:
2063: /*SPLIT msgs.c */
2064:
2065: /* Instructions */
2066:
2067: msglist(s)
2068: char **s;
2069: { while(*s) printf("%s\n", *s++); }
2070:
2071: Instructions()
2072: {
2073: static char *instr[] = {
2074: "Lest this program stop prematurely, i.e. before displaying\n",
2075: " `END OF TEST',\n",
2076: "try to persuade the computer NOT to terminate execution when an",
2077: "error like Over/Underflow or Division by Zero occurs, but rather",
2078: "to persevere with a surrogate value after, perhaps, displaying some",
2079: "warning. If persuasion avails naught, don't despair but run this",
2080: "program anyway to see how many milestones it passes, and then",
2081: "amend it to make further progress.\n",
2082: "Answer questions with Y, y, N or n (unless otherwise indicated).\n",
2083: 0};
2084:
2085: msglist(instr);
2086: }
2087:
2088: /* Heading */
2089:
2090: Heading()
2091: {
2092: static char *head[] = {
2093: "Users are invited to help debug and augment this program so it will",
2094: "cope with unanticipated and newly uncovered arithmetic pathologies.\n",
2095: "Please send suggestions and interesting results to",
2096: "\tRichard Karpinski",
2097: "\tComputer Center U-76",
2098: "\tUniversity of California",
2099: "\tSan Francisco, CA 94143-0704, USA\n",
2100: "In doing so, please include the following information:",
2101: #ifdef Single
2102: "\tPrecision:\tsingle;",
2103: #else
2104: "\tPrecision:\tdouble;",
2105: #endif
2106: "\tVersion:\t10 February 1989;",
2107: "\tComputer:\n",
2108: "\tCompiler:\n",
2109: "\tOptimization level:\n",
2110: "\tOther relevant compiler options:",
2111: 0};
2112:
2113: msglist(head);
2114: }
2115:
2116: /* Characteristics */
2117:
2118: Characteristics()
2119: {
2120: static char *chars[] = {
2121: "Running this program should reveal these characteristics:",
2122: " Radix = 1, 2, 4, 8, 10, 16, 100, 256 ...",
2123: " Precision = number of significant digits carried.",
2124: " U2 = Radix/Radix^Precision = One Ulp",
2125: "\t(OneUlpnit in the Last Place) of 1.000xxx .",
2126: " U1 = 1/Radix^Precision = One Ulp of numbers a little less than 1.0 .",
2127: " Adequacy of guard digits for Mult., Div. and Subt.",
2128: " Whether arithmetic is chopped, correctly rounded, or something else",
2129: "\tfor Mult., Div., Add/Subt. and Sqrt.",
2130: " Whether a Sticky Bit used correctly for rounding.",
2131: " UnderflowThreshold = an underflow threshold.",
2132: " E0 and PseudoZero tell whether underflow is abrupt, gradual, or fuzzy.",
2133: " V = an overflow threshold, roughly.",
2134: " V0 tells, roughly, whether Infinity is represented.",
2135: " Comparisions are checked for consistency with subtraction",
2136: "\tand for contamination with pseudo-zeros.",
2137: " Sqrt is tested. Y^X is not tested.",
2138: " Extra-precise subexpressions are revealed but NOT YET tested.",
2139: " Decimal-Binary conversion is NOT YET tested for accuracy.",
2140: 0};
2141:
2142: msglist(chars);
2143: }
2144:
2145: History()
2146:
2147: { /* History */
2148: /* Converted from Brian Wichmann's Pascal version to C by Thos Sumner,
2149: with further massaging by David M. Gay. */
2150:
2151: static char *hist[] = {
2152: "The program attempts to discriminate among",
2153: " FLAWs, like lack of a sticky bit,",
2154: " Serious DEFECTs, like lack of a guard digit, and",
2155: " FAILUREs, like 2+2 == 5 .",
2156: "Failures may confound subsequent diagnoses.\n",
2157: "The diagnostic capabilities of this program go beyond an earlier",
2158: "program called `MACHAR', which can be found at the end of the",
2159: "book `Software Manual for the Elementary Functions' (1980) by",
2160: "W. J. Cody and W. Waite. Although both programs try to discover",
2161: "the Radix, Precision and range (over/underflow thresholds)",
2162: "of the arithmetic, this program tries to cope with a wider variety",
2163: "of pathologies, and to say how well the arithmetic is implemented.",
2164: "\nThe program is based upon a conventional radix representation for",
2165: "floating-point numbers, but also allows logarithmic encoding",
2166: "as used by certain early WANG machines.\n",
2167: "BASIC version of this program (C) 1983 by Prof. W. M. Kahan;",
2168: "see source comments for more history.",
2169: 0};
2170:
2171: msglist(hist);
2172: }
2173:
2174: double
2175: pow(x, y) /* return x ^ y (exponentiation) */
2176: double x, y;
2177: {
2178: extern double exp(), frexp(), ldexp(), log(), modf();
2179: double xy, ye;
2180: long i;
2181: int ex, ey = 0, flip = 0;
2182:
2183: if (!y) return 1.0;
2184:
2185: if ((y < -1100. || y > 1100.) && x != -1.) return exp(y * log(x));
2186:
2187: if (y < 0.) { y = -y; flip = 1; }
2188: y = modf(y, &ye);
2189: if (y) xy = exp(y * log(x));
2190: else xy = 1.0;
2191: /* next several lines assume >= 32 bit integers */
2192: x = frexp(x, &ex);
2193: if (i = ye) for(;;) {
2194: if (i & 1) { xy *= x; ey += ex; }
2195: if (!(i >>= 1)) break;
2196: x *= x;
2197: ex *= 2;
2198: if (x < .5) { x *= 2.; ex -= 1; }
2199: }
2200: if (flip) { xy = 1. / xy; ey = -ey; }
2201: return ldexp(xy, ey);
2202: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.