source: rtems/testsuites/samples/paranoia/paranoia.c @ cdf44d93

4.104.115
Last change on this file since cdf44d93 was cdf44d93, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 03/29/10 at 11:30:49

exclude big samples for SMALL MEMORY BSPs

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