1*7e568061Sespie /* A C version of Kahan's Floating Point Test "Paranoia"
2*7e568061Sespie
3*7e568061Sespie Thos Sumner, UCSF, Feb. 1985
4*7e568061Sespie David Gay, BTL, Jan. 1986
5*7e568061Sespie
6*7e568061Sespie This is a rewrite from the Pascal version by
7*7e568061Sespie
8*7e568061Sespie B. A. Wichmann, 18 Jan. 1985
9*7e568061Sespie
10*7e568061Sespie (and does NOT exhibit good C programming style).
11*7e568061Sespie
12*7e568061Sespie Adjusted to use Standard C headers 19 Jan. 1992 (dmg);
13*7e568061Sespie
14*7e568061Sespie (C) Apr 19 1983 in BASIC version by:
15*7e568061Sespie Professor W. M. Kahan,
16*7e568061Sespie 567 Evans Hall
17*7e568061Sespie Electrical Engineering & Computer Science Dept.
18*7e568061Sespie University of California
19*7e568061Sespie Berkeley, California 94720
20*7e568061Sespie USA
21*7e568061Sespie
22*7e568061Sespie converted to Pascal by:
23*7e568061Sespie B. A. Wichmann
24*7e568061Sespie National Physical Laboratory
25*7e568061Sespie Teddington Middx
26*7e568061Sespie TW11 OLW
27*7e568061Sespie UK
28*7e568061Sespie
29*7e568061Sespie converted to C by:
30*7e568061Sespie
31*7e568061Sespie David M. Gay and Thos Sumner
32*7e568061Sespie AT&T Bell Labs Computer Center, Rm. U-76
33*7e568061Sespie 600 Mountain Avenue University of California
34*7e568061Sespie Murray Hill, NJ 07974 San Francisco, CA 94143
35*7e568061Sespie USA USA
36*7e568061Sespie
37*7e568061Sespie with simultaneous corrections to the Pascal source (reflected
38*7e568061Sespie in the Pascal source available over netlib).
39*7e568061Sespie [A couple of bug fixes from dgh = sun!dhough incorporated 31 July 1986.]
40*7e568061Sespie
41*7e568061Sespie Reports of results on various systems from all the versions
42*7e568061Sespie of Paranoia are being collected by Richard Karpinski at the
43*7e568061Sespie same address as Thos Sumner. This includes sample outputs,
44*7e568061Sespie bug reports, and criticisms.
45*7e568061Sespie
46*7e568061Sespie You may copy this program freely if you acknowledge its source.
47*7e568061Sespie Comments on the Pascal version to NPL, please.
48*7e568061Sespie
49*7e568061Sespie The following is from the introductory commentary from Wichmann's work:
50*7e568061Sespie
51*7e568061Sespie The BASIC program of Kahan is written in Microsoft BASIC using many
52*7e568061Sespie facilities which have no exact analogy in Pascal. The Pascal
53*7e568061Sespie version below cannot therefore be exactly the same. Rather than be
54*7e568061Sespie a minimal transcription of the BASIC program, the Pascal coding
55*7e568061Sespie follows the conventional style of block-structured languages. Hence
56*7e568061Sespie the Pascal version could be useful in producing versions in other
57*7e568061Sespie structured languages.
58*7e568061Sespie
59*7e568061Sespie Rather than use identifiers of minimal length (which therefore have
60*7e568061Sespie little mnemonic significance), the Pascal version uses meaningful
61*7e568061Sespie identifiers as follows [Note: A few changes have been made for C]:
62*7e568061Sespie
63*7e568061Sespie
64*7e568061Sespie BASIC C BASIC C BASIC C
65*7e568061Sespie
66*7e568061Sespie A J S StickyBit
67*7e568061Sespie A1 AInverse J0 NoErrors T
68*7e568061Sespie B Radix [Failure] T0 Underflow
69*7e568061Sespie B1 BInverse J1 NoErrors T2 ThirtyTwo
70*7e568061Sespie B2 RadixD2 [SeriousDefect] T5 OneAndHalf
71*7e568061Sespie B9 BMinusU2 J2 NoErrors T7 TwentySeven
72*7e568061Sespie C [Defect] T8 TwoForty
73*7e568061Sespie C1 CInverse J3 NoErrors U OneUlp
74*7e568061Sespie D [Flaw] U0 UnderflowThreshold
75*7e568061Sespie D4 FourD K PageNo U1
76*7e568061Sespie E0 L Milestone U2
77*7e568061Sespie E1 M V
78*7e568061Sespie E2 Exp2 N V0
79*7e568061Sespie E3 N1 V8
80*7e568061Sespie E5 MinSqEr O Zero V9
81*7e568061Sespie E6 SqEr O1 One W
82*7e568061Sespie E7 MaxSqEr O2 Two X
83*7e568061Sespie E8 O3 Three X1
84*7e568061Sespie E9 O4 Four X8
85*7e568061Sespie F1 MinusOne O5 Five X9 Random1
86*7e568061Sespie F2 Half O8 Eight Y
87*7e568061Sespie F3 Third O9 Nine Y1
88*7e568061Sespie F6 P Precision Y2
89*7e568061Sespie F9 Q Y9 Random2
90*7e568061Sespie G1 GMult Q8 Z
91*7e568061Sespie G2 GDiv Q9 Z0 PseudoZero
92*7e568061Sespie G3 GAddSub R Z1
93*7e568061Sespie H R1 RMult Z2
94*7e568061Sespie H1 HInverse R2 RDiv Z9
95*7e568061Sespie I R3 RAddSub
96*7e568061Sespie IO NoTrials R4 RSqrt
97*7e568061Sespie I3 IEEE R9 Random9
98*7e568061Sespie
99*7e568061Sespie SqRWrng
100*7e568061Sespie
101*7e568061Sespie All the variables in BASIC are true variables and in consequence,
102*7e568061Sespie the program is more difficult to follow since the "constants" must
103*7e568061Sespie be determined (the glossary is very helpful). The Pascal version
104*7e568061Sespie uses Real constants, but checks are added to ensure that the values
105*7e568061Sespie are correctly converted by the compiler.
106*7e568061Sespie
107*7e568061Sespie The major textual change to the Pascal version apart from the
108*7e568061Sespie identifiersis that named procedures are used, inserting parameters
109*7e568061Sespie wherehelpful. New procedures are also introduced. The
110*7e568061Sespie correspondence is as follows:
111*7e568061Sespie
112*7e568061Sespie
113*7e568061Sespie BASIC Pascal
114*7e568061Sespie lines
115*7e568061Sespie
116*7e568061Sespie 90- 140 Pause
117*7e568061Sespie 170- 250 Instructions
118*7e568061Sespie 380- 460 Heading
119*7e568061Sespie 480- 670 Characteristics
120*7e568061Sespie 690- 870 History
121*7e568061Sespie 2940-2950 Random
122*7e568061Sespie 3710-3740 NewD
123*7e568061Sespie 4040-4080 DoesYequalX
124*7e568061Sespie 4090-4110 PrintIfNPositive
125*7e568061Sespie 4640-4850 TestPartialUnderflow
126*7e568061Sespie
127*7e568061Sespie */
128*7e568061Sespie
129*7e568061Sespie /* This version of paranoia has been modified to work with GCC's internal
130*7e568061Sespie software floating point emulation library, as a sanity check of same.
131*7e568061Sespie
132*7e568061Sespie I'm doing this in C++ so that I can do operator overloading and not
133*7e568061Sespie have to modify so damned much of the existing code. */
134*7e568061Sespie
135*7e568061Sespie extern "C" {
136*7e568061Sespie #include <stdio.h>
137*7e568061Sespie #include <stddef.h>
138*7e568061Sespie #include <limits.h>
139*7e568061Sespie #include <string.h>
140*7e568061Sespie #include <stdlib.h>
141*7e568061Sespie #include <math.h>
142*7e568061Sespie #include <unistd.h>
143*7e568061Sespie #include <float.h>
144*7e568061Sespie
145*7e568061Sespie /* This part is made all the more awful because many gcc headers are
146*7e568061Sespie not prepared at all to be parsed as C++. The biggest stickler
147*7e568061Sespie here is const structure members. So we include exactly the pieces
148*7e568061Sespie that we need. */
149*7e568061Sespie
150*7e568061Sespie #define GTY(x)
151*7e568061Sespie
152*7e568061Sespie #include "ansidecl.h"
153*7e568061Sespie #include "auto-host.h"
154*7e568061Sespie #include "hwint.h"
155*7e568061Sespie
156*7e568061Sespie #undef EXTRA_MODES_FILE
157*7e568061Sespie
158*7e568061Sespie struct rtx_def;
159*7e568061Sespie typedef struct rtx_def *rtx;
160*7e568061Sespie struct rtvec_def;
161*7e568061Sespie typedef struct rtvec_def *rtvec;
162*7e568061Sespie union tree_node;
163*7e568061Sespie typedef union tree_node *tree;
164*7e568061Sespie
165*7e568061Sespie #define DEFTREECODE(SYM, STRING, TYPE, NARGS) SYM,
166*7e568061Sespie enum tree_code {
167*7e568061Sespie #include "tree.def"
168*7e568061Sespie LAST_AND_UNUSED_TREE_CODE
169*7e568061Sespie };
170*7e568061Sespie #undef DEFTREECODE
171*7e568061Sespie
172*7e568061Sespie #define ENUM_BITFIELD(X) enum X
173*7e568061Sespie #define class klass
174*7e568061Sespie
175*7e568061Sespie #include "real.h"
176*7e568061Sespie
177*7e568061Sespie #undef class
178*7e568061Sespie }
179*7e568061Sespie
180*7e568061Sespie /* We never produce signals from the library. Thus setjmp need do nothing. */
181*7e568061Sespie #undef setjmp
182*7e568061Sespie #define setjmp(x) (0)
183*7e568061Sespie
184*7e568061Sespie static bool verbose = false;
185*7e568061Sespie static int verbose_index = 0;
186*7e568061Sespie
187*7e568061Sespie /* ====================================================================== */
188*7e568061Sespie /* The implementation of the abstract floating point class based on gcc's
189*7e568061Sespie real.c. I.e. the object of this excersize. Templated so that we can
190*7e568061Sespie all fp sizes. */
191*7e568061Sespie
192*7e568061Sespie class real_c_float
193*7e568061Sespie {
194*7e568061Sespie public:
195*7e568061Sespie static const enum machine_mode MODE = SFmode;
196*7e568061Sespie
197*7e568061Sespie private:
198*7e568061Sespie static const int external_max = 128 / 32;
199*7e568061Sespie static const int internal_max
200*7e568061Sespie = (sizeof (REAL_VALUE_TYPE) + sizeof (long) + 1) / sizeof (long);
201*7e568061Sespie long image[external_max < internal_max ? internal_max : external_max];
202*7e568061Sespie
203*7e568061Sespie void from_long(long);
204*7e568061Sespie void from_str(const char *);
205*7e568061Sespie void binop(int code, const real_c_float&);
206*7e568061Sespie void unop(int code);
207*7e568061Sespie bool cmp(int code, const real_c_float&) const;
208*7e568061Sespie
209*7e568061Sespie public:
real_c_float()210*7e568061Sespie real_c_float()
211*7e568061Sespie { }
real_c_float(long l)212*7e568061Sespie real_c_float(long l)
213*7e568061Sespie { from_long(l); }
real_c_float(const char * s)214*7e568061Sespie real_c_float(const char *s)
215*7e568061Sespie { from_str(s); }
real_c_float(const real_c_float & b)216*7e568061Sespie real_c_float(const real_c_float &b)
217*7e568061Sespie { memcpy(image, b.image, sizeof(image)); }
218*7e568061Sespie
operator =(long l)219*7e568061Sespie const real_c_float& operator= (long l)
220*7e568061Sespie { from_long(l); return *this; }
operator =(const char * s)221*7e568061Sespie const real_c_float& operator= (const char *s)
222*7e568061Sespie { from_str(s); return *this; }
operator =(const real_c_float & b)223*7e568061Sespie const real_c_float& operator= (const real_c_float &b)
224*7e568061Sespie { memcpy(image, b.image, sizeof(image)); return *this; }
225*7e568061Sespie
operator +=(const real_c_float & b)226*7e568061Sespie const real_c_float& operator+= (const real_c_float &b)
227*7e568061Sespie { binop(PLUS_EXPR, b); return *this; }
operator -=(const real_c_float & b)228*7e568061Sespie const real_c_float& operator-= (const real_c_float &b)
229*7e568061Sespie { binop(MINUS_EXPR, b); return *this; }
operator *=(const real_c_float & b)230*7e568061Sespie const real_c_float& operator*= (const real_c_float &b)
231*7e568061Sespie { binop(MULT_EXPR, b); return *this; }
operator /=(const real_c_float & b)232*7e568061Sespie const real_c_float& operator/= (const real_c_float &b)
233*7e568061Sespie { binop(RDIV_EXPR, b); return *this; }
234*7e568061Sespie
operator -() const235*7e568061Sespie real_c_float operator- () const
236*7e568061Sespie { real_c_float r(*this); r.unop(NEGATE_EXPR); return r; }
abs() const237*7e568061Sespie real_c_float abs () const
238*7e568061Sespie { real_c_float r(*this); r.unop(ABS_EXPR); return r; }
239*7e568061Sespie
operator <(const real_c_float & b) const240*7e568061Sespie bool operator < (const real_c_float &b) const { return cmp(LT_EXPR, b); }
operator <=(const real_c_float & b) const241*7e568061Sespie bool operator <= (const real_c_float &b) const { return cmp(LE_EXPR, b); }
operator ==(const real_c_float & b) const242*7e568061Sespie bool operator == (const real_c_float &b) const { return cmp(EQ_EXPR, b); }
operator !=(const real_c_float & b) const243*7e568061Sespie bool operator != (const real_c_float &b) const { return cmp(NE_EXPR, b); }
operator >=(const real_c_float & b) const244*7e568061Sespie bool operator >= (const real_c_float &b) const { return cmp(GE_EXPR, b); }
operator >(const real_c_float & b) const245*7e568061Sespie bool operator > (const real_c_float &b) const { return cmp(GT_EXPR, b); }
246*7e568061Sespie
247*7e568061Sespie const char * str () const;
248*7e568061Sespie const char * hex () const;
249*7e568061Sespie long integer () const;
250*7e568061Sespie int exp () const;
251*7e568061Sespie void ldexp (int);
252*7e568061Sespie };
253*7e568061Sespie
254*7e568061Sespie void
from_long(long l)255*7e568061Sespie real_c_float::from_long (long l)
256*7e568061Sespie {
257*7e568061Sespie REAL_VALUE_TYPE f;
258*7e568061Sespie
259*7e568061Sespie real_from_integer (&f, MODE, l, l < 0 ? -1 : 0, 0);
260*7e568061Sespie real_to_target (image, &f, MODE);
261*7e568061Sespie }
262*7e568061Sespie
263*7e568061Sespie void
from_str(const char * s)264*7e568061Sespie real_c_float::from_str (const char *s)
265*7e568061Sespie {
266*7e568061Sespie REAL_VALUE_TYPE f;
267*7e568061Sespie const char *p = s;
268*7e568061Sespie
269*7e568061Sespie if (*p == '-' || *p == '+')
270*7e568061Sespie p++;
271*7e568061Sespie if (strcasecmp(p, "inf") == 0)
272*7e568061Sespie {
273*7e568061Sespie real_inf (&f);
274*7e568061Sespie if (*s == '-')
275*7e568061Sespie real_arithmetic (&f, NEGATE_EXPR, &f, NULL);
276*7e568061Sespie }
277*7e568061Sespie else if (strcasecmp(p, "nan") == 0)
278*7e568061Sespie real_nan (&f, "", 1, MODE);
279*7e568061Sespie else
280*7e568061Sespie real_from_string (&f, s);
281*7e568061Sespie
282*7e568061Sespie real_to_target (image, &f, MODE);
283*7e568061Sespie }
284*7e568061Sespie
285*7e568061Sespie void
binop(int code,const real_c_float & b)286*7e568061Sespie real_c_float::binop (int code, const real_c_float &b)
287*7e568061Sespie {
288*7e568061Sespie REAL_VALUE_TYPE ai, bi, ri;
289*7e568061Sespie
290*7e568061Sespie real_from_target (&ai, image, MODE);
291*7e568061Sespie real_from_target (&bi, b.image, MODE);
292*7e568061Sespie real_arithmetic (&ri, code, &ai, &bi);
293*7e568061Sespie real_to_target (image, &ri, MODE);
294*7e568061Sespie
295*7e568061Sespie if (verbose)
296*7e568061Sespie {
297*7e568061Sespie char ab[64], bb[64], rb[64];
298*7e568061Sespie const real_format *fmt = real_format_for_mode[MODE - QFmode];
299*7e568061Sespie const int digits = (fmt->p * fmt->log2_b + 3) / 4;
300*7e568061Sespie char symbol_for_code;
301*7e568061Sespie
302*7e568061Sespie real_from_target (&ri, image, MODE);
303*7e568061Sespie real_to_hexadecimal (ab, &ai, sizeof(ab), digits, 0);
304*7e568061Sespie real_to_hexadecimal (bb, &bi, sizeof(bb), digits, 0);
305*7e568061Sespie real_to_hexadecimal (rb, &ri, sizeof(rb), digits, 0);
306*7e568061Sespie
307*7e568061Sespie switch (code)
308*7e568061Sespie {
309*7e568061Sespie case PLUS_EXPR:
310*7e568061Sespie symbol_for_code = '+';
311*7e568061Sespie break;
312*7e568061Sespie case MINUS_EXPR:
313*7e568061Sespie symbol_for_code = '-';
314*7e568061Sespie break;
315*7e568061Sespie case MULT_EXPR:
316*7e568061Sespie symbol_for_code = '*';
317*7e568061Sespie break;
318*7e568061Sespie case RDIV_EXPR:
319*7e568061Sespie symbol_for_code = '/';
320*7e568061Sespie break;
321*7e568061Sespie default:
322*7e568061Sespie abort ();
323*7e568061Sespie }
324*7e568061Sespie
325*7e568061Sespie fprintf (stderr, "%6d: %s %c %s = %s\n", verbose_index++,
326*7e568061Sespie ab, symbol_for_code, bb, rb);
327*7e568061Sespie }
328*7e568061Sespie }
329*7e568061Sespie
330*7e568061Sespie void
unop(int code)331*7e568061Sespie real_c_float::unop (int code)
332*7e568061Sespie {
333*7e568061Sespie REAL_VALUE_TYPE ai, ri;
334*7e568061Sespie
335*7e568061Sespie real_from_target (&ai, image, MODE);
336*7e568061Sespie real_arithmetic (&ri, code, &ai, NULL);
337*7e568061Sespie real_to_target (image, &ri, MODE);
338*7e568061Sespie
339*7e568061Sespie if (verbose)
340*7e568061Sespie {
341*7e568061Sespie char ab[64], rb[64];
342*7e568061Sespie const real_format *fmt = real_format_for_mode[MODE - QFmode];
343*7e568061Sespie const int digits = (fmt->p * fmt->log2_b + 3) / 4;
344*7e568061Sespie const char *symbol_for_code;
345*7e568061Sespie
346*7e568061Sespie real_from_target (&ri, image, MODE);
347*7e568061Sespie real_to_hexadecimal (ab, &ai, sizeof(ab), digits, 0);
348*7e568061Sespie real_to_hexadecimal (rb, &ri, sizeof(rb), digits, 0);
349*7e568061Sespie
350*7e568061Sespie switch (code)
351*7e568061Sespie {
352*7e568061Sespie case NEGATE_EXPR:
353*7e568061Sespie symbol_for_code = "-";
354*7e568061Sespie break;
355*7e568061Sespie case ABS_EXPR:
356*7e568061Sespie symbol_for_code = "abs ";
357*7e568061Sespie break;
358*7e568061Sespie default:
359*7e568061Sespie abort ();
360*7e568061Sespie }
361*7e568061Sespie
362*7e568061Sespie fprintf (stderr, "%6d: %s%s = %s\n", verbose_index++,
363*7e568061Sespie symbol_for_code, ab, rb);
364*7e568061Sespie }
365*7e568061Sespie }
366*7e568061Sespie
367*7e568061Sespie bool
cmp(int code,const real_c_float & b) const368*7e568061Sespie real_c_float::cmp (int code, const real_c_float &b) const
369*7e568061Sespie {
370*7e568061Sespie REAL_VALUE_TYPE ai, bi;
371*7e568061Sespie bool ret;
372*7e568061Sespie
373*7e568061Sespie real_from_target (&ai, image, MODE);
374*7e568061Sespie real_from_target (&bi, b.image, MODE);
375*7e568061Sespie ret = real_compare (code, &ai, &bi);
376*7e568061Sespie
377*7e568061Sespie if (verbose)
378*7e568061Sespie {
379*7e568061Sespie char ab[64], bb[64];
380*7e568061Sespie const real_format *fmt = real_format_for_mode[MODE - QFmode];
381*7e568061Sespie const int digits = (fmt->p * fmt->log2_b + 3) / 4;
382*7e568061Sespie const char *symbol_for_code;
383*7e568061Sespie
384*7e568061Sespie real_to_hexadecimal (ab, &ai, sizeof(ab), digits, 0);
385*7e568061Sespie real_to_hexadecimal (bb, &bi, sizeof(bb), digits, 0);
386*7e568061Sespie
387*7e568061Sespie switch (code)
388*7e568061Sespie {
389*7e568061Sespie case LT_EXPR:
390*7e568061Sespie symbol_for_code = "<";
391*7e568061Sespie break;
392*7e568061Sespie case LE_EXPR:
393*7e568061Sespie symbol_for_code = "<=";
394*7e568061Sespie break;
395*7e568061Sespie case EQ_EXPR:
396*7e568061Sespie symbol_for_code = "==";
397*7e568061Sespie break;
398*7e568061Sespie case NE_EXPR:
399*7e568061Sespie symbol_for_code = "!=";
400*7e568061Sespie break;
401*7e568061Sespie case GE_EXPR:
402*7e568061Sespie symbol_for_code = ">=";
403*7e568061Sespie break;
404*7e568061Sespie case GT_EXPR:
405*7e568061Sespie symbol_for_code = ">";
406*7e568061Sespie break;
407*7e568061Sespie default:
408*7e568061Sespie abort ();
409*7e568061Sespie }
410*7e568061Sespie
411*7e568061Sespie fprintf (stderr, "%6d: %s %s %s = %s\n", verbose_index++,
412*7e568061Sespie ab, symbol_for_code, bb, (ret ? "true" : "false"));
413*7e568061Sespie }
414*7e568061Sespie
415*7e568061Sespie return ret;
416*7e568061Sespie }
417*7e568061Sespie
418*7e568061Sespie const char *
str() const419*7e568061Sespie real_c_float::str() const
420*7e568061Sespie {
421*7e568061Sespie REAL_VALUE_TYPE f;
422*7e568061Sespie const real_format *fmt = real_format_for_mode[MODE - QFmode];
423*7e568061Sespie const int digits = int(fmt->p * fmt->log2_b * .30102999566398119521 + 1);
424*7e568061Sespie
425*7e568061Sespie real_from_target (&f, image, MODE);
426*7e568061Sespie char *buf = new char[digits + 10];
427*7e568061Sespie real_to_decimal (buf, &f, digits+10, digits, 0);
428*7e568061Sespie
429*7e568061Sespie return buf;
430*7e568061Sespie }
431*7e568061Sespie
432*7e568061Sespie const char *
hex() const433*7e568061Sespie real_c_float::hex() const
434*7e568061Sespie {
435*7e568061Sespie REAL_VALUE_TYPE f;
436*7e568061Sespie const real_format *fmt = real_format_for_mode[MODE - QFmode];
437*7e568061Sespie const int digits = (fmt->p * fmt->log2_b + 3) / 4;
438*7e568061Sespie
439*7e568061Sespie real_from_target (&f, image, MODE);
440*7e568061Sespie char *buf = new char[digits + 10];
441*7e568061Sespie real_to_hexadecimal (buf, &f, digits+10, digits, 0);
442*7e568061Sespie
443*7e568061Sespie return buf;
444*7e568061Sespie }
445*7e568061Sespie
446*7e568061Sespie long
integer() const447*7e568061Sespie real_c_float::integer() const
448*7e568061Sespie {
449*7e568061Sespie REAL_VALUE_TYPE f;
450*7e568061Sespie real_from_target (&f, image, MODE);
451*7e568061Sespie return real_to_integer (&f);
452*7e568061Sespie }
453*7e568061Sespie
454*7e568061Sespie int
exp() const455*7e568061Sespie real_c_float::exp() const
456*7e568061Sespie {
457*7e568061Sespie REAL_VALUE_TYPE f;
458*7e568061Sespie real_from_target (&f, image, MODE);
459*7e568061Sespie return real_exponent (&f);
460*7e568061Sespie }
461*7e568061Sespie
462*7e568061Sespie void
ldexp(int exp)463*7e568061Sespie real_c_float::ldexp (int exp)
464*7e568061Sespie {
465*7e568061Sespie REAL_VALUE_TYPE ai;
466*7e568061Sespie
467*7e568061Sespie real_from_target (&ai, image, MODE);
468*7e568061Sespie real_ldexp (&ai, &ai, exp);
469*7e568061Sespie real_to_target (image, &ai, MODE);
470*7e568061Sespie }
471*7e568061Sespie
472*7e568061Sespie /* ====================================================================== */
473*7e568061Sespie /* An implementation of the abstract floating point class that uses native
474*7e568061Sespie arithmetic. Exists for reference and debugging. */
475*7e568061Sespie
476*7e568061Sespie template<typename T>
477*7e568061Sespie class native_float
478*7e568061Sespie {
479*7e568061Sespie private:
480*7e568061Sespie // Force intermediate results back to memory.
481*7e568061Sespie volatile T image;
482*7e568061Sespie
483*7e568061Sespie static T from_str (const char *);
484*7e568061Sespie static T do_abs (T);
485*7e568061Sespie static T verbose_binop (T, char, T, T);
486*7e568061Sespie static T verbose_unop (const char *, T, T);
487*7e568061Sespie static bool verbose_cmp (T, const char *, T, bool);
488*7e568061Sespie
489*7e568061Sespie public:
native_float()490*7e568061Sespie native_float()
491*7e568061Sespie { }
native_float(long l)492*7e568061Sespie native_float(long l)
493*7e568061Sespie { image = l; }
native_float(const char * s)494*7e568061Sespie native_float(const char *s)
495*7e568061Sespie { image = from_str(s); }
native_float(const native_float & b)496*7e568061Sespie native_float(const native_float &b)
497*7e568061Sespie { image = b.image; }
498*7e568061Sespie
operator =(long l)499*7e568061Sespie const native_float& operator= (long l)
500*7e568061Sespie { image = l; return *this; }
operator =(const char * s)501*7e568061Sespie const native_float& operator= (const char *s)
502*7e568061Sespie { image = from_str(s); return *this; }
operator =(const native_float & b)503*7e568061Sespie const native_float& operator= (const native_float &b)
504*7e568061Sespie { image = b.image; return *this; }
505*7e568061Sespie
operator +=(const native_float & b)506*7e568061Sespie const native_float& operator+= (const native_float &b)
507*7e568061Sespie {
508*7e568061Sespie image = verbose_binop(image, '+', b.image, image + b.image);
509*7e568061Sespie return *this;
510*7e568061Sespie }
operator -=(const native_float & b)511*7e568061Sespie const native_float& operator-= (const native_float &b)
512*7e568061Sespie {
513*7e568061Sespie image = verbose_binop(image, '-', b.image, image - b.image);
514*7e568061Sespie return *this;
515*7e568061Sespie }
operator *=(const native_float & b)516*7e568061Sespie const native_float& operator*= (const native_float &b)
517*7e568061Sespie {
518*7e568061Sespie image = verbose_binop(image, '*', b.image, image * b.image);
519*7e568061Sespie return *this;
520*7e568061Sespie }
operator /=(const native_float & b)521*7e568061Sespie const native_float& operator/= (const native_float &b)
522*7e568061Sespie {
523*7e568061Sespie image = verbose_binop(image, '/', b.image, image / b.image);
524*7e568061Sespie return *this;
525*7e568061Sespie }
526*7e568061Sespie
operator -() const527*7e568061Sespie native_float operator- () const
528*7e568061Sespie {
529*7e568061Sespie native_float r;
530*7e568061Sespie r.image = verbose_unop("-", image, -image);
531*7e568061Sespie return r;
532*7e568061Sespie }
abs() const533*7e568061Sespie native_float abs () const
534*7e568061Sespie {
535*7e568061Sespie native_float r;
536*7e568061Sespie r.image = verbose_unop("abs ", image, do_abs(image));
537*7e568061Sespie return r;
538*7e568061Sespie }
539*7e568061Sespie
operator <(const native_float & b) const540*7e568061Sespie bool operator < (const native_float &b) const
541*7e568061Sespie { return verbose_cmp(image, "<", b.image, image < b.image); }
operator <=(const native_float & b) const542*7e568061Sespie bool operator <= (const native_float &b) const
543*7e568061Sespie { return verbose_cmp(image, "<=", b.image, image <= b.image); }
operator ==(const native_float & b) const544*7e568061Sespie bool operator == (const native_float &b) const
545*7e568061Sespie { return verbose_cmp(image, "==", b.image, image == b.image); }
operator !=(const native_float & b) const546*7e568061Sespie bool operator != (const native_float &b) const
547*7e568061Sespie { return verbose_cmp(image, "!=", b.image, image != b.image); }
operator >=(const native_float & b) const548*7e568061Sespie bool operator >= (const native_float &b) const
549*7e568061Sespie { return verbose_cmp(image, ">=", b.image, image >= b.image); }
operator >(const native_float & b) const550*7e568061Sespie bool operator > (const native_float &b) const
551*7e568061Sespie { return verbose_cmp(image, ">", b.image, image > b.image); }
552*7e568061Sespie
553*7e568061Sespie const char * str () const;
554*7e568061Sespie const char * hex () const;
integer() const555*7e568061Sespie long integer () const
556*7e568061Sespie { return long(image); }
557*7e568061Sespie int exp () const;
558*7e568061Sespie void ldexp (int);
559*7e568061Sespie };
560*7e568061Sespie
561*7e568061Sespie template<typename T>
562*7e568061Sespie inline T
from_str(const char * s)563*7e568061Sespie native_float<T>::from_str (const char *s)
564*7e568061Sespie {
565*7e568061Sespie return strtold (s, NULL);
566*7e568061Sespie }
567*7e568061Sespie
568*7e568061Sespie template<>
569*7e568061Sespie inline float
from_str(const char * s)570*7e568061Sespie native_float<float>::from_str (const char *s)
571*7e568061Sespie {
572*7e568061Sespie return strtof (s, NULL);
573*7e568061Sespie }
574*7e568061Sespie
575*7e568061Sespie template<>
576*7e568061Sespie inline double
from_str(const char * s)577*7e568061Sespie native_float<double>::from_str (const char *s)
578*7e568061Sespie {
579*7e568061Sespie return strtod (s, NULL);
580*7e568061Sespie }
581*7e568061Sespie
582*7e568061Sespie template<typename T>
583*7e568061Sespie inline T
do_abs(T image)584*7e568061Sespie native_float<T>::do_abs (T image)
585*7e568061Sespie {
586*7e568061Sespie return fabsl (image);
587*7e568061Sespie }
588*7e568061Sespie
589*7e568061Sespie template<>
590*7e568061Sespie inline float
do_abs(float image)591*7e568061Sespie native_float<float>::do_abs (float image)
592*7e568061Sespie {
593*7e568061Sespie return fabsf (image);
594*7e568061Sespie }
595*7e568061Sespie
596*7e568061Sespie template<>
597*7e568061Sespie inline double
do_abs(double image)598*7e568061Sespie native_float<double>::do_abs (double image)
599*7e568061Sespie {
600*7e568061Sespie return fabs (image);
601*7e568061Sespie }
602*7e568061Sespie
603*7e568061Sespie template<typename T>
604*7e568061Sespie T
verbose_binop(T a,char symbol,T b,T r)605*7e568061Sespie native_float<T>::verbose_binop (T a, char symbol, T b, T r)
606*7e568061Sespie {
607*7e568061Sespie if (verbose)
608*7e568061Sespie {
609*7e568061Sespie const int digits = int(sizeof(T) * CHAR_BIT / 4) - 1;
610*7e568061Sespie #ifdef NO_LONG_DOUBLE
611*7e568061Sespie fprintf (stderr, "%6d: %.*a %c %.*a = %.*a\n", verbose_index++,
612*7e568061Sespie digits, (double)a, symbol,
613*7e568061Sespie digits, (double)b, digits, (double)r);
614*7e568061Sespie #else
615*7e568061Sespie fprintf (stderr, "%6d: %.*La %c %.*La = %.*La\n", verbose_index++,
616*7e568061Sespie digits, (long double)a, symbol,
617*7e568061Sespie digits, (long double)b, digits, (long double)r);
618*7e568061Sespie #endif
619*7e568061Sespie }
620*7e568061Sespie return r;
621*7e568061Sespie }
622*7e568061Sespie
623*7e568061Sespie template<typename T>
624*7e568061Sespie T
verbose_unop(const char * symbol,T a,T r)625*7e568061Sespie native_float<T>::verbose_unop (const char *symbol, T a, T r)
626*7e568061Sespie {
627*7e568061Sespie if (verbose)
628*7e568061Sespie {
629*7e568061Sespie const int digits = int(sizeof(T) * CHAR_BIT / 4) - 1;
630*7e568061Sespie #ifdef NO_LONG_DOUBLE
631*7e568061Sespie fprintf (stderr, "%6d: %s%.*a = %.*a\n", verbose_index++,
632*7e568061Sespie symbol, digits, (double)a, digits, (double)r);
633*7e568061Sespie #else
634*7e568061Sespie fprintf (stderr, "%6d: %s%.*La = %.*La\n", verbose_index++,
635*7e568061Sespie symbol, digits, (long double)a, digits, (long double)r);
636*7e568061Sespie #endif
637*7e568061Sespie }
638*7e568061Sespie return r;
639*7e568061Sespie }
640*7e568061Sespie
641*7e568061Sespie template<typename T>
642*7e568061Sespie bool
verbose_cmp(T a,const char * symbol,T b,bool r)643*7e568061Sespie native_float<T>::verbose_cmp (T a, const char *symbol, T b, bool r)
644*7e568061Sespie {
645*7e568061Sespie if (verbose)
646*7e568061Sespie {
647*7e568061Sespie const int digits = int(sizeof(T) * CHAR_BIT / 4) - 1;
648*7e568061Sespie #ifndef NO_LONG_DOUBLE
649*7e568061Sespie fprintf (stderr, "%6d: %.*a %s %.*a = %s\n", verbose_index++,
650*7e568061Sespie digits, (double)a, symbol,
651*7e568061Sespie digits, (double)b, (r ? "true" : "false"));
652*7e568061Sespie #else
653*7e568061Sespie fprintf (stderr, "%6d: %.*La %s %.*La = %s\n", verbose_index++,
654*7e568061Sespie digits, (long double)a, symbol,
655*7e568061Sespie digits, (long double)b, (r ? "true" : "false"));
656*7e568061Sespie #endif
657*7e568061Sespie }
658*7e568061Sespie return r;
659*7e568061Sespie }
660*7e568061Sespie
661*7e568061Sespie template<typename T>
662*7e568061Sespie const char *
str() const663*7e568061Sespie native_float<T>::str() const
664*7e568061Sespie {
665*7e568061Sespie char *buf = new char[50];
666*7e568061Sespie const int digits = int(sizeof(T) * CHAR_BIT * .30102999566398119521 + 1);
667*7e568061Sespie #ifndef NO_LONG_DOUBLE
668*7e568061Sespie sprintf (buf, "%.*e", digits - 1, (double) image);
669*7e568061Sespie #else
670*7e568061Sespie sprintf (buf, "%.*Le", digits - 1, (long double) image);
671*7e568061Sespie #endif
672*7e568061Sespie return buf;
673*7e568061Sespie }
674*7e568061Sespie
675*7e568061Sespie template<typename T>
676*7e568061Sespie const char *
hex() const677*7e568061Sespie native_float<T>::hex() const
678*7e568061Sespie {
679*7e568061Sespie char *buf = new char[50];
680*7e568061Sespie const int digits = int(sizeof(T) * CHAR_BIT / 4);
681*7e568061Sespie #ifndef NO_LONG_DOUBLE
682*7e568061Sespie sprintf (buf, "%.*a", digits - 1, (double) image);
683*7e568061Sespie #else
684*7e568061Sespie sprintf (buf, "%.*La", digits - 1, (long double) image);
685*7e568061Sespie #endif
686*7e568061Sespie return buf;
687*7e568061Sespie }
688*7e568061Sespie
689*7e568061Sespie template<typename T>
690*7e568061Sespie int
exp() const691*7e568061Sespie native_float<T>::exp() const
692*7e568061Sespie {
693*7e568061Sespie int e;
694*7e568061Sespie frexp (image, &e);
695*7e568061Sespie return e;
696*7e568061Sespie }
697*7e568061Sespie
698*7e568061Sespie template<typename T>
699*7e568061Sespie void
ldexp(int exp)700*7e568061Sespie native_float<T>::ldexp (int exp)
701*7e568061Sespie {
702*7e568061Sespie image = ldexpl (image, exp);
703*7e568061Sespie }
704*7e568061Sespie
705*7e568061Sespie template<>
706*7e568061Sespie void
ldexp(int exp)707*7e568061Sespie native_float<float>::ldexp (int exp)
708*7e568061Sespie {
709*7e568061Sespie image = ldexpf (image, exp);
710*7e568061Sespie }
711*7e568061Sespie
712*7e568061Sespie template<>
713*7e568061Sespie void
ldexp(int exp)714*7e568061Sespie native_float<double>::ldexp (int exp)
715*7e568061Sespie {
716*7e568061Sespie image = ::ldexp (image, exp);
717*7e568061Sespie }
718*7e568061Sespie
719*7e568061Sespie /* ====================================================================== */
720*7e568061Sespie /* Some libm routines that Paranoia expects to be available. */
721*7e568061Sespie
722*7e568061Sespie template<typename FLOAT>
723*7e568061Sespie inline FLOAT
FABS(const FLOAT & f)724*7e568061Sespie FABS (const FLOAT &f)
725*7e568061Sespie {
726*7e568061Sespie return f.abs();
727*7e568061Sespie }
728*7e568061Sespie
729*7e568061Sespie template<typename FLOAT, typename RHS>
730*7e568061Sespie inline FLOAT
operator +(const FLOAT & a,const RHS & b)731*7e568061Sespie operator+ (const FLOAT &a, const RHS &b)
732*7e568061Sespie {
733*7e568061Sespie return FLOAT(a) += FLOAT(b);
734*7e568061Sespie }
735*7e568061Sespie
736*7e568061Sespie template<typename FLOAT, typename RHS>
737*7e568061Sespie inline FLOAT
operator -(const FLOAT & a,const RHS & b)738*7e568061Sespie operator- (const FLOAT &a, const RHS &b)
739*7e568061Sespie {
740*7e568061Sespie return FLOAT(a) -= FLOAT(b);
741*7e568061Sespie }
742*7e568061Sespie
743*7e568061Sespie template<typename FLOAT, typename RHS>
744*7e568061Sespie inline FLOAT
operator *(const FLOAT & a,const RHS & b)745*7e568061Sespie operator* (const FLOAT &a, const RHS &b)
746*7e568061Sespie {
747*7e568061Sespie return FLOAT(a) *= FLOAT(b);
748*7e568061Sespie }
749*7e568061Sespie
750*7e568061Sespie template<typename FLOAT, typename RHS>
751*7e568061Sespie inline FLOAT
operator /(const FLOAT & a,const RHS & b)752*7e568061Sespie operator/ (const FLOAT &a, const RHS &b)
753*7e568061Sespie {
754*7e568061Sespie return FLOAT(a) /= FLOAT(b);
755*7e568061Sespie }
756*7e568061Sespie
757*7e568061Sespie template<typename FLOAT>
758*7e568061Sespie FLOAT
FLOOR(const FLOAT & f)759*7e568061Sespie FLOOR (const FLOAT &f)
760*7e568061Sespie {
761*7e568061Sespie /* ??? This is only correct when F is representable as an integer. */
762*7e568061Sespie long i = f.integer();
763*7e568061Sespie FLOAT r;
764*7e568061Sespie
765*7e568061Sespie r = i;
766*7e568061Sespie if (i < 0 && f != r)
767*7e568061Sespie r = i - 1;
768*7e568061Sespie
769*7e568061Sespie return r;
770*7e568061Sespie }
771*7e568061Sespie
772*7e568061Sespie template<typename FLOAT>
773*7e568061Sespie FLOAT
SQRT(const FLOAT & f)774*7e568061Sespie SQRT (const FLOAT &f)
775*7e568061Sespie {
776*7e568061Sespie #if 0
777*7e568061Sespie FLOAT zero = long(0);
778*7e568061Sespie FLOAT two = 2;
779*7e568061Sespie FLOAT one = 1;
780*7e568061Sespie FLOAT diff, diff2;
781*7e568061Sespie FLOAT z, t;
782*7e568061Sespie
783*7e568061Sespie if (f == zero)
784*7e568061Sespie return zero;
785*7e568061Sespie if (f < zero)
786*7e568061Sespie return zero / zero;
787*7e568061Sespie if (f == one)
788*7e568061Sespie return f;
789*7e568061Sespie
790*7e568061Sespie z = f;
791*7e568061Sespie z.ldexp (-f.exp() / 2);
792*7e568061Sespie
793*7e568061Sespie diff2 = FABS (z * z - f);
794*7e568061Sespie if (diff2 > zero)
795*7e568061Sespie while (1)
796*7e568061Sespie {
797*7e568061Sespie t = (f / (two * z)) + (z / two);
798*7e568061Sespie diff = FABS (t * t - f);
799*7e568061Sespie if (diff >= diff2)
800*7e568061Sespie break;
801*7e568061Sespie z = t;
802*7e568061Sespie diff2 = diff;
803*7e568061Sespie }
804*7e568061Sespie
805*7e568061Sespie return z;
806*7e568061Sespie #elif defined(NO_LONG_DOUBLE)
807*7e568061Sespie double d;
808*7e568061Sespie char buf[64];
809*7e568061Sespie
810*7e568061Sespie d = strtod (f.hex(), NULL);
811*7e568061Sespie d = sqrt (d);
812*7e568061Sespie sprintf(buf, "%.35a", d);
813*7e568061Sespie
814*7e568061Sespie return FLOAT(buf);
815*7e568061Sespie #else
816*7e568061Sespie long double ld;
817*7e568061Sespie char buf[64];
818*7e568061Sespie
819*7e568061Sespie ld = strtold (f.hex(), NULL);
820*7e568061Sespie ld = sqrtl (ld);
821*7e568061Sespie sprintf(buf, "%.35La", ld);
822*7e568061Sespie
823*7e568061Sespie return FLOAT(buf);
824*7e568061Sespie #endif
825*7e568061Sespie }
826*7e568061Sespie
827*7e568061Sespie template<typename FLOAT>
828*7e568061Sespie FLOAT
LOG(FLOAT x)829*7e568061Sespie LOG (FLOAT x)
830*7e568061Sespie {
831*7e568061Sespie #if 0
832*7e568061Sespie FLOAT zero = long(0);
833*7e568061Sespie FLOAT one = 1;
834*7e568061Sespie
835*7e568061Sespie if (x <= zero)
836*7e568061Sespie return zero / zero;
837*7e568061Sespie if (x == one)
838*7e568061Sespie return zero;
839*7e568061Sespie
840*7e568061Sespie int exp = x.exp() - 1;
841*7e568061Sespie x.ldexp(-exp);
842*7e568061Sespie
843*7e568061Sespie FLOAT xm1 = x - one;
844*7e568061Sespie FLOAT y = xm1;
845*7e568061Sespie long n = 2;
846*7e568061Sespie
847*7e568061Sespie FLOAT sum = xm1;
848*7e568061Sespie while (1)
849*7e568061Sespie {
850*7e568061Sespie y *= xm1;
851*7e568061Sespie FLOAT term = y / FLOAT (n);
852*7e568061Sespie FLOAT next = sum + term;
853*7e568061Sespie if (next == sum)
854*7e568061Sespie break;
855*7e568061Sespie sum = next;
856*7e568061Sespie if (++n == 1000)
857*7e568061Sespie break;
858*7e568061Sespie }
859*7e568061Sespie
860*7e568061Sespie if (exp)
861*7e568061Sespie sum += FLOAT (exp) * FLOAT(".69314718055994530941");
862*7e568061Sespie
863*7e568061Sespie return sum;
864*7e568061Sespie #elif defined (NO_LONG_DOUBLE)
865*7e568061Sespie double d;
866*7e568061Sespie char buf[64];
867*7e568061Sespie
868*7e568061Sespie d = strtod (x.hex(), NULL);
869*7e568061Sespie d = log (d);
870*7e568061Sespie sprintf(buf, "%.35a", d);
871*7e568061Sespie
872*7e568061Sespie return FLOAT(buf);
873*7e568061Sespie #else
874*7e568061Sespie long double ld;
875*7e568061Sespie char buf[64];
876*7e568061Sespie
877*7e568061Sespie ld = strtold (x.hex(), NULL);
878*7e568061Sespie ld = logl (ld);
879*7e568061Sespie sprintf(buf, "%.35La", ld);
880*7e568061Sespie
881*7e568061Sespie return FLOAT(buf);
882*7e568061Sespie #endif
883*7e568061Sespie }
884*7e568061Sespie
885*7e568061Sespie template<typename FLOAT>
886*7e568061Sespie FLOAT
EXP(const FLOAT & x)887*7e568061Sespie EXP (const FLOAT &x)
888*7e568061Sespie {
889*7e568061Sespie /* Cheat. */
890*7e568061Sespie #ifdef NO_LONG_DOUBLE
891*7e568061Sespie double d;
892*7e568061Sespie char buf[64];
893*7e568061Sespie
894*7e568061Sespie d = strtod (x.hex(), NULL);
895*7e568061Sespie d = exp (d);
896*7e568061Sespie sprintf(buf, "%.35a", d);
897*7e568061Sespie
898*7e568061Sespie return FLOAT(buf);
899*7e568061Sespie #else
900*7e568061Sespie long double ld;
901*7e568061Sespie char buf[64];
902*7e568061Sespie
903*7e568061Sespie ld = strtold (x.hex(), NULL);
904*7e568061Sespie ld = expl (ld);
905*7e568061Sespie sprintf(buf, "%.35La", ld);
906*7e568061Sespie
907*7e568061Sespie return FLOAT(buf);
908*7e568061Sespie #endif
909*7e568061Sespie }
910*7e568061Sespie
911*7e568061Sespie template<typename FLOAT>
912*7e568061Sespie FLOAT
POW(const FLOAT & base,const FLOAT & exp)913*7e568061Sespie POW (const FLOAT &base, const FLOAT &exp)
914*7e568061Sespie {
915*7e568061Sespie /* Cheat. */
916*7e568061Sespie #ifdef NO_LONG_DOUBLE
917*7e568061Sespie double d1, d2;
918*7e568061Sespie char buf[64];
919*7e568061Sespie
920*7e568061Sespie d1 = strtod (base.hex(), NULL);
921*7e568061Sespie d2 = strtod (exp.hex(), NULL);
922*7e568061Sespie d1 = pow (d1, d2);
923*7e568061Sespie sprintf(buf, "%.35a", d1);
924*7e568061Sespie
925*7e568061Sespie return FLOAT(buf);
926*7e568061Sespie #else
927*7e568061Sespie long double ld1, ld2;
928*7e568061Sespie char buf[64];
929*7e568061Sespie
930*7e568061Sespie ld1 = strtold (base.hex(), NULL);
931*7e568061Sespie ld2 = strtold (exp.hex(), NULL);
932*7e568061Sespie ld1 = powl (ld1, ld2);
933*7e568061Sespie sprintf(buf, "%.35La", ld1);
934*7e568061Sespie
935*7e568061Sespie return FLOAT(buf);
936*7e568061Sespie #endif
937*7e568061Sespie }
938*7e568061Sespie
939*7e568061Sespie /* ====================================================================== */
940*7e568061Sespie /* Real Paranoia begins again here. We wrap the thing in a template so
941*7e568061Sespie that we can instantiate it for each floating point type we care for. */
942*7e568061Sespie
943*7e568061Sespie int NoTrials = 20; /*Number of tests for commutativity. */
944*7e568061Sespie bool do_pause = false;
945*7e568061Sespie
946*7e568061Sespie enum Guard { No, Yes };
947*7e568061Sespie enum Rounding { Other, Rounded, Chopped };
948*7e568061Sespie enum Class { Failure, Serious, Defect, Flaw };
949*7e568061Sespie
950*7e568061Sespie template<typename FLOAT>
951*7e568061Sespie struct Paranoia
952*7e568061Sespie {
953*7e568061Sespie FLOAT Radix, BInvrse, RadixD2, BMinusU2;
954*7e568061Sespie
955*7e568061Sespie /* Small floating point constants. */
956*7e568061Sespie FLOAT Zero;
957*7e568061Sespie FLOAT Half;
958*7e568061Sespie FLOAT One;
959*7e568061Sespie FLOAT Two;
960*7e568061Sespie FLOAT Three;
961*7e568061Sespie FLOAT Four;
962*7e568061Sespie FLOAT Five;
963*7e568061Sespie FLOAT Eight;
964*7e568061Sespie FLOAT Nine;
965*7e568061Sespie FLOAT TwentySeven;
966*7e568061Sespie FLOAT ThirtyTwo;
967*7e568061Sespie FLOAT TwoForty;
968*7e568061Sespie FLOAT MinusOne;
969*7e568061Sespie FLOAT OneAndHalf;
970*7e568061Sespie
971*7e568061Sespie /* Declarations of Variables. */
972*7e568061Sespie int Indx;
973*7e568061Sespie char ch[8];
974*7e568061Sespie FLOAT AInvrse, A1;
975*7e568061Sespie FLOAT C, CInvrse;
976*7e568061Sespie FLOAT D, FourD;
977*7e568061Sespie FLOAT E0, E1, Exp2, E3, MinSqEr;
978*7e568061Sespie FLOAT SqEr, MaxSqEr, E9;
979*7e568061Sespie FLOAT Third;
980*7e568061Sespie FLOAT F6, F9;
981*7e568061Sespie FLOAT H, HInvrse;
982*7e568061Sespie int I;
983*7e568061Sespie FLOAT StickyBit, J;
984*7e568061Sespie FLOAT MyZero;
985*7e568061Sespie FLOAT Precision;
986*7e568061Sespie FLOAT Q, Q9;
987*7e568061Sespie FLOAT R, Random9;
988*7e568061Sespie FLOAT T, Underflow, S;
989*7e568061Sespie FLOAT OneUlp, UfThold, U1, U2;
990*7e568061Sespie FLOAT V, V0, V9;
991*7e568061Sespie FLOAT W;
992*7e568061Sespie FLOAT X, X1, X2, X8, Random1;
993*7e568061Sespie FLOAT Y, Y1, Y2, Random2;
994*7e568061Sespie FLOAT Z, PseudoZero, Z1, Z2, Z9;
995*7e568061Sespie int ErrCnt[4];
996*7e568061Sespie int Milestone;
997*7e568061Sespie int PageNo;
998*7e568061Sespie int M, N, N1;
999*7e568061Sespie Guard GMult, GDiv, GAddSub;
1000*7e568061Sespie Rounding RMult, RDiv, RAddSub, RSqrt;
1001*7e568061Sespie int Break, Done, NotMonot, Monot, Anomaly, IEEE, SqRWrng, UfNGrad;
1002*7e568061Sespie
1003*7e568061Sespie /* Computed constants. */
1004*7e568061Sespie /*U1 gap below 1.0, i.e, 1.0-U1 is next number below 1.0 */
1005*7e568061Sespie /*U2 gap above 1.0, i.e, 1.0+U2 is next number above 1.0 */
1006*7e568061Sespie
1007*7e568061Sespie int main ();
1008*7e568061Sespie
1009*7e568061Sespie FLOAT Sign (FLOAT);
1010*7e568061Sespie FLOAT Random ();
1011*7e568061Sespie void Pause ();
1012*7e568061Sespie void BadCond (int, const char *);
1013*7e568061Sespie void SqXMinX (int);
1014*7e568061Sespie void TstCond (int, int, const char *);
1015*7e568061Sespie void notify (const char *);
1016*7e568061Sespie void IsYeqX ();
1017*7e568061Sespie void NewD ();
1018*7e568061Sespie void PrintIfNPositive ();
1019*7e568061Sespie void SR3750 ();
1020*7e568061Sespie void TstPtUf ();
1021*7e568061Sespie
1022*7e568061Sespie // Pretend we're bss.
ParanoiaParanoia1023*7e568061Sespie Paranoia() { memset(this, 0, sizeof (*this)); }
1024*7e568061Sespie };
1025*7e568061Sespie
1026*7e568061Sespie template<typename FLOAT>
1027*7e568061Sespie int
main()1028*7e568061Sespie Paranoia<FLOAT>::main()
1029*7e568061Sespie {
1030*7e568061Sespie /* First two assignments use integer right-hand sides. */
1031*7e568061Sespie Zero = long(0);
1032*7e568061Sespie One = long(1);
1033*7e568061Sespie Two = long(2);
1034*7e568061Sespie Three = long(3);
1035*7e568061Sespie Four = long(4);
1036*7e568061Sespie Five = long(5);
1037*7e568061Sespie Eight = long(8);
1038*7e568061Sespie Nine = long(9);
1039*7e568061Sespie TwentySeven = long(27);
1040*7e568061Sespie ThirtyTwo = long(32);
1041*7e568061Sespie TwoForty = long(240);
1042*7e568061Sespie MinusOne = long(-1);
1043*7e568061Sespie Half = "0x1p-1";
1044*7e568061Sespie OneAndHalf = "0x3p-1";
1045*7e568061Sespie ErrCnt[Failure] = 0;
1046*7e568061Sespie ErrCnt[Serious] = 0;
1047*7e568061Sespie ErrCnt[Defect] = 0;
1048*7e568061Sespie ErrCnt[Flaw] = 0;
1049*7e568061Sespie PageNo = 1;
1050*7e568061Sespie /*=============================================*/
1051*7e568061Sespie Milestone = 7;
1052*7e568061Sespie /*=============================================*/
1053*7e568061Sespie printf ("Program is now RUNNING tests on small integers:\n");
1054*7e568061Sespie
1055*7e568061Sespie TstCond (Failure, (Zero + Zero == Zero), "0+0 != 0");
1056*7e568061Sespie TstCond (Failure, (One - One == Zero), "1-1 != 0");
1057*7e568061Sespie TstCond (Failure, (One > Zero), "1 <= 0");
1058*7e568061Sespie TstCond (Failure, (One + One == Two), "1+1 != 2");
1059*7e568061Sespie
1060*7e568061Sespie Z = -Zero;
1061*7e568061Sespie if (Z != Zero)
1062*7e568061Sespie {
1063*7e568061Sespie ErrCnt[Failure] = ErrCnt[Failure] + 1;
1064*7e568061Sespie printf ("Comparison alleges that -0.0 is Non-zero!\n");
1065*7e568061Sespie U2 = "0.001";
1066*7e568061Sespie Radix = 1;
1067*7e568061Sespie TstPtUf ();
1068*7e568061Sespie }
1069*7e568061Sespie
1070*7e568061Sespie TstCond (Failure, (Three == Two + One), "3 != 2+1");
1071*7e568061Sespie TstCond (Failure, (Four == Three + One), "4 != 3+1");
1072*7e568061Sespie TstCond (Failure, (Four + Two * (-Two) == Zero), "4 + 2*(-2) != 0");
1073*7e568061Sespie TstCond (Failure, (Four - Three - One == Zero), "4-3-1 != 0");
1074*7e568061Sespie
1075*7e568061Sespie TstCond (Failure, (MinusOne == (Zero - One)), "-1 != 0-1");
1076*7e568061Sespie TstCond (Failure, (MinusOne + One == Zero), "-1+1 != 0");
1077*7e568061Sespie TstCond (Failure, (One + MinusOne == Zero), "1+(-1) != 0");
1078*7e568061Sespie TstCond (Failure, (MinusOne + FABS (One) == Zero), "-1+abs(1) != 0");
1079*7e568061Sespie TstCond (Failure, (MinusOne + MinusOne * MinusOne == Zero),
1080*7e568061Sespie "-1+(-1)*(-1) != 0");
1081*7e568061Sespie
1082*7e568061Sespie TstCond (Failure, Half + MinusOne + Half == Zero, "1/2 + (-1) + 1/2 != 0");
1083*7e568061Sespie
1084*7e568061Sespie /*=============================================*/
1085*7e568061Sespie Milestone = 10;
1086*7e568061Sespie /*=============================================*/
1087*7e568061Sespie
1088*7e568061Sespie TstCond (Failure, (Nine == Three * Three), "9 != 3*3");
1089*7e568061Sespie TstCond (Failure, (TwentySeven == Nine * Three), "27 != 9*3");
1090*7e568061Sespie TstCond (Failure, (Eight == Four + Four), "8 != 4+4");
1091*7e568061Sespie TstCond (Failure, (ThirtyTwo == Eight * Four), "32 != 8*4");
1092*7e568061Sespie TstCond (Failure, (ThirtyTwo - TwentySeven - Four - One == Zero),
1093*7e568061Sespie "32-27-4-1 != 0");
1094*7e568061Sespie
1095*7e568061Sespie TstCond (Failure, Five == Four + One, "5 != 4+1");
1096*7e568061Sespie TstCond (Failure, TwoForty == Four * Five * Three * Four, "240 != 4*5*3*4");
1097*7e568061Sespie TstCond (Failure, TwoForty / Three - Four * Four * Five == Zero,
1098*7e568061Sespie "240/3 - 4*4*5 != 0");
1099*7e568061Sespie TstCond (Failure, TwoForty / Four - Five * Three * Four == Zero,
1100*7e568061Sespie "240/4 - 5*3*4 != 0");
1101*7e568061Sespie TstCond (Failure, TwoForty / Five - Four * Three * Four == Zero,
1102*7e568061Sespie "240/5 - 4*3*4 != 0");
1103*7e568061Sespie
1104*7e568061Sespie if (ErrCnt[Failure] == 0)
1105*7e568061Sespie {
1106*7e568061Sespie printf ("-1, 0, 1/2, 1, 2, 3, 4, 5, 9, 27, 32 & 240 are O.K.\n");
1107*7e568061Sespie printf ("\n");
1108*7e568061Sespie }
1109*7e568061Sespie printf ("Searching for Radix and Precision.\n");
1110*7e568061Sespie W = One;
1111*7e568061Sespie do
1112*7e568061Sespie {
1113*7e568061Sespie W = W + W;
1114*7e568061Sespie Y = W + One;
1115*7e568061Sespie Z = Y - W;
1116*7e568061Sespie Y = Z - One;
1117*7e568061Sespie }
1118*7e568061Sespie while (MinusOne + FABS (Y) < Zero);
1119*7e568061Sespie /*.. now W is just big enough that |((W+1)-W)-1| >= 1 ... */
1120*7e568061Sespie Precision = Zero;
1121*7e568061Sespie Y = One;
1122*7e568061Sespie do
1123*7e568061Sespie {
1124*7e568061Sespie Radix = W + Y;
1125*7e568061Sespie Y = Y + Y;
1126*7e568061Sespie Radix = Radix - W;
1127*7e568061Sespie }
1128*7e568061Sespie while (Radix == Zero);
1129*7e568061Sespie if (Radix < Two)
1130*7e568061Sespie Radix = One;
1131*7e568061Sespie printf ("Radix = %s .\n", Radix.str());
1132*7e568061Sespie if (Radix != One)
1133*7e568061Sespie {
1134*7e568061Sespie W = One;
1135*7e568061Sespie do
1136*7e568061Sespie {
1137*7e568061Sespie Precision = Precision + One;
1138*7e568061Sespie W = W * Radix;
1139*7e568061Sespie Y = W + One;
1140*7e568061Sespie }
1141*7e568061Sespie while ((Y - W) == One);
1142*7e568061Sespie }
1143*7e568061Sespie /*... now W == Radix^Precision is barely too big to satisfy (W+1)-W == 1
1144*7e568061Sespie ... */
1145*7e568061Sespie U1 = One / W;
1146*7e568061Sespie U2 = Radix * U1;
1147*7e568061Sespie printf ("Closest relative separation found is U1 = %s .\n\n", U1.str());
1148*7e568061Sespie printf ("Recalculating radix and precision\n ");
1149*7e568061Sespie
1150*7e568061Sespie /*save old values */
1151*7e568061Sespie E0 = Radix;
1152*7e568061Sespie E1 = U1;
1153*7e568061Sespie E9 = U2;
1154*7e568061Sespie E3 = Precision;
1155*7e568061Sespie
1156*7e568061Sespie X = Four / Three;
1157*7e568061Sespie Third = X - One;
1158*7e568061Sespie F6 = Half - Third;
1159*7e568061Sespie X = F6 + F6;
1160*7e568061Sespie X = FABS (X - Third);
1161*7e568061Sespie if (X < U2)
1162*7e568061Sespie X = U2;
1163*7e568061Sespie
1164*7e568061Sespie /*... now X = (unknown no.) ulps of 1+... */
1165*7e568061Sespie do
1166*7e568061Sespie {
1167*7e568061Sespie U2 = X;
1168*7e568061Sespie Y = Half * U2 + ThirtyTwo * U2 * U2;
1169*7e568061Sespie Y = One + Y;
1170*7e568061Sespie X = Y - One;
1171*7e568061Sespie }
1172*7e568061Sespie while (!((U2 <= X) || (X <= Zero)));
1173*7e568061Sespie
1174*7e568061Sespie /*... now U2 == 1 ulp of 1 + ... */
1175*7e568061Sespie X = Two / Three;
1176*7e568061Sespie F6 = X - Half;
1177*7e568061Sespie Third = F6 + F6;
1178*7e568061Sespie X = Third - Half;
1179*7e568061Sespie X = FABS (X + F6);
1180*7e568061Sespie if (X < U1)
1181*7e568061Sespie X = U1;
1182*7e568061Sespie
1183*7e568061Sespie /*... now X == (unknown no.) ulps of 1 -... */
1184*7e568061Sespie do
1185*7e568061Sespie {
1186*7e568061Sespie U1 = X;
1187*7e568061Sespie Y = Half * U1 + ThirtyTwo * U1 * U1;
1188*7e568061Sespie Y = Half - Y;
1189*7e568061Sespie X = Half + Y;
1190*7e568061Sespie Y = Half - X;
1191*7e568061Sespie X = Half + Y;
1192*7e568061Sespie }
1193*7e568061Sespie while (!((U1 <= X) || (X <= Zero)));
1194*7e568061Sespie /*... now U1 == 1 ulp of 1 - ... */
1195*7e568061Sespie if (U1 == E1)
1196*7e568061Sespie printf ("confirms closest relative separation U1 .\n");
1197*7e568061Sespie else
1198*7e568061Sespie printf ("gets better closest relative separation U1 = %s .\n", U1.str());
1199*7e568061Sespie W = One / U1;
1200*7e568061Sespie F9 = (Half - U1) + Half;
1201*7e568061Sespie
1202*7e568061Sespie Radix = FLOOR (FLOAT ("0.01") + U2 / U1);
1203*7e568061Sespie if (Radix == E0)
1204*7e568061Sespie printf ("Radix confirmed.\n");
1205*7e568061Sespie else
1206*7e568061Sespie printf ("MYSTERY: recalculated Radix = %s .\n", Radix.str());
1207*7e568061Sespie TstCond (Defect, Radix <= Eight + Eight,
1208*7e568061Sespie "Radix is too big: roundoff problems");
1209*7e568061Sespie TstCond (Flaw, (Radix == Two) || (Radix == 10)
1210*7e568061Sespie || (Radix == One), "Radix is not as good as 2 or 10");
1211*7e568061Sespie /*=============================================*/
1212*7e568061Sespie Milestone = 20;
1213*7e568061Sespie /*=============================================*/
1214*7e568061Sespie TstCond (Failure, F9 - Half < Half,
1215*7e568061Sespie "(1-U1)-1/2 < 1/2 is FALSE, prog. fails?");
1216*7e568061Sespie X = F9;
1217*7e568061Sespie I = 1;
1218*7e568061Sespie Y = X - Half;
1219*7e568061Sespie Z = Y - Half;
1220*7e568061Sespie TstCond (Failure, (X != One)
1221*7e568061Sespie || (Z == Zero), "Comparison is fuzzy,X=1 but X-1/2-1/2 != 0");
1222*7e568061Sespie X = One + U2;
1223*7e568061Sespie I = 0;
1224*7e568061Sespie /*=============================================*/
1225*7e568061Sespie Milestone = 25;
1226*7e568061Sespie /*=============================================*/
1227*7e568061Sespie /*... BMinusU2 = nextafter(Radix, 0) */
1228*7e568061Sespie BMinusU2 = Radix - One;
1229*7e568061Sespie BMinusU2 = (BMinusU2 - U2) + One;
1230*7e568061Sespie /* Purify Integers */
1231*7e568061Sespie if (Radix != One)
1232*7e568061Sespie {
1233*7e568061Sespie X = -TwoForty * LOG (U1) / LOG (Radix);
1234*7e568061Sespie Y = FLOOR (Half + X);
1235*7e568061Sespie if (FABS (X - Y) * Four < One)
1236*7e568061Sespie X = Y;
1237*7e568061Sespie Precision = X / TwoForty;
1238*7e568061Sespie Y = FLOOR (Half + Precision);
1239*7e568061Sespie if (FABS (Precision - Y) * TwoForty < Half)
1240*7e568061Sespie Precision = Y;
1241*7e568061Sespie }
1242*7e568061Sespie if ((Precision != FLOOR (Precision)) || (Radix == One))
1243*7e568061Sespie {
1244*7e568061Sespie printf ("Precision cannot be characterized by an Integer number\n");
1245*7e568061Sespie printf
1246*7e568061Sespie ("of significant digits but, by itself, this is a minor flaw.\n");
1247*7e568061Sespie }
1248*7e568061Sespie if (Radix == One)
1249*7e568061Sespie printf
1250*7e568061Sespie ("logarithmic encoding has precision characterized solely by U1.\n");
1251*7e568061Sespie else
1252*7e568061Sespie printf ("The number of significant digits of the Radix is %s .\n",
1253*7e568061Sespie Precision.str());
1254*7e568061Sespie TstCond (Serious, U2 * Nine * Nine * TwoForty < One,
1255*7e568061Sespie "Precision worse than 5 decimal figures ");
1256*7e568061Sespie /*=============================================*/
1257*7e568061Sespie Milestone = 30;
1258*7e568061Sespie /*=============================================*/
1259*7e568061Sespie /* Test for extra-precise subexpressions */
1260*7e568061Sespie X = FABS (((Four / Three - One) - One / Four) * Three - One / Four);
1261*7e568061Sespie do
1262*7e568061Sespie {
1263*7e568061Sespie Z2 = X;
1264*7e568061Sespie X = (One + (Half * Z2 + ThirtyTwo * Z2 * Z2)) - One;
1265*7e568061Sespie }
1266*7e568061Sespie while (!((Z2 <= X) || (X <= Zero)));
1267*7e568061Sespie X = Y = Z = FABS ((Three / Four - Two / Three) * Three - One / Four);
1268*7e568061Sespie do
1269*7e568061Sespie {
1270*7e568061Sespie Z1 = Z;
1271*7e568061Sespie Z = (One / Two - ((One / Two - (Half * Z1 + ThirtyTwo * Z1 * Z1))
1272*7e568061Sespie + One / Two)) + One / Two;
1273*7e568061Sespie }
1274*7e568061Sespie while (!((Z1 <= Z) || (Z <= Zero)));
1275*7e568061Sespie do
1276*7e568061Sespie {
1277*7e568061Sespie do
1278*7e568061Sespie {
1279*7e568061Sespie Y1 = Y;
1280*7e568061Sespie Y =
1281*7e568061Sespie (Half - ((Half - (Half * Y1 + ThirtyTwo * Y1 * Y1)) + Half)) +
1282*7e568061Sespie Half;
1283*7e568061Sespie }
1284*7e568061Sespie while (!((Y1 <= Y) || (Y <= Zero)));
1285*7e568061Sespie X1 = X;
1286*7e568061Sespie X = ((Half * X1 + ThirtyTwo * X1 * X1) - F9) + F9;
1287*7e568061Sespie }
1288*7e568061Sespie while (!((X1 <= X) || (X <= Zero)));
1289*7e568061Sespie if ((X1 != Y1) || (X1 != Z1))
1290*7e568061Sespie {
1291*7e568061Sespie BadCond (Serious, "Disagreements among the values X1, Y1, Z1,\n");
1292*7e568061Sespie printf ("respectively %s, %s, %s,\n", X1.str(), Y1.str(), Z1.str());
1293*7e568061Sespie printf ("are symptoms of inconsistencies introduced\n");
1294*7e568061Sespie printf ("by extra-precise evaluation of arithmetic subexpressions.\n");
1295*7e568061Sespie notify ("Possibly some part of this");
1296*7e568061Sespie if ((X1 == U1) || (Y1 == U1) || (Z1 == U1))
1297*7e568061Sespie printf ("That feature is not tested further by this program.\n");
1298*7e568061Sespie }
1299*7e568061Sespie else
1300*7e568061Sespie {
1301*7e568061Sespie if ((Z1 != U1) || (Z2 != U2))
1302*7e568061Sespie {
1303*7e568061Sespie if ((Z1 >= U1) || (Z2 >= U2))
1304*7e568061Sespie {
1305*7e568061Sespie BadCond (Failure, "");
1306*7e568061Sespie notify ("Precision");
1307*7e568061Sespie printf ("\tU1 = %s, Z1 - U1 = %s\n", U1.str(), (Z1 - U1).str());
1308*7e568061Sespie printf ("\tU2 = %s, Z2 - U2 = %s\n", U2.str(), (Z2 - U2).str());
1309*7e568061Sespie }
1310*7e568061Sespie else
1311*7e568061Sespie {
1312*7e568061Sespie if ((Z1 <= Zero) || (Z2 <= Zero))
1313*7e568061Sespie {
1314*7e568061Sespie printf ("Because of unusual Radix = %s", Radix.str());
1315*7e568061Sespie printf (", or exact rational arithmetic a result\n");
1316*7e568061Sespie printf ("Z1 = %s, or Z2 = %s ", Z1.str(), Z2.str());
1317*7e568061Sespie notify ("of an\nextra-precision");
1318*7e568061Sespie }
1319*7e568061Sespie if (Z1 != Z2 || Z1 > Zero)
1320*7e568061Sespie {
1321*7e568061Sespie X = Z1 / U1;
1322*7e568061Sespie Y = Z2 / U2;
1323*7e568061Sespie if (Y > X)
1324*7e568061Sespie X = Y;
1325*7e568061Sespie Q = -LOG (X);
1326*7e568061Sespie printf ("Some subexpressions appear to be calculated "
1327*7e568061Sespie "extra precisely\n");
1328*7e568061Sespie printf ("with about %s extra B-digits, i.e.\n",
1329*7e568061Sespie (Q / LOG (Radix)).str());
1330*7e568061Sespie printf ("roughly %s extra significant decimals.\n",
1331*7e568061Sespie (Q / LOG (FLOAT (10))).str());
1332*7e568061Sespie }
1333*7e568061Sespie printf
1334*7e568061Sespie ("That feature is not tested further by this program.\n");
1335*7e568061Sespie }
1336*7e568061Sespie }
1337*7e568061Sespie }
1338*7e568061Sespie Pause ();
1339*7e568061Sespie /*=============================================*/
1340*7e568061Sespie Milestone = 35;
1341*7e568061Sespie /*=============================================*/
1342*7e568061Sespie if (Radix >= Two)
1343*7e568061Sespie {
1344*7e568061Sespie X = W / (Radix * Radix);
1345*7e568061Sespie Y = X + One;
1346*7e568061Sespie Z = Y - X;
1347*7e568061Sespie T = Z + U2;
1348*7e568061Sespie X = T - Z;
1349*7e568061Sespie TstCond (Failure, X == U2,
1350*7e568061Sespie "Subtraction is not normalized X=Y,X+Z != Y+Z!");
1351*7e568061Sespie if (X == U2)
1352*7e568061Sespie printf ("Subtraction appears to be normalized, as it should be.");
1353*7e568061Sespie }
1354*7e568061Sespie printf ("\nChecking for guard digit in *, /, and -.\n");
1355*7e568061Sespie Y = F9 * One;
1356*7e568061Sespie Z = One * F9;
1357*7e568061Sespie X = F9 - Half;
1358*7e568061Sespie Y = (Y - Half) - X;
1359*7e568061Sespie Z = (Z - Half) - X;
1360*7e568061Sespie X = One + U2;
1361*7e568061Sespie T = X * Radix;
1362*7e568061Sespie R = Radix * X;
1363*7e568061Sespie X = T - Radix;
1364*7e568061Sespie X = X - Radix * U2;
1365*7e568061Sespie T = R - Radix;
1366*7e568061Sespie T = T - Radix * U2;
1367*7e568061Sespie X = X * (Radix - One);
1368*7e568061Sespie T = T * (Radix - One);
1369*7e568061Sespie if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero))
1370*7e568061Sespie GMult = Yes;
1371*7e568061Sespie else
1372*7e568061Sespie {
1373*7e568061Sespie GMult = No;
1374*7e568061Sespie TstCond (Serious, false, "* lacks a Guard Digit, so 1*X != X");
1375*7e568061Sespie }
1376*7e568061Sespie Z = Radix * U2;
1377*7e568061Sespie X = One + Z;
1378*7e568061Sespie Y = FABS ((X + Z) - X * X) - U2;
1379*7e568061Sespie X = One - U2;
1380*7e568061Sespie Z = FABS ((X - U2) - X * X) - U1;
1381*7e568061Sespie TstCond (Failure, (Y <= Zero)
1382*7e568061Sespie && (Z <= Zero), "* gets too many final digits wrong.\n");
1383*7e568061Sespie Y = One - U2;
1384*7e568061Sespie X = One + U2;
1385*7e568061Sespie Z = One / Y;
1386*7e568061Sespie Y = Z - X;
1387*7e568061Sespie X = One / Three;
1388*7e568061Sespie Z = Three / Nine;
1389*7e568061Sespie X = X - Z;
1390*7e568061Sespie T = Nine / TwentySeven;
1391*7e568061Sespie Z = Z - T;
1392*7e568061Sespie TstCond (Defect, X == Zero && Y == Zero && Z == Zero,
1393*7e568061Sespie "Division lacks a Guard Digit, so error can exceed 1 ulp\n"
1394*7e568061Sespie "or 1/3 and 3/9 and 9/27 may disagree");
1395*7e568061Sespie Y = F9 / One;
1396*7e568061Sespie X = F9 - Half;
1397*7e568061Sespie Y = (Y - Half) - X;
1398*7e568061Sespie X = One + U2;
1399*7e568061Sespie T = X / One;
1400*7e568061Sespie X = T - X;
1401*7e568061Sespie if ((X == Zero) && (Y == Zero) && (Z == Zero))
1402*7e568061Sespie GDiv = Yes;
1403*7e568061Sespie else
1404*7e568061Sespie {
1405*7e568061Sespie GDiv = No;
1406*7e568061Sespie TstCond (Serious, false, "Division lacks a Guard Digit, so X/1 != X");
1407*7e568061Sespie }
1408*7e568061Sespie X = One / (One + U2);
1409*7e568061Sespie Y = X - Half - Half;
1410*7e568061Sespie TstCond (Serious, Y < Zero, "Computed value of 1/1.000..1 >= 1");
1411*7e568061Sespie X = One - U2;
1412*7e568061Sespie Y = One + Radix * U2;
1413*7e568061Sespie Z = X * Radix;
1414*7e568061Sespie T = Y * Radix;
1415*7e568061Sespie R = Z / Radix;
1416*7e568061Sespie StickyBit = T / Radix;
1417*7e568061Sespie X = R - X;
1418*7e568061Sespie Y = StickyBit - Y;
1419*7e568061Sespie TstCond (Failure, X == Zero && Y == Zero,
1420*7e568061Sespie "* and/or / gets too many last digits wrong");
1421*7e568061Sespie Y = One - U1;
1422*7e568061Sespie X = One - F9;
1423*7e568061Sespie Y = One - Y;
1424*7e568061Sespie T = Radix - U2;
1425*7e568061Sespie Z = Radix - BMinusU2;
1426*7e568061Sespie T = Radix - T;
1427*7e568061Sespie if ((X == U1) && (Y == U1) && (Z == U2) && (T == U2))
1428*7e568061Sespie GAddSub = Yes;
1429*7e568061Sespie else
1430*7e568061Sespie {
1431*7e568061Sespie GAddSub = No;
1432*7e568061Sespie TstCond (Serious, false,
1433*7e568061Sespie "- lacks Guard Digit, so cancellation is obscured");
1434*7e568061Sespie }
1435*7e568061Sespie if (F9 != One && F9 - One >= Zero)
1436*7e568061Sespie {
1437*7e568061Sespie BadCond (Serious, "comparison alleges (1-U1) < 1 although\n");
1438*7e568061Sespie printf (" subtraction yields (1-U1) - 1 = 0 , thereby vitiating\n");
1439*7e568061Sespie printf (" such precautions against division by zero as\n");
1440*7e568061Sespie printf (" ... if (X == 1.0) {.....} else {.../(X-1.0)...}\n");
1441*7e568061Sespie }
1442*7e568061Sespie if (GMult == Yes && GDiv == Yes && GAddSub == Yes)
1443*7e568061Sespie printf
1444*7e568061Sespie (" *, /, and - appear to have guard digits, as they should.\n");
1445*7e568061Sespie /*=============================================*/
1446*7e568061Sespie Milestone = 40;
1447*7e568061Sespie /*=============================================*/
1448*7e568061Sespie Pause ();
1449*7e568061Sespie printf ("Checking rounding on multiply, divide and add/subtract.\n");
1450*7e568061Sespie RMult = Other;
1451*7e568061Sespie RDiv = Other;
1452*7e568061Sespie RAddSub = Other;
1453*7e568061Sespie RadixD2 = Radix / Two;
1454*7e568061Sespie A1 = Two;
1455*7e568061Sespie Done = false;
1456*7e568061Sespie do
1457*7e568061Sespie {
1458*7e568061Sespie AInvrse = Radix;
1459*7e568061Sespie do
1460*7e568061Sespie {
1461*7e568061Sespie X = AInvrse;
1462*7e568061Sespie AInvrse = AInvrse / A1;
1463*7e568061Sespie }
1464*7e568061Sespie while (!(FLOOR (AInvrse) != AInvrse));
1465*7e568061Sespie Done = (X == One) || (A1 > Three);
1466*7e568061Sespie if (!Done)
1467*7e568061Sespie A1 = Nine + One;
1468*7e568061Sespie }
1469*7e568061Sespie while (!(Done));
1470*7e568061Sespie if (X == One)
1471*7e568061Sespie A1 = Radix;
1472*7e568061Sespie AInvrse = One / A1;
1473*7e568061Sespie X = A1;
1474*7e568061Sespie Y = AInvrse;
1475*7e568061Sespie Done = false;
1476*7e568061Sespie do
1477*7e568061Sespie {
1478*7e568061Sespie Z = X * Y - Half;
1479*7e568061Sespie TstCond (Failure, Z == Half, "X * (1/X) differs from 1");
1480*7e568061Sespie Done = X == Radix;
1481*7e568061Sespie X = Radix;
1482*7e568061Sespie Y = One / X;
1483*7e568061Sespie }
1484*7e568061Sespie while (!(Done));
1485*7e568061Sespie Y2 = One + U2;
1486*7e568061Sespie Y1 = One - U2;
1487*7e568061Sespie X = OneAndHalf - U2;
1488*7e568061Sespie Y = OneAndHalf + U2;
1489*7e568061Sespie Z = (X - U2) * Y2;
1490*7e568061Sespie T = Y * Y1;
1491*7e568061Sespie Z = Z - X;
1492*7e568061Sespie T = T - X;
1493*7e568061Sespie X = X * Y2;
1494*7e568061Sespie Y = (Y + U2) * Y1;
1495*7e568061Sespie X = X - OneAndHalf;
1496*7e568061Sespie Y = Y - OneAndHalf;
1497*7e568061Sespie if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T <= Zero))
1498*7e568061Sespie {
1499*7e568061Sespie X = (OneAndHalf + U2) * Y2;
1500*7e568061Sespie Y = OneAndHalf - U2 - U2;
1501*7e568061Sespie Z = OneAndHalf + U2 + U2;
1502*7e568061Sespie T = (OneAndHalf - U2) * Y1;
1503*7e568061Sespie X = X - (Z + U2);
1504*7e568061Sespie StickyBit = Y * Y1;
1505*7e568061Sespie S = Z * Y2;
1506*7e568061Sespie T = T - Y;
1507*7e568061Sespie Y = (U2 - Y) + StickyBit;
1508*7e568061Sespie Z = S - (Z + U2 + U2);
1509*7e568061Sespie StickyBit = (Y2 + U2) * Y1;
1510*7e568061Sespie Y1 = Y2 * Y1;
1511*7e568061Sespie StickyBit = StickyBit - Y2;
1512*7e568061Sespie Y1 = Y1 - Half;
1513*7e568061Sespie if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero)
1514*7e568061Sespie && (StickyBit == Zero) && (Y1 == Half))
1515*7e568061Sespie {
1516*7e568061Sespie RMult = Rounded;
1517*7e568061Sespie printf ("Multiplication appears to round correctly.\n");
1518*7e568061Sespie }
1519*7e568061Sespie else if ((X + U2 == Zero) && (Y < Zero) && (Z + U2 == Zero)
1520*7e568061Sespie && (T < Zero) && (StickyBit + U2 == Zero) && (Y1 < Half))
1521*7e568061Sespie {
1522*7e568061Sespie RMult = Chopped;
1523*7e568061Sespie printf ("Multiplication appears to chop.\n");
1524*7e568061Sespie }
1525*7e568061Sespie else
1526*7e568061Sespie printf ("* is neither chopped nor correctly rounded.\n");
1527*7e568061Sespie if ((RMult == Rounded) && (GMult == No))
1528*7e568061Sespie notify ("Multiplication");
1529*7e568061Sespie }
1530*7e568061Sespie else
1531*7e568061Sespie printf ("* is neither chopped nor correctly rounded.\n");
1532*7e568061Sespie /*=============================================*/
1533*7e568061Sespie Milestone = 45;
1534*7e568061Sespie /*=============================================*/
1535*7e568061Sespie Y2 = One + U2;
1536*7e568061Sespie Y1 = One - U2;
1537*7e568061Sespie Z = OneAndHalf + U2 + U2;
1538*7e568061Sespie X = Z / Y2;
1539*7e568061Sespie T = OneAndHalf - U2 - U2;
1540*7e568061Sespie Y = (T - U2) / Y1;
1541*7e568061Sespie Z = (Z + U2) / Y2;
1542*7e568061Sespie X = X - OneAndHalf;
1543*7e568061Sespie Y = Y - T;
1544*7e568061Sespie T = T / Y1;
1545*7e568061Sespie Z = Z - (OneAndHalf + U2);
1546*7e568061Sespie T = (U2 - OneAndHalf) + T;
1547*7e568061Sespie if (!((X > Zero) || (Y > Zero) || (Z > Zero) || (T > Zero)))
1548*7e568061Sespie {
1549*7e568061Sespie X = OneAndHalf / Y2;
1550*7e568061Sespie Y = OneAndHalf - U2;
1551*7e568061Sespie Z = OneAndHalf + U2;
1552*7e568061Sespie X = X - Y;
1553*7e568061Sespie T = OneAndHalf / Y1;
1554*7e568061Sespie Y = Y / Y1;
1555*7e568061Sespie T = T - (Z + U2);
1556*7e568061Sespie Y = Y - Z;
1557*7e568061Sespie Z = Z / Y2;
1558*7e568061Sespie Y1 = (Y2 + U2) / Y2;
1559*7e568061Sespie Z = Z - OneAndHalf;
1560*7e568061Sespie Y2 = Y1 - Y2;
1561*7e568061Sespie Y1 = (F9 - U1) / F9;
1562*7e568061Sespie if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero)
1563*7e568061Sespie && (Y2 == Zero) && (Y2 == Zero) && (Y1 - Half == F9 - Half))
1564*7e568061Sespie {
1565*7e568061Sespie RDiv = Rounded;
1566*7e568061Sespie printf ("Division appears to round correctly.\n");
1567*7e568061Sespie if (GDiv == No)
1568*7e568061Sespie notify ("Division");
1569*7e568061Sespie }
1570*7e568061Sespie else if ((X < Zero) && (Y < Zero) && (Z < Zero) && (T < Zero)
1571*7e568061Sespie && (Y2 < Zero) && (Y1 - Half < F9 - Half))
1572*7e568061Sespie {
1573*7e568061Sespie RDiv = Chopped;
1574*7e568061Sespie printf ("Division appears to chop.\n");
1575*7e568061Sespie }
1576*7e568061Sespie }
1577*7e568061Sespie if (RDiv == Other)
1578*7e568061Sespie printf ("/ is neither chopped nor correctly rounded.\n");
1579*7e568061Sespie BInvrse = One / Radix;
1580*7e568061Sespie TstCond (Failure, (BInvrse * Radix - Half == Half),
1581*7e568061Sespie "Radix * ( 1 / Radix ) differs from 1");
1582*7e568061Sespie /*=============================================*/
1583*7e568061Sespie Milestone = 50;
1584*7e568061Sespie /*=============================================*/
1585*7e568061Sespie TstCond (Failure, ((F9 + U1) - Half == Half)
1586*7e568061Sespie && ((BMinusU2 + U2) - One == Radix - One),
1587*7e568061Sespie "Incomplete carry-propagation in Addition");
1588*7e568061Sespie X = One - U1 * U1;
1589*7e568061Sespie Y = One + U2 * (One - U2);
1590*7e568061Sespie Z = F9 - Half;
1591*7e568061Sespie X = (X - Half) - Z;
1592*7e568061Sespie Y = Y - One;
1593*7e568061Sespie if ((X == Zero) && (Y == Zero))
1594*7e568061Sespie {
1595*7e568061Sespie RAddSub = Chopped;
1596*7e568061Sespie printf ("Add/Subtract appears to be chopped.\n");
1597*7e568061Sespie }
1598*7e568061Sespie if (GAddSub == Yes)
1599*7e568061Sespie {
1600*7e568061Sespie X = (Half + U2) * U2;
1601*7e568061Sespie Y = (Half - U2) * U2;
1602*7e568061Sespie X = One + X;
1603*7e568061Sespie Y = One + Y;
1604*7e568061Sespie X = (One + U2) - X;
1605*7e568061Sespie Y = One - Y;
1606*7e568061Sespie if ((X == Zero) && (Y == Zero))
1607*7e568061Sespie {
1608*7e568061Sespie X = (Half + U2) * U1;
1609*7e568061Sespie Y = (Half - U2) * U1;
1610*7e568061Sespie X = One - X;
1611*7e568061Sespie Y = One - Y;
1612*7e568061Sespie X = F9 - X;
1613*7e568061Sespie Y = One - Y;
1614*7e568061Sespie if ((X == Zero) && (Y == Zero))
1615*7e568061Sespie {
1616*7e568061Sespie RAddSub = Rounded;
1617*7e568061Sespie printf ("Addition/Subtraction appears to round correctly.\n");
1618*7e568061Sespie if (GAddSub == No)
1619*7e568061Sespie notify ("Add/Subtract");
1620*7e568061Sespie }
1621*7e568061Sespie else
1622*7e568061Sespie printf ("Addition/Subtraction neither rounds nor chops.\n");
1623*7e568061Sespie }
1624*7e568061Sespie else
1625*7e568061Sespie printf ("Addition/Subtraction neither rounds nor chops.\n");
1626*7e568061Sespie }
1627*7e568061Sespie else
1628*7e568061Sespie printf ("Addition/Subtraction neither rounds nor chops.\n");
1629*7e568061Sespie S = One;
1630*7e568061Sespie X = One + Half * (One + Half);
1631*7e568061Sespie Y = (One + U2) * Half;
1632*7e568061Sespie Z = X - Y;
1633*7e568061Sespie T = Y - X;
1634*7e568061Sespie StickyBit = Z + T;
1635*7e568061Sespie if (StickyBit != Zero)
1636*7e568061Sespie {
1637*7e568061Sespie S = Zero;
1638*7e568061Sespie BadCond (Flaw, "(X - Y) + (Y - X) is non zero!\n");
1639*7e568061Sespie }
1640*7e568061Sespie StickyBit = Zero;
1641*7e568061Sespie if ((GMult == Yes) && (GDiv == Yes) && (GAddSub == Yes)
1642*7e568061Sespie && (RMult == Rounded) && (RDiv == Rounded)
1643*7e568061Sespie && (RAddSub == Rounded) && (FLOOR (RadixD2) == RadixD2))
1644*7e568061Sespie {
1645*7e568061Sespie printf ("Checking for sticky bit.\n");
1646*7e568061Sespie X = (Half + U1) * U2;
1647*7e568061Sespie Y = Half * U2;
1648*7e568061Sespie Z = One + Y;
1649*7e568061Sespie T = One + X;
1650*7e568061Sespie if ((Z - One <= Zero) && (T - One >= U2))
1651*7e568061Sespie {
1652*7e568061Sespie Z = T + Y;
1653*7e568061Sespie Y = Z - X;
1654*7e568061Sespie if ((Z - T >= U2) && (Y - T == Zero))
1655*7e568061Sespie {
1656*7e568061Sespie X = (Half + U1) * U1;
1657*7e568061Sespie Y = Half * U1;
1658*7e568061Sespie Z = One - Y;
1659*7e568061Sespie T = One - X;
1660*7e568061Sespie if ((Z - One == Zero) && (T - F9 == Zero))
1661*7e568061Sespie {
1662*7e568061Sespie Z = (Half - U1) * U1;
1663*7e568061Sespie T = F9 - Z;
1664*7e568061Sespie Q = F9 - Y;
1665*7e568061Sespie if ((T - F9 == Zero) && (F9 - U1 - Q == Zero))
1666*7e568061Sespie {
1667*7e568061Sespie Z = (One + U2) * OneAndHalf;
1668*7e568061Sespie T = (OneAndHalf + U2) - Z + U2;
1669*7e568061Sespie X = One + Half / Radix;
1670*7e568061Sespie Y = One + Radix * U2;
1671*7e568061Sespie Z = X * Y;
1672*7e568061Sespie if (T == Zero && X + Radix * U2 - Z == Zero)
1673*7e568061Sespie {
1674*7e568061Sespie if (Radix != Two)
1675*7e568061Sespie {
1676*7e568061Sespie X = Two + U2;
1677*7e568061Sespie Y = X / Two;
1678*7e568061Sespie if ((Y - One == Zero))
1679*7e568061Sespie StickyBit = S;
1680*7e568061Sespie }
1681*7e568061Sespie else
1682*7e568061Sespie StickyBit = S;
1683*7e568061Sespie }
1684*7e568061Sespie }
1685*7e568061Sespie }
1686*7e568061Sespie }
1687*7e568061Sespie }
1688*7e568061Sespie }
1689*7e568061Sespie if (StickyBit == One)
1690*7e568061Sespie printf ("Sticky bit apparently used correctly.\n");
1691*7e568061Sespie else
1692*7e568061Sespie printf ("Sticky bit used incorrectly or not at all.\n");
1693*7e568061Sespie TstCond (Flaw, !(GMult == No || GDiv == No || GAddSub == No ||
1694*7e568061Sespie RMult == Other || RDiv == Other || RAddSub == Other),
1695*7e568061Sespie "lack(s) of guard digits or failure(s) to correctly round or chop\n\
1696*7e568061Sespie (noted above) count as one flaw in the final tally below");
1697*7e568061Sespie /*=============================================*/
1698*7e568061Sespie Milestone = 60;
1699*7e568061Sespie /*=============================================*/
1700*7e568061Sespie printf ("\n");
1701*7e568061Sespie printf ("Does Multiplication commute? ");
1702*7e568061Sespie printf ("Testing on %d random pairs.\n", NoTrials);
1703*7e568061Sespie Random9 = SQRT (FLOAT (3));
1704*7e568061Sespie Random1 = Third;
1705*7e568061Sespie I = 1;
1706*7e568061Sespie do
1707*7e568061Sespie {
1708*7e568061Sespie X = Random ();
1709*7e568061Sespie Y = Random ();
1710*7e568061Sespie Z9 = Y * X;
1711*7e568061Sespie Z = X * Y;
1712*7e568061Sespie Z9 = Z - Z9;
1713*7e568061Sespie I = I + 1;
1714*7e568061Sespie }
1715*7e568061Sespie while (!((I > NoTrials) || (Z9 != Zero)));
1716*7e568061Sespie if (I == NoTrials)
1717*7e568061Sespie {
1718*7e568061Sespie Random1 = One + Half / Three;
1719*7e568061Sespie Random2 = (U2 + U1) + One;
1720*7e568061Sespie Z = Random1 * Random2;
1721*7e568061Sespie Y = Random2 * Random1;
1722*7e568061Sespie Z9 = (One + Half / Three) * ((U2 + U1) + One) - (One + Half /
1723*7e568061Sespie Three) * ((U2 + U1) +
1724*7e568061Sespie One);
1725*7e568061Sespie }
1726*7e568061Sespie if (!((I == NoTrials) || (Z9 == Zero)))
1727*7e568061Sespie BadCond (Defect, "X * Y == Y * X trial fails.\n");
1728*7e568061Sespie else
1729*7e568061Sespie printf (" No failures found in %d integer pairs.\n", NoTrials);
1730*7e568061Sespie /*=============================================*/
1731*7e568061Sespie Milestone = 70;
1732*7e568061Sespie /*=============================================*/
1733*7e568061Sespie printf ("\nRunning test of square root(x).\n");
1734*7e568061Sespie TstCond (Failure, (Zero == SQRT (Zero))
1735*7e568061Sespie && (-Zero == SQRT (-Zero))
1736*7e568061Sespie && (One == SQRT (One)), "Square root of 0.0, -0.0 or 1.0 wrong");
1737*7e568061Sespie MinSqEr = Zero;
1738*7e568061Sespie MaxSqEr = Zero;
1739*7e568061Sespie J = Zero;
1740*7e568061Sespie X = Radix;
1741*7e568061Sespie OneUlp = U2;
1742*7e568061Sespie SqXMinX (Serious);
1743*7e568061Sespie X = BInvrse;
1744*7e568061Sespie OneUlp = BInvrse * U1;
1745*7e568061Sespie SqXMinX (Serious);
1746*7e568061Sespie X = U1;
1747*7e568061Sespie OneUlp = U1 * U1;
1748*7e568061Sespie SqXMinX (Serious);
1749*7e568061Sespie if (J != Zero)
1750*7e568061Sespie Pause ();
1751*7e568061Sespie printf ("Testing if sqrt(X * X) == X for %d Integers X.\n", NoTrials);
1752*7e568061Sespie J = Zero;
1753*7e568061Sespie X = Two;
1754*7e568061Sespie Y = Radix;
1755*7e568061Sespie if ((Radix != One))
1756*7e568061Sespie do
1757*7e568061Sespie {
1758*7e568061Sespie X = Y;
1759*7e568061Sespie Y = Radix * Y;
1760*7e568061Sespie }
1761*7e568061Sespie while (!((Y - X >= NoTrials)));
1762*7e568061Sespie OneUlp = X * U2;
1763*7e568061Sespie I = 1;
1764*7e568061Sespie while (I <= NoTrials)
1765*7e568061Sespie {
1766*7e568061Sespie X = X + One;
1767*7e568061Sespie SqXMinX (Defect);
1768*7e568061Sespie if (J > Zero)
1769*7e568061Sespie break;
1770*7e568061Sespie I = I + 1;
1771*7e568061Sespie }
1772*7e568061Sespie printf ("Test for sqrt monotonicity.\n");
1773*7e568061Sespie I = -1;
1774*7e568061Sespie X = BMinusU2;
1775*7e568061Sespie Y = Radix;
1776*7e568061Sespie Z = Radix + Radix * U2;
1777*7e568061Sespie NotMonot = false;
1778*7e568061Sespie Monot = false;
1779*7e568061Sespie while (!(NotMonot || Monot))
1780*7e568061Sespie {
1781*7e568061Sespie I = I + 1;
1782*7e568061Sespie X = SQRT (X);
1783*7e568061Sespie Q = SQRT (Y);
1784*7e568061Sespie Z = SQRT (Z);
1785*7e568061Sespie if ((X > Q) || (Q > Z))
1786*7e568061Sespie NotMonot = true;
1787*7e568061Sespie else
1788*7e568061Sespie {
1789*7e568061Sespie Q = FLOOR (Q + Half);
1790*7e568061Sespie if (!(I > 0 || Radix == Q * Q))
1791*7e568061Sespie Monot = true;
1792*7e568061Sespie else if (I > 0)
1793*7e568061Sespie {
1794*7e568061Sespie if (I > 1)
1795*7e568061Sespie Monot = true;
1796*7e568061Sespie else
1797*7e568061Sespie {
1798*7e568061Sespie Y = Y * BInvrse;
1799*7e568061Sespie X = Y - U1;
1800*7e568061Sespie Z = Y + U1;
1801*7e568061Sespie }
1802*7e568061Sespie }
1803*7e568061Sespie else
1804*7e568061Sespie {
1805*7e568061Sespie Y = Q;
1806*7e568061Sespie X = Y - U2;
1807*7e568061Sespie Z = Y + U2;
1808*7e568061Sespie }
1809*7e568061Sespie }
1810*7e568061Sespie }
1811*7e568061Sespie if (Monot)
1812*7e568061Sespie printf ("sqrt has passed a test for Monotonicity.\n");
1813*7e568061Sespie else
1814*7e568061Sespie {
1815*7e568061Sespie BadCond (Defect, "");
1816*7e568061Sespie printf ("sqrt(X) is non-monotonic for X near %s .\n", Y.str());
1817*7e568061Sespie }
1818*7e568061Sespie /*=============================================*/
1819*7e568061Sespie Milestone = 110;
1820*7e568061Sespie /*=============================================*/
1821*7e568061Sespie printf ("Seeking Underflow thresholds UfThold and E0.\n");
1822*7e568061Sespie D = U1;
1823*7e568061Sespie if (Precision != FLOOR (Precision))
1824*7e568061Sespie {
1825*7e568061Sespie D = BInvrse;
1826*7e568061Sespie X = Precision;
1827*7e568061Sespie do
1828*7e568061Sespie {
1829*7e568061Sespie D = D * BInvrse;
1830*7e568061Sespie X = X - One;
1831*7e568061Sespie }
1832*7e568061Sespie while (X > Zero);
1833*7e568061Sespie }
1834*7e568061Sespie Y = One;
1835*7e568061Sespie Z = D;
1836*7e568061Sespie /* ... D is power of 1/Radix < 1. */
1837*7e568061Sespie do
1838*7e568061Sespie {
1839*7e568061Sespie C = Y;
1840*7e568061Sespie Y = Z;
1841*7e568061Sespie Z = Y * Y;
1842*7e568061Sespie }
1843*7e568061Sespie while ((Y > Z) && (Z + Z > Z));
1844*7e568061Sespie Y = C;
1845*7e568061Sespie Z = Y * D;
1846*7e568061Sespie do
1847*7e568061Sespie {
1848*7e568061Sespie C = Y;
1849*7e568061Sespie Y = Z;
1850*7e568061Sespie Z = Y * D;
1851*7e568061Sespie }
1852*7e568061Sespie while ((Y > Z) && (Z + Z > Z));
1853*7e568061Sespie if (Radix < Two)
1854*7e568061Sespie HInvrse = Two;
1855*7e568061Sespie else
1856*7e568061Sespie HInvrse = Radix;
1857*7e568061Sespie H = One / HInvrse;
1858*7e568061Sespie /* ... 1/HInvrse == H == Min(1/Radix, 1/2) */
1859*7e568061Sespie CInvrse = One / C;
1860*7e568061Sespie E0 = C;
1861*7e568061Sespie Z = E0 * H;
1862*7e568061Sespie /* ...1/Radix^(BIG Integer) << 1 << CInvrse == 1/C */
1863*7e568061Sespie do
1864*7e568061Sespie {
1865*7e568061Sespie Y = E0;
1866*7e568061Sespie E0 = Z;
1867*7e568061Sespie Z = E0 * H;
1868*7e568061Sespie }
1869*7e568061Sespie while ((E0 > Z) && (Z + Z > Z));
1870*7e568061Sespie UfThold = E0;
1871*7e568061Sespie E1 = Zero;
1872*7e568061Sespie Q = Zero;
1873*7e568061Sespie E9 = U2;
1874*7e568061Sespie S = One + E9;
1875*7e568061Sespie D = C * S;
1876*7e568061Sespie if (D <= C)
1877*7e568061Sespie {
1878*7e568061Sespie E9 = Radix * U2;
1879*7e568061Sespie S = One + E9;
1880*7e568061Sespie D = C * S;
1881*7e568061Sespie if (D <= C)
1882*7e568061Sespie {
1883*7e568061Sespie BadCond (Failure,
1884*7e568061Sespie "multiplication gets too many last digits wrong.\n");
1885*7e568061Sespie Underflow = E0;
1886*7e568061Sespie Y1 = Zero;
1887*7e568061Sespie PseudoZero = Z;
1888*7e568061Sespie Pause ();
1889*7e568061Sespie }
1890*7e568061Sespie }
1891*7e568061Sespie else
1892*7e568061Sespie {
1893*7e568061Sespie Underflow = D;
1894*7e568061Sespie PseudoZero = Underflow * H;
1895*7e568061Sespie UfThold = Zero;
1896*7e568061Sespie do
1897*7e568061Sespie {
1898*7e568061Sespie Y1 = Underflow;
1899*7e568061Sespie Underflow = PseudoZero;
1900*7e568061Sespie if (E1 + E1 <= E1)
1901*7e568061Sespie {
1902*7e568061Sespie Y2 = Underflow * HInvrse;
1903*7e568061Sespie E1 = FABS (Y1 - Y2);
1904*7e568061Sespie Q = Y1;
1905*7e568061Sespie if ((UfThold == Zero) && (Y1 != Y2))
1906*7e568061Sespie UfThold = Y1;
1907*7e568061Sespie }
1908*7e568061Sespie PseudoZero = PseudoZero * H;
1909*7e568061Sespie }
1910*7e568061Sespie while ((Underflow > PseudoZero)
1911*7e568061Sespie && (PseudoZero + PseudoZero > PseudoZero));
1912*7e568061Sespie }
1913*7e568061Sespie /* Comment line 4530 .. 4560 */
1914*7e568061Sespie if (PseudoZero != Zero)
1915*7e568061Sespie {
1916*7e568061Sespie printf ("\n");
1917*7e568061Sespie Z = PseudoZero;
1918*7e568061Sespie /* ... Test PseudoZero for "phoney- zero" violates */
1919*7e568061Sespie /* ... PseudoZero < Underflow or PseudoZero < PseudoZero + PseudoZero
1920*7e568061Sespie ... */
1921*7e568061Sespie if (PseudoZero <= Zero)
1922*7e568061Sespie {
1923*7e568061Sespie BadCond (Failure, "Positive expressions can underflow to an\n");
1924*7e568061Sespie printf ("allegedly negative value\n");
1925*7e568061Sespie printf ("PseudoZero that prints out as: %s .\n", PseudoZero.str());
1926*7e568061Sespie X = -PseudoZero;
1927*7e568061Sespie if (X <= Zero)
1928*7e568061Sespie {
1929*7e568061Sespie printf ("But -PseudoZero, which should be\n");
1930*7e568061Sespie printf ("positive, isn't; it prints out as %s .\n", X.str());
1931*7e568061Sespie }
1932*7e568061Sespie }
1933*7e568061Sespie else
1934*7e568061Sespie {
1935*7e568061Sespie BadCond (Flaw, "Underflow can stick at an allegedly positive\n");
1936*7e568061Sespie printf ("value PseudoZero that prints out as %s .\n",
1937*7e568061Sespie PseudoZero.str());
1938*7e568061Sespie }
1939*7e568061Sespie TstPtUf ();
1940*7e568061Sespie }
1941*7e568061Sespie /*=============================================*/
1942*7e568061Sespie Milestone = 120;
1943*7e568061Sespie /*=============================================*/
1944*7e568061Sespie if (CInvrse * Y > CInvrse * Y1)
1945*7e568061Sespie {
1946*7e568061Sespie S = H * S;
1947*7e568061Sespie E0 = Underflow;
1948*7e568061Sespie }
1949*7e568061Sespie if (!((E1 == Zero) || (E1 == E0)))
1950*7e568061Sespie {
1951*7e568061Sespie BadCond (Defect, "");
1952*7e568061Sespie if (E1 < E0)
1953*7e568061Sespie {
1954*7e568061Sespie printf ("Products underflow at a higher");
1955*7e568061Sespie printf (" threshold than differences.\n");
1956*7e568061Sespie if (PseudoZero == Zero)
1957*7e568061Sespie E0 = E1;
1958*7e568061Sespie }
1959*7e568061Sespie else
1960*7e568061Sespie {
1961*7e568061Sespie printf ("Difference underflows at a higher");
1962*7e568061Sespie printf (" threshold than products.\n");
1963*7e568061Sespie }
1964*7e568061Sespie }
1965*7e568061Sespie printf ("Smallest strictly positive number found is E0 = %s .\n", E0.str());
1966*7e568061Sespie Z = E0;
1967*7e568061Sespie TstPtUf ();
1968*7e568061Sespie Underflow = E0;
1969*7e568061Sespie if (N == 1)
1970*7e568061Sespie Underflow = Y;
1971*7e568061Sespie I = 4;
1972*7e568061Sespie if (E1 == Zero)
1973*7e568061Sespie I = 3;
1974*7e568061Sespie if (UfThold == Zero)
1975*7e568061Sespie I = I - 2;
1976*7e568061Sespie UfNGrad = true;
1977*7e568061Sespie switch (I)
1978*7e568061Sespie {
1979*7e568061Sespie case 1:
1980*7e568061Sespie UfThold = Underflow;
1981*7e568061Sespie if ((CInvrse * Q) != ((CInvrse * Y) * S))
1982*7e568061Sespie {
1983*7e568061Sespie UfThold = Y;
1984*7e568061Sespie BadCond (Failure, "Either accuracy deteriorates as numbers\n");
1985*7e568061Sespie printf ("approach a threshold = %s\n", UfThold.str());
1986*7e568061Sespie printf (" coming down from %s\n", C.str());
1987*7e568061Sespie printf
1988*7e568061Sespie (" or else multiplication gets too many last digits wrong.\n");
1989*7e568061Sespie }
1990*7e568061Sespie Pause ();
1991*7e568061Sespie break;
1992*7e568061Sespie
1993*7e568061Sespie case 2:
1994*7e568061Sespie BadCond (Failure,
1995*7e568061Sespie "Underflow confuses Comparison, which alleges that\n");
1996*7e568061Sespie printf ("Q == Y while denying that |Q - Y| == 0; these values\n");
1997*7e568061Sespie printf ("print out as Q = %s, Y = %s .\n", Q.str(), Y2.str());
1998*7e568061Sespie printf ("|Q - Y| = %s .\n", FABS (Q - Y2).str());
1999*7e568061Sespie UfThold = Q;
2000*7e568061Sespie break;
2001*7e568061Sespie
2002*7e568061Sespie case 3:
2003*7e568061Sespie X = X;
2004*7e568061Sespie break;
2005*7e568061Sespie
2006*7e568061Sespie case 4:
2007*7e568061Sespie if ((Q == UfThold) && (E1 == E0) && (FABS (UfThold - E1 / E9) <= E1))
2008*7e568061Sespie {
2009*7e568061Sespie UfNGrad = false;
2010*7e568061Sespie printf ("Underflow is gradual; it incurs Absolute Error =\n");
2011*7e568061Sespie printf ("(roundoff in UfThold) < E0.\n");
2012*7e568061Sespie Y = E0 * CInvrse;
2013*7e568061Sespie Y = Y * (OneAndHalf + U2);
2014*7e568061Sespie X = CInvrse * (One + U2);
2015*7e568061Sespie Y = Y / X;
2016*7e568061Sespie IEEE = (Y == E0);
2017*7e568061Sespie }
2018*7e568061Sespie }
2019*7e568061Sespie if (UfNGrad)
2020*7e568061Sespie {
2021*7e568061Sespie printf ("\n");
2022*7e568061Sespie if (setjmp (ovfl_buf))
2023*7e568061Sespie {
2024*7e568061Sespie printf ("Underflow / UfThold failed!\n");
2025*7e568061Sespie R = H + H;
2026*7e568061Sespie }
2027*7e568061Sespie else
2028*7e568061Sespie R = SQRT (Underflow / UfThold);
2029*7e568061Sespie if (R <= H)
2030*7e568061Sespie {
2031*7e568061Sespie Z = R * UfThold;
2032*7e568061Sespie X = Z * (One + R * H * (One + H));
2033*7e568061Sespie }
2034*7e568061Sespie else
2035*7e568061Sespie {
2036*7e568061Sespie Z = UfThold;
2037*7e568061Sespie X = Z * (One + H * H * (One + H));
2038*7e568061Sespie }
2039*7e568061Sespie if (!((X == Z) || (X - Z != Zero)))
2040*7e568061Sespie {
2041*7e568061Sespie BadCond (Flaw, "");
2042*7e568061Sespie printf ("X = %s\n\tis not equal to Z = %s .\n", X.str(), Z.str());
2043*7e568061Sespie Z9 = X - Z;
2044*7e568061Sespie printf ("yet X - Z yields %s .\n", Z9.str());
2045*7e568061Sespie printf (" Should this NOT signal Underflow, ");
2046*7e568061Sespie printf ("this is a SERIOUS DEFECT\nthat causes ");
2047*7e568061Sespie printf ("confusion when innocent statements like\n");;
2048*7e568061Sespie printf (" if (X == Z) ... else");
2049*7e568061Sespie printf (" ... (f(X) - f(Z)) / (X - Z) ...\n");
2050*7e568061Sespie printf ("encounter Division by Zero although actually\n");
2051*7e568061Sespie if (setjmp (ovfl_buf))
2052*7e568061Sespie printf ("X / Z fails!\n");
2053*7e568061Sespie else
2054*7e568061Sespie printf ("X / Z = 1 + %s .\n", ((X / Z - Half) - Half).str());
2055*7e568061Sespie }
2056*7e568061Sespie }
2057*7e568061Sespie printf ("The Underflow threshold is %s, below which\n", UfThold.str());
2058*7e568061Sespie printf ("calculation may suffer larger Relative error than ");
2059*7e568061Sespie printf ("merely roundoff.\n");
2060*7e568061Sespie Y2 = U1 * U1;
2061*7e568061Sespie Y = Y2 * Y2;
2062*7e568061Sespie Y2 = Y * U1;
2063*7e568061Sespie if (Y2 <= UfThold)
2064*7e568061Sespie {
2065*7e568061Sespie if (Y > E0)
2066*7e568061Sespie {
2067*7e568061Sespie BadCond (Defect, "");
2068*7e568061Sespie I = 5;
2069*7e568061Sespie }
2070*7e568061Sespie else
2071*7e568061Sespie {
2072*7e568061Sespie BadCond (Serious, "");
2073*7e568061Sespie I = 4;
2074*7e568061Sespie }
2075*7e568061Sespie printf ("Range is too narrow; U1^%d Underflows.\n", I);
2076*7e568061Sespie }
2077*7e568061Sespie /*=============================================*/
2078*7e568061Sespie Milestone = 130;
2079*7e568061Sespie /*=============================================*/
2080*7e568061Sespie Y = -FLOOR (Half - TwoForty * LOG (UfThold) / LOG (HInvrse)) / TwoForty;
2081*7e568061Sespie Y2 = Y + Y;
2082*7e568061Sespie printf ("Since underflow occurs below the threshold\n");
2083*7e568061Sespie printf ("UfThold = (%s) ^ (%s)\nonly underflow ", HInvrse.str(), Y.str());
2084*7e568061Sespie printf ("should afflict the expression\n\t(%s) ^ (%s);\n",
2085*7e568061Sespie HInvrse.str(), Y2.str());
2086*7e568061Sespie printf ("actually calculating yields:");
2087*7e568061Sespie if (setjmp (ovfl_buf))
2088*7e568061Sespie {
2089*7e568061Sespie BadCond (Serious, "trap on underflow.\n");
2090*7e568061Sespie }
2091*7e568061Sespie else
2092*7e568061Sespie {
2093*7e568061Sespie V9 = POW (HInvrse, Y2);
2094*7e568061Sespie printf (" %s .\n", V9.str());
2095*7e568061Sespie if (!((V9 >= Zero) && (V9 <= (Radix + Radix + E9) * UfThold)))
2096*7e568061Sespie {
2097*7e568061Sespie BadCond (Serious, "this is not between 0 and underflow\n");
2098*7e568061Sespie printf (" threshold = %s .\n", UfThold.str());
2099*7e568061Sespie }
2100*7e568061Sespie else if (!(V9 > UfThold * (One + E9)))
2101*7e568061Sespie printf ("This computed value is O.K.\n");
2102*7e568061Sespie else
2103*7e568061Sespie {
2104*7e568061Sespie BadCond (Defect, "this is not between 0 and underflow\n");
2105*7e568061Sespie printf (" threshold = %s .\n", UfThold.str());
2106*7e568061Sespie }
2107*7e568061Sespie }
2108*7e568061Sespie /*=============================================*/
2109*7e568061Sespie Milestone = 160;
2110*7e568061Sespie /*=============================================*/
2111*7e568061Sespie Pause ();
2112*7e568061Sespie printf ("Searching for Overflow threshold:\n");
2113*7e568061Sespie printf ("This may generate an error.\n");
2114*7e568061Sespie Y = -CInvrse;
2115*7e568061Sespie V9 = HInvrse * Y;
2116*7e568061Sespie if (setjmp (ovfl_buf))
2117*7e568061Sespie {
2118*7e568061Sespie I = 0;
2119*7e568061Sespie V9 = Y;
2120*7e568061Sespie goto overflow;
2121*7e568061Sespie }
2122*7e568061Sespie do
2123*7e568061Sespie {
2124*7e568061Sespie V = Y;
2125*7e568061Sespie Y = V9;
2126*7e568061Sespie V9 = HInvrse * Y;
2127*7e568061Sespie }
2128*7e568061Sespie while (V9 < Y);
2129*7e568061Sespie I = 1;
2130*7e568061Sespie overflow:
2131*7e568061Sespie Z = V9;
2132*7e568061Sespie printf ("Can `Z = -Y' overflow?\n");
2133*7e568061Sespie printf ("Trying it on Y = %s .\n", Y.str());
2134*7e568061Sespie V9 = -Y;
2135*7e568061Sespie V0 = V9;
2136*7e568061Sespie if (V - Y == V + V0)
2137*7e568061Sespie printf ("Seems O.K.\n");
2138*7e568061Sespie else
2139*7e568061Sespie {
2140*7e568061Sespie printf ("finds a ");
2141*7e568061Sespie BadCond (Flaw, "-(-Y) differs from Y.\n");
2142*7e568061Sespie }
2143*7e568061Sespie if (Z != Y)
2144*7e568061Sespie {
2145*7e568061Sespie BadCond (Serious, "");
2146*7e568061Sespie printf ("overflow past %s\n\tshrinks to %s .\n", Y.str(), Z.str());
2147*7e568061Sespie }
2148*7e568061Sespie if (I)
2149*7e568061Sespie {
2150*7e568061Sespie Y = V * (HInvrse * U2 - HInvrse);
2151*7e568061Sespie Z = Y + ((One - HInvrse) * U2) * V;
2152*7e568061Sespie if (Z < V0)
2153*7e568061Sespie Y = Z;
2154*7e568061Sespie if (Y < V0)
2155*7e568061Sespie V = Y;
2156*7e568061Sespie if (V0 - V < V0)
2157*7e568061Sespie V = V0;
2158*7e568061Sespie }
2159*7e568061Sespie else
2160*7e568061Sespie {
2161*7e568061Sespie V = Y * (HInvrse * U2 - HInvrse);
2162*7e568061Sespie V = V + ((One - HInvrse) * U2) * Y;
2163*7e568061Sespie }
2164*7e568061Sespie printf ("Overflow threshold is V = %s .\n", V.str());
2165*7e568061Sespie if (I)
2166*7e568061Sespie printf ("Overflow saturates at V0 = %s .\n", V0.str());
2167*7e568061Sespie else
2168*7e568061Sespie printf ("There is no saturation value because "
2169*7e568061Sespie "the system traps on overflow.\n");
2170*7e568061Sespie V9 = V * One;
2171*7e568061Sespie printf ("No Overflow should be signaled for V * 1 = %s\n", V9.str());
2172*7e568061Sespie V9 = V / One;
2173*7e568061Sespie printf (" nor for V / 1 = %s.\n", V9.str());
2174*7e568061Sespie printf ("Any overflow signal separating this * from the one\n");
2175*7e568061Sespie printf ("above is a DEFECT.\n");
2176*7e568061Sespie /*=============================================*/
2177*7e568061Sespie Milestone = 170;
2178*7e568061Sespie /*=============================================*/
2179*7e568061Sespie if (!(-V < V && -V0 < V0 && -UfThold < V && UfThold < V))
2180*7e568061Sespie {
2181*7e568061Sespie BadCond (Failure, "Comparisons involving ");
2182*7e568061Sespie printf ("+-%s, +-%s\nand +-%s are confused by Overflow.",
2183*7e568061Sespie V.str(), V0.str(), UfThold.str());
2184*7e568061Sespie }
2185*7e568061Sespie /*=============================================*/
2186*7e568061Sespie Milestone = 175;
2187*7e568061Sespie /*=============================================*/
2188*7e568061Sespie printf ("\n");
2189*7e568061Sespie for (Indx = 1; Indx <= 3; ++Indx)
2190*7e568061Sespie {
2191*7e568061Sespie switch (Indx)
2192*7e568061Sespie {
2193*7e568061Sespie case 1:
2194*7e568061Sespie Z = UfThold;
2195*7e568061Sespie break;
2196*7e568061Sespie case 2:
2197*7e568061Sespie Z = E0;
2198*7e568061Sespie break;
2199*7e568061Sespie case 3:
2200*7e568061Sespie Z = PseudoZero;
2201*7e568061Sespie break;
2202*7e568061Sespie }
2203*7e568061Sespie if (Z != Zero)
2204*7e568061Sespie {
2205*7e568061Sespie V9 = SQRT (Z);
2206*7e568061Sespie Y = V9 * V9;
2207*7e568061Sespie if (Y / (One - Radix * E9) < Z || Y > (One + Radix * E9) * Z)
2208*7e568061Sespie { /* dgh: + E9 --> * E9 */
2209*7e568061Sespie if (V9 > U1)
2210*7e568061Sespie BadCond (Serious, "");
2211*7e568061Sespie else
2212*7e568061Sespie BadCond (Defect, "");
2213*7e568061Sespie printf ("Comparison alleges that what prints as Z = %s\n",
2214*7e568061Sespie Z.str());
2215*7e568061Sespie printf (" is too far from sqrt(Z) ^ 2 = %s .\n", Y.str());
2216*7e568061Sespie }
2217*7e568061Sespie }
2218*7e568061Sespie }
2219*7e568061Sespie /*=============================================*/
2220*7e568061Sespie Milestone = 180;
2221*7e568061Sespie /*=============================================*/
2222*7e568061Sespie for (Indx = 1; Indx <= 2; ++Indx)
2223*7e568061Sespie {
2224*7e568061Sespie if (Indx == 1)
2225*7e568061Sespie Z = V;
2226*7e568061Sespie else
2227*7e568061Sespie Z = V0;
2228*7e568061Sespie V9 = SQRT (Z);
2229*7e568061Sespie X = (One - Radix * E9) * V9;
2230*7e568061Sespie V9 = V9 * X;
2231*7e568061Sespie if (((V9 < (One - Two * Radix * E9) * Z) || (V9 > Z)))
2232*7e568061Sespie {
2233*7e568061Sespie Y = V9;
2234*7e568061Sespie if (X < W)
2235*7e568061Sespie BadCond (Serious, "");
2236*7e568061Sespie else
2237*7e568061Sespie BadCond (Defect, "");
2238*7e568061Sespie printf ("Comparison alleges that Z = %s\n", Z.str());
2239*7e568061Sespie printf (" is too far from sqrt(Z) ^ 2 (%s) .\n", Y.str());
2240*7e568061Sespie }
2241*7e568061Sespie }
2242*7e568061Sespie /*=============================================*/
2243*7e568061Sespie Milestone = 190;
2244*7e568061Sespie /*=============================================*/
2245*7e568061Sespie Pause ();
2246*7e568061Sespie X = UfThold * V;
2247*7e568061Sespie Y = Radix * Radix;
2248*7e568061Sespie if (X * Y < One || X > Y)
2249*7e568061Sespie {
2250*7e568061Sespie if (X * Y < U1 || X > Y / U1)
2251*7e568061Sespie BadCond (Defect, "Badly");
2252*7e568061Sespie else
2253*7e568061Sespie BadCond (Flaw, "");
2254*7e568061Sespie
2255*7e568061Sespie printf (" unbalanced range; UfThold * V = %s\n\t%s\n",
2256*7e568061Sespie X.str(), "is too far from 1.\n");
2257*7e568061Sespie }
2258*7e568061Sespie /*=============================================*/
2259*7e568061Sespie Milestone = 200;
2260*7e568061Sespie /*=============================================*/
2261*7e568061Sespie for (Indx = 1; Indx <= 5; ++Indx)
2262*7e568061Sespie {
2263*7e568061Sespie X = F9;
2264*7e568061Sespie switch (Indx)
2265*7e568061Sespie {
2266*7e568061Sespie case 2:
2267*7e568061Sespie X = One + U2;
2268*7e568061Sespie break;
2269*7e568061Sespie case 3:
2270*7e568061Sespie X = V;
2271*7e568061Sespie break;
2272*7e568061Sespie case 4:
2273*7e568061Sespie X = UfThold;
2274*7e568061Sespie break;
2275*7e568061Sespie case 5:
2276*7e568061Sespie X = Radix;
2277*7e568061Sespie }
2278*7e568061Sespie Y = X;
2279*7e568061Sespie if (setjmp (ovfl_buf))
2280*7e568061Sespie printf (" X / X traps when X = %s\n", X.str());
2281*7e568061Sespie else
2282*7e568061Sespie {
2283*7e568061Sespie V9 = (Y / X - Half) - Half;
2284*7e568061Sespie if (V9 == Zero)
2285*7e568061Sespie continue;
2286*7e568061Sespie if (V9 == -U1 && Indx < 5)
2287*7e568061Sespie BadCond (Flaw, "");
2288*7e568061Sespie else
2289*7e568061Sespie BadCond (Serious, "");
2290*7e568061Sespie printf (" X / X differs from 1 when X = %s\n", X.str());
2291*7e568061Sespie printf (" instead, X / X - 1/2 - 1/2 = %s .\n", V9.str());
2292*7e568061Sespie }
2293*7e568061Sespie }
2294*7e568061Sespie /*=============================================*/
2295*7e568061Sespie Milestone = 210;
2296*7e568061Sespie /*=============================================*/
2297*7e568061Sespie MyZero = Zero;
2298*7e568061Sespie printf ("\n");
2299*7e568061Sespie printf ("What message and/or values does Division by Zero produce?\n");
2300*7e568061Sespie printf (" Trying to compute 1 / 0 produces ...");
2301*7e568061Sespie if (!setjmp (ovfl_buf))
2302*7e568061Sespie printf (" %s .\n", (One / MyZero).str());
2303*7e568061Sespie printf ("\n Trying to compute 0 / 0 produces ...");
2304*7e568061Sespie if (!setjmp (ovfl_buf))
2305*7e568061Sespie printf (" %s .\n", (Zero / MyZero).str());
2306*7e568061Sespie /*=============================================*/
2307*7e568061Sespie Milestone = 220;
2308*7e568061Sespie /*=============================================*/
2309*7e568061Sespie Pause ();
2310*7e568061Sespie printf ("\n");
2311*7e568061Sespie {
2312*7e568061Sespie static const char *msg[] = {
2313*7e568061Sespie "FAILUREs encountered =",
2314*7e568061Sespie "SERIOUS DEFECTs discovered =",
2315*7e568061Sespie "DEFECTs discovered =",
2316*7e568061Sespie "FLAWs discovered ="
2317*7e568061Sespie };
2318*7e568061Sespie int i;
2319*7e568061Sespie for (i = 0; i < 4; i++)
2320*7e568061Sespie if (ErrCnt[i])
2321*7e568061Sespie printf ("The number of %-29s %d.\n", msg[i], ErrCnt[i]);
2322*7e568061Sespie }
2323*7e568061Sespie printf ("\n");
2324*7e568061Sespie if ((ErrCnt[Failure] + ErrCnt[Serious] + ErrCnt[Defect] + ErrCnt[Flaw]) > 0)
2325*7e568061Sespie {
2326*7e568061Sespie if ((ErrCnt[Failure] + ErrCnt[Serious] + ErrCnt[Defect] == 0)
2327*7e568061Sespie && (ErrCnt[Flaw] > 0))
2328*7e568061Sespie {
2329*7e568061Sespie printf ("The arithmetic diagnosed seems ");
2330*7e568061Sespie printf ("Satisfactory though flawed.\n");
2331*7e568061Sespie }
2332*7e568061Sespie if ((ErrCnt[Failure] + ErrCnt[Serious] == 0) && (ErrCnt[Defect] > 0))
2333*7e568061Sespie {
2334*7e568061Sespie printf ("The arithmetic diagnosed may be Acceptable\n");
2335*7e568061Sespie printf ("despite inconvenient Defects.\n");
2336*7e568061Sespie }
2337*7e568061Sespie if ((ErrCnt[Failure] + ErrCnt[Serious]) > 0)
2338*7e568061Sespie {
2339*7e568061Sespie printf ("The arithmetic diagnosed has ");
2340*7e568061Sespie printf ("unacceptable Serious Defects.\n");
2341*7e568061Sespie }
2342*7e568061Sespie if (ErrCnt[Failure] > 0)
2343*7e568061Sespie {
2344*7e568061Sespie printf ("Potentially fatal FAILURE may have spoiled this");
2345*7e568061Sespie printf (" program's subsequent diagnoses.\n");
2346*7e568061Sespie }
2347*7e568061Sespie }
2348*7e568061Sespie else
2349*7e568061Sespie {
2350*7e568061Sespie printf ("No failures, defects nor flaws have been discovered.\n");
2351*7e568061Sespie if (!((RMult == Rounded) && (RDiv == Rounded)
2352*7e568061Sespie && (RAddSub == Rounded) && (RSqrt == Rounded)))
2353*7e568061Sespie printf ("The arithmetic diagnosed seems Satisfactory.\n");
2354*7e568061Sespie else
2355*7e568061Sespie {
2356*7e568061Sespie if (StickyBit >= One &&
2357*7e568061Sespie (Radix - Two) * (Radix - Nine - One) == Zero)
2358*7e568061Sespie {
2359*7e568061Sespie printf ("Rounding appears to conform to ");
2360*7e568061Sespie printf ("the proposed IEEE standard P");
2361*7e568061Sespie if ((Radix == Two) &&
2362*7e568061Sespie ((Precision - Four * Three * Two) *
2363*7e568061Sespie (Precision - TwentySeven - TwentySeven + One) == Zero))
2364*7e568061Sespie printf ("754");
2365*7e568061Sespie else
2366*7e568061Sespie printf ("854");
2367*7e568061Sespie if (IEEE)
2368*7e568061Sespie printf (".\n");
2369*7e568061Sespie else
2370*7e568061Sespie {
2371*7e568061Sespie printf (",\nexcept for possibly Double Rounding");
2372*7e568061Sespie printf (" during Gradual Underflow.\n");
2373*7e568061Sespie }
2374*7e568061Sespie }
2375*7e568061Sespie printf ("The arithmetic diagnosed appears to be Excellent!\n");
2376*7e568061Sespie }
2377*7e568061Sespie }
2378*7e568061Sespie printf ("END OF TEST.\n");
2379*7e568061Sespie return 0;
2380*7e568061Sespie }
2381*7e568061Sespie
2382*7e568061Sespie template<typename FLOAT>
2383*7e568061Sespie FLOAT
Sign(FLOAT X)2384*7e568061Sespie Paranoia<FLOAT>::Sign (FLOAT X)
2385*7e568061Sespie {
2386*7e568061Sespie return X >= FLOAT (long (0)) ? 1 : -1;
2387*7e568061Sespie }
2388*7e568061Sespie
2389*7e568061Sespie template<typename FLOAT>
2390*7e568061Sespie void
Pause()2391*7e568061Sespie Paranoia<FLOAT>::Pause ()
2392*7e568061Sespie {
2393*7e568061Sespie if (do_pause)
2394*7e568061Sespie {
2395*7e568061Sespie fputs ("Press return...", stdout);
2396*7e568061Sespie fflush (stdout);
2397*7e568061Sespie getchar();
2398*7e568061Sespie }
2399*7e568061Sespie printf ("\nDiagnosis resumes after milestone Number %d", Milestone);
2400*7e568061Sespie printf (" Page: %d\n\n", PageNo);
2401*7e568061Sespie ++Milestone;
2402*7e568061Sespie ++PageNo;
2403*7e568061Sespie }
2404*7e568061Sespie
2405*7e568061Sespie template<typename FLOAT>
2406*7e568061Sespie void
TstCond(int K,int Valid,const char * T)2407*7e568061Sespie Paranoia<FLOAT>::TstCond (int K, int Valid, const char *T)
2408*7e568061Sespie {
2409*7e568061Sespie if (!Valid)
2410*7e568061Sespie {
2411*7e568061Sespie BadCond (K, T);
2412*7e568061Sespie printf (".\n");
2413*7e568061Sespie }
2414*7e568061Sespie }
2415*7e568061Sespie
2416*7e568061Sespie template<typename FLOAT>
2417*7e568061Sespie void
BadCond(int K,const char * T)2418*7e568061Sespie Paranoia<FLOAT>::BadCond (int K, const char *T)
2419*7e568061Sespie {
2420*7e568061Sespie static const char *msg[] = { "FAILURE", "SERIOUS DEFECT", "DEFECT", "FLAW" };
2421*7e568061Sespie
2422*7e568061Sespie ErrCnt[K] = ErrCnt[K] + 1;
2423*7e568061Sespie printf ("%s: %s", msg[K], T);
2424*7e568061Sespie }
2425*7e568061Sespie
2426*7e568061Sespie /* Random computes
2427*7e568061Sespie X = (Random1 + Random9)^5
2428*7e568061Sespie Random1 = X - FLOOR(X) + 0.000005 * X;
2429*7e568061Sespie and returns the new value of Random1. */
2430*7e568061Sespie
2431*7e568061Sespie template<typename FLOAT>
2432*7e568061Sespie FLOAT
Random()2433*7e568061Sespie Paranoia<FLOAT>::Random ()
2434*7e568061Sespie {
2435*7e568061Sespie FLOAT X, Y;
2436*7e568061Sespie
2437*7e568061Sespie X = Random1 + Random9;
2438*7e568061Sespie Y = X * X;
2439*7e568061Sespie Y = Y * Y;
2440*7e568061Sespie X = X * Y;
2441*7e568061Sespie Y = X - FLOOR (X);
2442*7e568061Sespie Random1 = Y + X * FLOAT ("0.000005");
2443*7e568061Sespie return (Random1);
2444*7e568061Sespie }
2445*7e568061Sespie
2446*7e568061Sespie template<typename FLOAT>
2447*7e568061Sespie void
SqXMinX(int ErrKind)2448*7e568061Sespie Paranoia<FLOAT>::SqXMinX (int ErrKind)
2449*7e568061Sespie {
2450*7e568061Sespie FLOAT XA, XB;
2451*7e568061Sespie
2452*7e568061Sespie XB = X * BInvrse;
2453*7e568061Sespie XA = X - XB;
2454*7e568061Sespie SqEr = ((SQRT (X * X) - XB) - XA) / OneUlp;
2455*7e568061Sespie if (SqEr != Zero)
2456*7e568061Sespie {
2457*7e568061Sespie if (SqEr < MinSqEr)
2458*7e568061Sespie MinSqEr = SqEr;
2459*7e568061Sespie if (SqEr > MaxSqEr)
2460*7e568061Sespie MaxSqEr = SqEr;
2461*7e568061Sespie J = J + 1;
2462*7e568061Sespie BadCond (ErrKind, "\n");
2463*7e568061Sespie printf ("sqrt(%s) - %s = %s\n", (X * X).str(), X.str(),
2464*7e568061Sespie (OneUlp * SqEr).str());
2465*7e568061Sespie printf ("\tinstead of correct value 0 .\n");
2466*7e568061Sespie }
2467*7e568061Sespie }
2468*7e568061Sespie
2469*7e568061Sespie template<typename FLOAT>
2470*7e568061Sespie void
NewD()2471*7e568061Sespie Paranoia<FLOAT>::NewD ()
2472*7e568061Sespie {
2473*7e568061Sespie X = Z1 * Q;
2474*7e568061Sespie X = FLOOR (Half - X / Radix) * Radix + X;
2475*7e568061Sespie Q = (Q - X * Z) / Radix + X * X * (D / Radix);
2476*7e568061Sespie Z = Z - Two * X * D;
2477*7e568061Sespie if (Z <= Zero)
2478*7e568061Sespie {
2479*7e568061Sespie Z = -Z;
2480*7e568061Sespie Z1 = -Z1;
2481*7e568061Sespie }
2482*7e568061Sespie D = Radix * D;
2483*7e568061Sespie }
2484*7e568061Sespie
2485*7e568061Sespie template<typename FLOAT>
2486*7e568061Sespie void
SR3750()2487*7e568061Sespie Paranoia<FLOAT>::SR3750 ()
2488*7e568061Sespie {
2489*7e568061Sespie if (!((X - Radix < Z2 - Radix) || (X - Z2 > W - Z2)))
2490*7e568061Sespie {
2491*7e568061Sespie I = I + 1;
2492*7e568061Sespie X2 = SQRT (X * D);
2493*7e568061Sespie Y2 = (X2 - Z2) - (Y - Z2);
2494*7e568061Sespie X2 = X8 / (Y - Half);
2495*7e568061Sespie X2 = X2 - Half * X2 * X2;
2496*7e568061Sespie SqEr = (Y2 + Half) + (Half - X2);
2497*7e568061Sespie if (SqEr < MinSqEr)
2498*7e568061Sespie MinSqEr = SqEr;
2499*7e568061Sespie SqEr = Y2 - X2;
2500*7e568061Sespie if (SqEr > MaxSqEr)
2501*7e568061Sespie MaxSqEr = SqEr;
2502*7e568061Sespie }
2503*7e568061Sespie }
2504*7e568061Sespie
2505*7e568061Sespie template<typename FLOAT>
2506*7e568061Sespie void
IsYeqX()2507*7e568061Sespie Paranoia<FLOAT>::IsYeqX ()
2508*7e568061Sespie {
2509*7e568061Sespie if (Y != X)
2510*7e568061Sespie {
2511*7e568061Sespie if (N <= 0)
2512*7e568061Sespie {
2513*7e568061Sespie if (Z == Zero && Q <= Zero)
2514*7e568061Sespie printf ("WARNING: computing\n");
2515*7e568061Sespie else
2516*7e568061Sespie BadCond (Defect, "computing\n");
2517*7e568061Sespie printf ("\t(%s) ^ (%s)\n", Z.str(), Q.str());
2518*7e568061Sespie printf ("\tyielded %s;\n", Y.str());
2519*7e568061Sespie printf ("\twhich compared unequal to correct %s ;\n", X.str());
2520*7e568061Sespie printf ("\t\tthey differ by %s .\n", (Y - X).str());
2521*7e568061Sespie }
2522*7e568061Sespie N = N + 1; /* ... count discrepancies. */
2523*7e568061Sespie }
2524*7e568061Sespie }
2525*7e568061Sespie
2526*7e568061Sespie template<typename FLOAT>
2527*7e568061Sespie void
PrintIfNPositive()2528*7e568061Sespie Paranoia<FLOAT>::PrintIfNPositive ()
2529*7e568061Sespie {
2530*7e568061Sespie if (N > 0)
2531*7e568061Sespie printf ("Similar discrepancies have occurred %d times.\n", N);
2532*7e568061Sespie }
2533*7e568061Sespie
2534*7e568061Sespie template<typename FLOAT>
2535*7e568061Sespie void
TstPtUf()2536*7e568061Sespie Paranoia<FLOAT>::TstPtUf ()
2537*7e568061Sespie {
2538*7e568061Sespie N = 0;
2539*7e568061Sespie if (Z != Zero)
2540*7e568061Sespie {
2541*7e568061Sespie printf ("Since comparison denies Z = 0, evaluating ");
2542*7e568061Sespie printf ("(Z + Z) / Z should be safe.\n");
2543*7e568061Sespie if (setjmp (ovfl_buf))
2544*7e568061Sespie goto very_serious;
2545*7e568061Sespie Q9 = (Z + Z) / Z;
2546*7e568061Sespie printf ("What the machine gets for (Z + Z) / Z is %s .\n", Q9.str());
2547*7e568061Sespie if (FABS (Q9 - Two) < Radix * U2)
2548*7e568061Sespie {
2549*7e568061Sespie printf ("This is O.K., provided Over/Underflow");
2550*7e568061Sespie printf (" has NOT just been signaled.\n");
2551*7e568061Sespie }
2552*7e568061Sespie else
2553*7e568061Sespie {
2554*7e568061Sespie if ((Q9 < One) || (Q9 > Two))
2555*7e568061Sespie {
2556*7e568061Sespie very_serious:
2557*7e568061Sespie N = 1;
2558*7e568061Sespie ErrCnt[Serious] = ErrCnt[Serious] + 1;
2559*7e568061Sespie printf ("This is a VERY SERIOUS DEFECT!\n");
2560*7e568061Sespie }
2561*7e568061Sespie else
2562*7e568061Sespie {
2563*7e568061Sespie N = 1;
2564*7e568061Sespie ErrCnt[Defect] = ErrCnt[Defect] + 1;
2565*7e568061Sespie printf ("This is a DEFECT!\n");
2566*7e568061Sespie }
2567*7e568061Sespie }
2568*7e568061Sespie V9 = Z * One;
2569*7e568061Sespie Random1 = V9;
2570*7e568061Sespie V9 = One * Z;
2571*7e568061Sespie Random2 = V9;
2572*7e568061Sespie V9 = Z / One;
2573*7e568061Sespie if ((Z == Random1) && (Z == Random2) && (Z == V9))
2574*7e568061Sespie {
2575*7e568061Sespie if (N > 0)
2576*7e568061Sespie Pause ();
2577*7e568061Sespie }
2578*7e568061Sespie else
2579*7e568061Sespie {
2580*7e568061Sespie N = 1;
2581*7e568061Sespie BadCond (Defect, "What prints as Z = ");
2582*7e568061Sespie printf ("%s\n\tcompares different from ", Z.str());
2583*7e568061Sespie if (Z != Random1)
2584*7e568061Sespie printf ("Z * 1 = %s ", Random1.str());
2585*7e568061Sespie if (!((Z == Random2) || (Random2 == Random1)))
2586*7e568061Sespie printf ("1 * Z == %s\n", Random2.str());
2587*7e568061Sespie if (!(Z == V9))
2588*7e568061Sespie printf ("Z / 1 = %s\n", V9.str());
2589*7e568061Sespie if (Random2 != Random1)
2590*7e568061Sespie {
2591*7e568061Sespie ErrCnt[Defect] = ErrCnt[Defect] + 1;
2592*7e568061Sespie BadCond (Defect, "Multiplication does not commute!\n");
2593*7e568061Sespie printf ("\tComparison alleges that 1 * Z = %s\n", Random2.str());
2594*7e568061Sespie printf ("\tdiffers from Z * 1 = %s\n", Random1.str());
2595*7e568061Sespie }
2596*7e568061Sespie Pause ();
2597*7e568061Sespie }
2598*7e568061Sespie }
2599*7e568061Sespie }
2600*7e568061Sespie
2601*7e568061Sespie template<typename FLOAT>
2602*7e568061Sespie void
notify(const char * s)2603*7e568061Sespie Paranoia<FLOAT>::notify (const char *s)
2604*7e568061Sespie {
2605*7e568061Sespie printf ("%s test appears to be inconsistent...\n", s);
2606*7e568061Sespie printf (" PLEASE NOTIFY KARPINKSI!\n");
2607*7e568061Sespie }
2608*7e568061Sespie
2609*7e568061Sespie /* ====================================================================== */
2610*7e568061Sespie
main(int ac,char ** av)2611*7e568061Sespie int main(int ac, char **av)
2612*7e568061Sespie {
2613*7e568061Sespie setbuf(stdout, NULL);
2614*7e568061Sespie setbuf(stderr, NULL);
2615*7e568061Sespie
2616*7e568061Sespie while (1)
2617*7e568061Sespie switch (getopt (ac, av, "pvg:fdl"))
2618*7e568061Sespie {
2619*7e568061Sespie case -1:
2620*7e568061Sespie return 0;
2621*7e568061Sespie case 'p':
2622*7e568061Sespie do_pause = true;
2623*7e568061Sespie break;
2624*7e568061Sespie case 'v':
2625*7e568061Sespie verbose = true;
2626*7e568061Sespie break;
2627*7e568061Sespie case 'g':
2628*7e568061Sespie {
2629*7e568061Sespie static const struct {
2630*7e568061Sespie const char *name;
2631*7e568061Sespie const struct real_format *fmt;
2632*7e568061Sespie } fmts[] = {
2633*7e568061Sespie #define F(x) { #x, &x##_format }
2634*7e568061Sespie F(ieee_single),
2635*7e568061Sespie F(ieee_double),
2636*7e568061Sespie F(ieee_extended_motorola),
2637*7e568061Sespie F(ieee_extended_intel_96),
2638*7e568061Sespie F(ieee_extended_intel_128),
2639*7e568061Sespie F(ibm_extended),
2640*7e568061Sespie F(ieee_quad),
2641*7e568061Sespie F(vax_f),
2642*7e568061Sespie F(vax_d),
2643*7e568061Sespie F(vax_g),
2644*7e568061Sespie F(i370_single),
2645*7e568061Sespie F(i370_double),
2646*7e568061Sespie F(c4x_single),
2647*7e568061Sespie F(c4x_extended),
2648*7e568061Sespie F(real_internal),
2649*7e568061Sespie #undef F
2650*7e568061Sespie };
2651*7e568061Sespie
2652*7e568061Sespie int i, n = sizeof (fmts)/sizeof(*fmts);
2653*7e568061Sespie
2654*7e568061Sespie for (i = 0; i < n; ++i)
2655*7e568061Sespie if (strcmp (fmts[i].name, optarg) == 0)
2656*7e568061Sespie break;
2657*7e568061Sespie
2658*7e568061Sespie if (i == n)
2659*7e568061Sespie {
2660*7e568061Sespie printf ("Unknown implementation \"%s\"; "
2661*7e568061Sespie "available implementations:\n", optarg);
2662*7e568061Sespie for (i = 0; i < n; ++i)
2663*7e568061Sespie printf ("\t%s\n", fmts[i].name);
2664*7e568061Sespie return 1;
2665*7e568061Sespie }
2666*7e568061Sespie
2667*7e568061Sespie // We cheat and use the same mode all the time, but vary
2668*7e568061Sespie // the format used for that mode.
2669*7e568061Sespie real_format_for_mode[int(real_c_float::MODE) - int(QFmode)]
2670*7e568061Sespie = fmts[i].fmt;
2671*7e568061Sespie
2672*7e568061Sespie Paranoia<real_c_float>().main();
2673*7e568061Sespie break;
2674*7e568061Sespie }
2675*7e568061Sespie
2676*7e568061Sespie case 'f':
2677*7e568061Sespie Paranoia < native_float<float> >().main();
2678*7e568061Sespie break;
2679*7e568061Sespie case 'd':
2680*7e568061Sespie Paranoia < native_float<double> >().main();
2681*7e568061Sespie break;
2682*7e568061Sespie case 'l':
2683*7e568061Sespie #ifndef NO_LONG_DOUBLE
2684*7e568061Sespie Paranoia < native_float<long double> >().main();
2685*7e568061Sespie #endif
2686*7e568061Sespie break;
2687*7e568061Sespie
2688*7e568061Sespie case '?':
2689*7e568061Sespie puts ("-p\tpause between pages");
2690*7e568061Sespie puts ("-g<FMT>\treal.c implementation FMT");
2691*7e568061Sespie puts ("-f\tnative float");
2692*7e568061Sespie puts ("-d\tnative double");
2693*7e568061Sespie puts ("-l\tnative long double");
2694*7e568061Sespie return 0;
2695*7e568061Sespie }
2696*7e568061Sespie }
2697*7e568061Sespie
2698*7e568061Sespie /* GCC stuff referenced by real.o. */
2699*7e568061Sespie
2700*7e568061Sespie extern "C" void
fancy_abort()2701*7e568061Sespie fancy_abort ()
2702*7e568061Sespie {
2703*7e568061Sespie abort ();
2704*7e568061Sespie }
2705*7e568061Sespie
2706*7e568061Sespie int target_flags = 0;
2707*7e568061Sespie
2708*7e568061Sespie extern "C" int
floor_log2_wide(unsigned HOST_WIDE_INT x)2709*7e568061Sespie floor_log2_wide (unsigned HOST_WIDE_INT x)
2710*7e568061Sespie {
2711*7e568061Sespie int log = -1;
2712*7e568061Sespie while (x != 0)
2713*7e568061Sespie log++,
2714*7e568061Sespie x >>= 1;
2715*7e568061Sespie return log;
2716*7e568061Sespie }
2717