OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [contrib/] [paranoia.cc] - Rev 723

Compare with Previous | Blame | View Log

/*	A C version of Kahan's Floating Point Test "Paranoia"
 
Thos Sumner, UCSF, Feb. 1985
David Gay, BTL, Jan. 1986
 
This is a rewrite from the Pascal version by
 
B. A. Wichmann, 18 Jan. 1985
 
(and does NOT exhibit good C programming style).
 
Adjusted to use Standard C headers 19 Jan. 1992 (dmg);
 
(C) Apr 19 1983 in BASIC version by:
Professor W. M. Kahan,
567 Evans Hall
Electrical Engineering & Computer Science Dept.
University of California
Berkeley, California 94720
USA
 
converted to Pascal by:
B. A. Wichmann
National Physical Laboratory
Teddington Middx
TW11 OLW
UK
 
converted to C by:
 
David M. Gay		and	Thos Sumner
AT&T Bell Labs			Computer Center, Rm. U-76
600 Mountain Avenue		University of California
Murray Hill, NJ 07974		San Francisco, CA 94143
USA				USA
 
with simultaneous corrections to the Pascal source (reflected
in the Pascal source available over netlib).
[A couple of bug fixes from dgh = sun!dhough incorporated 31 July 1986.]
 
Reports of results on various systems from all the versions
of Paranoia are being collected by Richard Karpinski at the
same address as Thos Sumner.  This includes sample outputs,
bug reports, and criticisms.
 
You may copy this program freely if you acknowledge its source.
Comments on the Pascal version to NPL, please.
 
The following is from the introductory commentary from Wichmann's work:
 
The BASIC program of Kahan is written in Microsoft BASIC using many
facilities which have no exact analogy in Pascal.  The Pascal
version below cannot therefore be exactly the same.  Rather than be
a minimal transcription of the BASIC program, the Pascal coding
follows the conventional style of block-structured languages.  Hence
the Pascal version could be useful in producing versions in other
structured languages.
 
Rather than use identifiers of minimal length (which therefore have
little mnemonic significance), the Pascal version uses meaningful
identifiers as follows [Note: A few changes have been made for C]:
 
 
BASIC   C               BASIC   C               BASIC   C
 
A                       J                       S    StickyBit
A1   AInverse           J0   NoErrors           T
B    Radix                    [Failure]         T0   Underflow
B1   BInverse           J1   NoErrors           T2   ThirtyTwo
B2   RadixD2                  [SeriousDefect]   T5   OneAndHalf
B9   BMinusU2           J2   NoErrors           T7   TwentySeven
C                             [Defect]          T8   TwoForty
C1   CInverse           J3   NoErrors           U    OneUlp
D                             [Flaw]            U0   UnderflowThreshold
D4   FourD              K    PageNo             U1
E0                      L    Milestone          U2
E1                      M                       V
E2   Exp2               N                       V0
E3                      N1                      V8
E5   MinSqEr            O    Zero               V9
E6   SqEr               O1   One                W
E7   MaxSqEr            O2   Two                X
E8                      O3   Three              X1
E9                      O4   Four               X8
F1   MinusOne           O5   Five               X9   Random1
F2   Half               O8   Eight              Y
F3   Third              O9   Nine               Y1
F6                      P    Precision          Y2
F9                      Q                       Y9   Random2
G1   GMult              Q8                      Z
G2   GDiv               Q9                      Z0   PseudoZero
G3   GAddSub            R                       Z1
H                       R1   RMult              Z2
H1   HInverse           R2   RDiv               Z9
I                       R3   RAddSub
IO   NoTrials           R4   RSqrt
I3   IEEE               R9   Random9
 
SqRWrng
 
All the variables in BASIC are true variables and in consequence,
the program is more difficult to follow since the "constants" must
be determined (the glossary is very helpful).  The Pascal version
uses Real constants, but checks are added to ensure that the values
are correctly converted by the compiler.
 
The major textual change to the Pascal version apart from the
identifiersis that named procedures are used, inserting parameters
wherehelpful.  New procedures are also introduced.  The
correspondence is as follows:
 
 
BASIC       Pascal
lines
 
90- 140   Pause
170- 250   Instructions
380- 460   Heading
480- 670   Characteristics
690- 870   History
2940-2950   Random
3710-3740   NewD
4040-4080   DoesYequalX
4090-4110   PrintIfNPositive
4640-4850   TestPartialUnderflow
 
*/
 
  /* This version of paranoia has been modified to work with GCC's internal
     software floating point emulation library, as a sanity check of same.
 
     I'm doing this in C++ so that I can do operator overloading and not
     have to modify so damned much of the existing code.  */
 
  extern "C" {
#include <stdio.h>
#include <stddef.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <float.h>
 
    /* This part is made all the more awful because many gcc headers are
       not prepared at all to be parsed as C++.  The biggest stickler
       here is const structure members.  So we include exactly the pieces
       that we need.  */
 
#define GTY(x)
 
#include "ansidecl.h"
#include "auto-host.h"
#include "hwint.h"
 
#undef EXTRA_MODES_FILE
 
    struct rtx_def;
    typedef struct rtx_def *rtx;
    struct rtvec_def;
    typedef struct rtvec_def *rtvec;
    union tree_node;
    typedef union tree_node *tree;
 
#define DEFTREECODE(SYM, STRING, TYPE, NARGS)   SYM,
    enum tree_code {
#include "tree.def"
      LAST_AND_UNUSED_TREE_CODE
    };
#undef DEFTREECODE
 
#define class klass
 
#include "real.h"
 
#undef class
  }
 
/* We never produce signals from the library.  Thus setjmp need do nothing.  */
#undef setjmp
#define setjmp(x)  (0)
 
static bool verbose = false;
static int verbose_index = 0;
 
/* ====================================================================== */
/* The implementation of the abstract floating point class based on gcc's
   real.c.  I.e. the object of this exercise.  Templated so that we can
   all fp sizes.  */
 
class real_c_float
{
 public:
  static const enum machine_mode MODE = SFmode;
 
 private:
  static const int external_max = 128 / 32;
  static const int internal_max
    = (sizeof (REAL_VALUE_TYPE) + sizeof (long) + 1) / sizeof (long);
  long image[external_max < internal_max ? internal_max : external_max];
 
  void from_long(long);
  void from_str(const char *);
  void binop(int code, const real_c_float&);
  void unop(int code);
  bool cmp(int code, const real_c_float&) const;
 
 public:
  real_c_float()
    { }
  real_c_float(long l)
    { from_long(l); }
  real_c_float(const char *s)
    { from_str(s); }
  real_c_float(const real_c_float &b)
    { memcpy(image, b.image, sizeof(image)); }
 
  const real_c_float& operator= (long l)
    { from_long(l); return *this; }
  const real_c_float& operator= (const char *s)
    { from_str(s); return *this; }
  const real_c_float& operator= (const real_c_float &b)
    { memcpy(image, b.image, sizeof(image)); return *this; }
 
  const real_c_float& operator+= (const real_c_float &b)
    { binop(PLUS_EXPR, b); return *this; }
  const real_c_float& operator-= (const real_c_float &b)
    { binop(MINUS_EXPR, b); return *this; }
  const real_c_float& operator*= (const real_c_float &b)
    { binop(MULT_EXPR, b); return *this; }
  const real_c_float& operator/= (const real_c_float &b)
    { binop(RDIV_EXPR, b); return *this; }
 
  real_c_float operator- () const
    { real_c_float r(*this); r.unop(NEGATE_EXPR); return r; }
  real_c_float abs () const
    { real_c_float r(*this); r.unop(ABS_EXPR); return r; }
 
  bool operator <  (const real_c_float &b) const { return cmp(LT_EXPR, b); }
  bool operator <= (const real_c_float &b) const { return cmp(LE_EXPR, b); }
  bool operator == (const real_c_float &b) const { return cmp(EQ_EXPR, b); }
  bool operator != (const real_c_float &b) const { return cmp(NE_EXPR, b); }
  bool operator >= (const real_c_float &b) const { return cmp(GE_EXPR, b); }
  bool operator >  (const real_c_float &b) const { return cmp(GT_EXPR, b); }
 
  const char * str () const;
  const char * hex () const;
  long integer () const;
  int exp () const;
  void ldexp (int);
};
 
void
real_c_float::from_long (long l)
{
  REAL_VALUE_TYPE f;
 
  real_from_integer (&f, MODE, l, l < 0 ? -1 : 0, 0);
  real_to_target (image, &f, MODE);
}
 
void
real_c_float::from_str (const char *s)
{
  REAL_VALUE_TYPE f;
  const char *p = s;
 
  if (*p == '-' || *p == '+')
    p++;
  if (strcasecmp(p, "inf") == 0)
    {
      real_inf (&f);
      if (*s == '-')
        real_arithmetic (&f, NEGATE_EXPR, &f, NULL);
    }
  else if (strcasecmp(p, "nan") == 0)
    real_nan (&f, "", 1, MODE);
  else
    real_from_string (&f, s);
 
  real_to_target (image, &f, MODE);
}
 
void
real_c_float::binop (int code, const real_c_float &b)
{
  REAL_VALUE_TYPE ai, bi, ri;
 
  real_from_target (&ai, image, MODE);
  real_from_target (&bi, b.image, MODE);
  real_arithmetic (&ri, code, &ai, &bi);
  real_to_target (image, &ri, MODE);
 
  if (verbose)
    {
      char ab[64], bb[64], rb[64];
      const real_format *fmt = real_format_for_mode[MODE - QFmode];
      const int digits = (fmt->p * fmt->log2_b + 3) / 4;
      char symbol_for_code;
 
      real_from_target (&ri, image, MODE);
      real_to_hexadecimal (ab, &ai, sizeof(ab), digits, 0);
      real_to_hexadecimal (bb, &bi, sizeof(bb), digits, 0);
      real_to_hexadecimal (rb, &ri, sizeof(rb), digits, 0);
 
      switch (code)
	{
	case PLUS_EXPR:
	  symbol_for_code = '+';
	  break;
	case MINUS_EXPR:
	  symbol_for_code = '-';
	  break;
	case MULT_EXPR:
	  symbol_for_code = '*';
	  break;
	case RDIV_EXPR:
	  symbol_for_code = '/';
	  break;
	default:
	  abort ();
	}
 
      fprintf (stderr, "%6d: %s %c %s = %s\n", verbose_index++,
	       ab, symbol_for_code, bb, rb);
    }
}
 
void
real_c_float::unop (int code)
{
  REAL_VALUE_TYPE ai, ri;
 
  real_from_target (&ai, image, MODE);
  real_arithmetic (&ri, code, &ai, NULL);
  real_to_target (image, &ri, MODE);
 
  if (verbose)
    {
      char ab[64], rb[64];
      const real_format *fmt = real_format_for_mode[MODE - QFmode];
      const int digits = (fmt->p * fmt->log2_b + 3) / 4;
      const char *symbol_for_code;
 
      real_from_target (&ri, image, MODE);
      real_to_hexadecimal (ab, &ai, sizeof(ab), digits, 0);
      real_to_hexadecimal (rb, &ri, sizeof(rb), digits, 0);
 
      switch (code)
	{
	case NEGATE_EXPR:
	  symbol_for_code = "-";
	  break;
	case ABS_EXPR:
	  symbol_for_code = "abs ";
	  break;
	default:
	  abort ();
	}
 
      fprintf (stderr, "%6d: %s%s = %s\n", verbose_index++,
	       symbol_for_code, ab, rb);
    }
}
 
bool
real_c_float::cmp (int code, const real_c_float &b) const
{
  REAL_VALUE_TYPE ai, bi;
  bool ret;
 
  real_from_target (&ai, image, MODE);
  real_from_target (&bi, b.image, MODE);
  ret = real_compare (code, &ai, &bi);
 
  if (verbose)
    {
      char ab[64], bb[64];
      const real_format *fmt = real_format_for_mode[MODE - QFmode];
      const int digits = (fmt->p * fmt->log2_b + 3) / 4;
      const char *symbol_for_code;
 
      real_to_hexadecimal (ab, &ai, sizeof(ab), digits, 0);
      real_to_hexadecimal (bb, &bi, sizeof(bb), digits, 0);
 
      switch (code)
	{
	case LT_EXPR:
	  symbol_for_code = "<";
	  break;
	case LE_EXPR:
	  symbol_for_code = "<=";
	  break;
	case EQ_EXPR:
	  symbol_for_code = "==";
	  break;
	case NE_EXPR:
	  symbol_for_code = "!=";
	  break;
	case GE_EXPR:
	  symbol_for_code = ">=";
	  break;
	case GT_EXPR:
	  symbol_for_code = ">";
	  break;
	default:
	  abort ();
	}
 
      fprintf (stderr, "%6d: %s %s %s = %s\n", verbose_index++,
	       ab, symbol_for_code, bb, (ret ? "true" : "false"));
    }
 
  return ret;
}
 
const char *
real_c_float::str() const
{
  REAL_VALUE_TYPE f;
  const real_format *fmt = real_format_for_mode[MODE - QFmode];
  const int digits = int(fmt->p * fmt->log2_b * .30102999566398119521 + 1);
 
  real_from_target (&f, image, MODE);
  char *buf = new char[digits + 10];
  real_to_decimal (buf, &f, digits+10, digits, 0);
 
  return buf;
}
 
const char *
real_c_float::hex() const
{
  REAL_VALUE_TYPE f;
  const real_format *fmt = real_format_for_mode[MODE - QFmode];
  const int digits = (fmt->p * fmt->log2_b + 3) / 4;
 
  real_from_target (&f, image, MODE);
  char *buf = new char[digits + 10];
  real_to_hexadecimal (buf, &f, digits+10, digits, 0);
 
  return buf;
}
 
long
real_c_float::integer() const
{
  REAL_VALUE_TYPE f;
  real_from_target (&f, image, MODE);
  return real_to_integer (&f);
}
 
int
real_c_float::exp() const
{
  REAL_VALUE_TYPE f;
  real_from_target (&f, image, MODE);
  return real_exponent (&f);
}
 
void
real_c_float::ldexp (int exp)
{
  REAL_VALUE_TYPE ai;
 
  real_from_target (&ai, image, MODE);
  real_ldexp (&ai, &ai, exp);
  real_to_target (image, &ai, MODE);
}
 
/* ====================================================================== */
/* An implementation of the abstract floating point class that uses native
   arithmetic.  Exists for reference and debugging.  */
 
template<typename T>
class native_float
{
 private:
  // Force intermediate results back to memory.
  volatile T image;
 
  static T from_str (const char *);
  static T do_abs (T);
  static T verbose_binop (T, char, T, T);
  static T verbose_unop (const char *, T, T);
  static bool verbose_cmp (T, const char *, T, bool);
 
 public:
  native_float()
    { }
  native_float(long l)
    { image = l; }
  native_float(const char *s)
    { image = from_str(s); }
  native_float(const native_float &b)
    { image = b.image; }
 
  const native_float& operator= (long l)
    { image = l; return *this; }
  const native_float& operator= (const char *s)
    { image = from_str(s); return *this; }
  const native_float& operator= (const native_float &b)
    { image = b.image; return *this; }
 
  const native_float& operator+= (const native_float &b)
    {
      image = verbose_binop(image, '+', b.image, image + b.image);
      return *this;
    }
  const native_float& operator-= (const native_float &b)
    {
      image = verbose_binop(image, '-', b.image, image - b.image);
      return *this;
    }
  const native_float& operator*= (const native_float &b)
    {
      image = verbose_binop(image, '*', b.image, image * b.image);
      return *this;
    }
  const native_float& operator/= (const native_float &b)
    {
      image = verbose_binop(image, '/', b.image, image / b.image);
      return *this;
    }
 
  native_float operator- () const
    {
      native_float r;
      r.image = verbose_unop("-", image, -image);
      return r;
    }
  native_float abs () const
    {
      native_float r;
      r.image = verbose_unop("abs ", image, do_abs(image));
      return r;
    }
 
  bool operator <  (const native_float &b) const
    { return verbose_cmp(image, "<", b.image, image <  b.image); }
  bool operator <= (const native_float &b) const
    { return verbose_cmp(image, "<=", b.image, image <= b.image); }
  bool operator == (const native_float &b) const
    { return verbose_cmp(image, "==", b.image, image == b.image); }
  bool operator != (const native_float &b) const
    { return verbose_cmp(image, "!=", b.image, image != b.image); }
  bool operator >= (const native_float &b) const
    { return verbose_cmp(image, ">=", b.image, image >= b.image); }
  bool operator >  (const native_float &b) const
    { return verbose_cmp(image, ">", b.image, image > b.image); }
 
  const char * str () const;
  const char * hex () const;
  long integer () const
    { return long(image); }
  int exp () const;
  void ldexp (int);
};
 
template<typename T>
inline T
native_float<T>::from_str (const char *s)
{
  return strtold (s, NULL);
}
 
template<>
inline float
native_float<float>::from_str (const char *s)
{
  return strtof (s, NULL);
}
 
template<>
inline double
native_float<double>::from_str (const char *s)
{
  return strtod (s, NULL);
}
 
template<typename T>
inline T
native_float<T>::do_abs (T image)
{
  return fabsl (image);
}
 
template<>
inline float
native_float<float>::do_abs (float image)
{
  return fabsf (image);
}
 
template<>
inline double
native_float<double>::do_abs (double image)
{
  return fabs (image);
}
 
template<typename T>
T
native_float<T>::verbose_binop (T a, char symbol, T b, T r)
{
  if (verbose)
    {
      const int digits = int(sizeof(T) * CHAR_BIT / 4) - 1;
#ifdef NO_LONG_DOUBLE
      fprintf (stderr, "%6d: %.*a %c %.*a = %.*a\n", verbose_index++,
	       digits, (double)a, symbol,
	       digits, (double)b, digits, (double)r);
#else
      fprintf (stderr, "%6d: %.*La %c %.*La = %.*La\n", verbose_index++,
	       digits, (long double)a, symbol,
	       digits, (long double)b, digits, (long double)r);
#endif
    }
  return r;
}
 
template<typename T>
T
native_float<T>::verbose_unop (const char *symbol, T a, T r)
{
  if (verbose)
    {
      const int digits = int(sizeof(T) * CHAR_BIT / 4) - 1;
#ifdef NO_LONG_DOUBLE
      fprintf (stderr, "%6d: %s%.*a = %.*a\n", verbose_index++,
	       symbol, digits, (double)a, digits, (double)r);
#else
      fprintf (stderr, "%6d: %s%.*La = %.*La\n", verbose_index++,
	       symbol, digits, (long double)a, digits, (long double)r);
#endif
    }
  return r;
}
 
template<typename T>
bool
native_float<T>::verbose_cmp (T a, const char *symbol, T b, bool r)
{
  if (verbose)
    {
      const int digits = int(sizeof(T) * CHAR_BIT / 4) - 1;
#ifndef NO_LONG_DOUBLE
      fprintf (stderr, "%6d: %.*a %s %.*a = %s\n", verbose_index++,
	       digits, (double)a, symbol,
	       digits, (double)b, (r ? "true" : "false"));
#else
      fprintf (stderr, "%6d: %.*La %s %.*La = %s\n", verbose_index++,
	       digits, (long double)a, symbol,
	       digits, (long double)b, (r ? "true" : "false"));
#endif
    }
  return r;
}
 
template<typename T>
const char *
native_float<T>::str() const
{
  char *buf = new char[50];
  const int digits = int(sizeof(T) * CHAR_BIT * .30102999566398119521 + 1);
#ifndef NO_LONG_DOUBLE
  sprintf (buf, "%.*e", digits - 1, (double) image);
#else
  sprintf (buf, "%.*Le", digits - 1, (long double) image);
#endif
  return buf;
}
 
template<typename T>
const char *
native_float<T>::hex() const
{
  char *buf = new char[50];
  const int digits = int(sizeof(T) * CHAR_BIT / 4);
#ifndef NO_LONG_DOUBLE
  sprintf (buf, "%.*a", digits - 1, (double) image);
#else
  sprintf (buf, "%.*La", digits - 1, (long double) image);
#endif
  return buf;
}
 
template<typename T>
int
native_float<T>::exp() const
{
  int e;
  frexp (image, &e);
  return e;
}
 
template<typename T>
void
native_float<T>::ldexp (int exp)
{
  image = ldexpl (image, exp);
}
 
template<>
void
native_float<float>::ldexp (int exp)
{
  image = ldexpf (image, exp);
}
 
template<>
void
native_float<double>::ldexp (int exp)
{
  image = ::ldexp (image, exp);
}
 
/* ====================================================================== */
/* Some libm routines that Paranoia expects to be available.  */
 
template<typename FLOAT>
inline FLOAT
FABS (const FLOAT &f)
{
  return f.abs();
}
 
template<typename FLOAT, typename RHS>
inline FLOAT
operator+ (const FLOAT &a, const RHS &b)
{
  return FLOAT(a) += FLOAT(b);
}
 
template<typename FLOAT, typename RHS>
inline FLOAT
operator- (const FLOAT &a, const RHS &b)
{
  return FLOAT(a) -= FLOAT(b);
}
 
template<typename FLOAT, typename RHS>
inline FLOAT
operator* (const FLOAT &a, const RHS &b)
{
  return FLOAT(a) *= FLOAT(b);
}
 
template<typename FLOAT, typename RHS>
inline FLOAT
operator/ (const FLOAT &a, const RHS &b)
{
  return FLOAT(a) /= FLOAT(b);
}
 
template<typename FLOAT>
FLOAT
FLOOR (const FLOAT &f)
{
  /* ??? This is only correct when F is representable as an integer.  */
  long i = f.integer();
  FLOAT r;
 
  r = i;
  if (i < 0 && f != r)
    r = i - 1;
 
  return r;
}
 
template<typename FLOAT>
FLOAT
SQRT (const FLOAT &f)
{
#if 0
  FLOAT zero = long(0);
  FLOAT two = 2;
  FLOAT one = 1;
  FLOAT diff, diff2;
  FLOAT z, t;
 
  if (f == zero)
    return zero;
  if (f < zero)
    return zero / zero;
  if (f == one)
    return f;
 
  z = f;
  z.ldexp (-f.exp() / 2);
 
  diff2 = FABS (z * z - f);
  if (diff2 > zero)
    while (1)
      {
	t = (f / (two * z)) + (z / two);
	diff = FABS (t * t - f);
	if (diff >= diff2)
	  break;
	z = t;
	diff2 = diff;
      }
 
  return z;
#elif defined(NO_LONG_DOUBLE)
  double d;
  char buf[64];
 
  d = strtod (f.hex(), NULL);
  d = sqrt (d);
  sprintf(buf, "%.35a", d);
 
  return FLOAT(buf);
#else
  long double ld;
  char buf[64];
 
  ld = strtold (f.hex(), NULL);
  ld = sqrtl (ld);
  sprintf(buf, "%.35La", ld);
 
  return FLOAT(buf);
#endif
}
 
template<typename FLOAT>
FLOAT
LOG (FLOAT x)
{
#if 0
  FLOAT zero = long(0);
  FLOAT one = 1;
 
  if (x <= zero)
    return zero / zero;
  if (x == one)
    return zero;
 
  int exp = x.exp() - 1;
  x.ldexp(-exp);
 
  FLOAT xm1 = x - one;
  FLOAT y = xm1;
  long n = 2;
 
  FLOAT sum = xm1;
  while (1)
    {
      y *= xm1;
      FLOAT term = y / FLOAT (n);
      FLOAT next = sum + term;
      if (next == sum)
	break;
      sum = next;
      if (++n == 1000)
	break;
    }
 
  if (exp)
    sum += FLOAT (exp) * FLOAT(".69314718055994530941");
 
  return sum;
#elif defined (NO_LONG_DOUBLE)
  double d;
  char buf[64];
 
  d = strtod (x.hex(), NULL);
  d = log (d);
  sprintf(buf, "%.35a", d);
 
  return FLOAT(buf);
#else
  long double ld;
  char buf[64];
 
  ld = strtold (x.hex(), NULL);
  ld = logl (ld);
  sprintf(buf, "%.35La", ld);
 
  return FLOAT(buf);
#endif
}
 
template<typename FLOAT>
FLOAT
EXP (const FLOAT &x)
{
  /* Cheat.  */
#ifdef NO_LONG_DOUBLE
  double d;
  char buf[64];
 
  d = strtod (x.hex(), NULL);
  d = exp (d);
  sprintf(buf, "%.35a", d);
 
  return FLOAT(buf);
#else
  long double ld;
  char buf[64];
 
  ld = strtold (x.hex(), NULL);
  ld = expl (ld);
  sprintf(buf, "%.35La", ld);
 
  return FLOAT(buf);
#endif
}
 
template<typename FLOAT>
FLOAT
POW (const FLOAT &base, const FLOAT &exp)
{
  /* Cheat.  */
#ifdef NO_LONG_DOUBLE
  double d1, d2;
  char buf[64];
 
  d1 = strtod (base.hex(), NULL);
  d2 = strtod (exp.hex(), NULL);
  d1 = pow (d1, d2);
  sprintf(buf, "%.35a", d1);
 
  return FLOAT(buf);
#else
  long double ld1, ld2;
  char buf[64];
 
  ld1 = strtold (base.hex(), NULL);
  ld2 = strtold (exp.hex(), NULL);
  ld1 = powl (ld1, ld2);
  sprintf(buf, "%.35La", ld1);
 
  return FLOAT(buf);
#endif
}
 
/* ====================================================================== */
/* Real Paranoia begins again here.  We wrap the thing in a template so
   that we can instantiate it for each floating point type we care for.  */
 
int NoTrials = 20;		/*Number of tests for commutativity. */
bool do_pause = false;
 
enum Guard { No, Yes };
enum Rounding { Other, Rounded, Chopped };
enum Class { Failure, Serious, Defect, Flaw };
 
template<typename FLOAT>
struct Paranoia
{
  FLOAT Radix, BInvrse, RadixD2, BMinusU2;
 
  /* Small floating point constants.  */
  FLOAT Zero;
  FLOAT Half;
  FLOAT One;
  FLOAT Two;
  FLOAT Three;
  FLOAT Four;
  FLOAT Five;
  FLOAT Eight;
  FLOAT Nine;
  FLOAT TwentySeven;
  FLOAT ThirtyTwo;
  FLOAT TwoForty;
  FLOAT MinusOne;
  FLOAT OneAndHalf;
 
  /* Declarations of Variables.  */
  int Indx;
  char ch[8];
  FLOAT AInvrse, A1;
  FLOAT C, CInvrse;
  FLOAT D, FourD;
  FLOAT E0, E1, Exp2, E3, MinSqEr;
  FLOAT SqEr, MaxSqEr, E9;
  FLOAT Third;
  FLOAT F6, F9;
  FLOAT H, HInvrse;
  int I;
  FLOAT StickyBit, J;
  FLOAT MyZero;
  FLOAT Precision;
  FLOAT Q, Q9;
  FLOAT R, Random9;
  FLOAT T, Underflow, S;
  FLOAT OneUlp, UfThold, U1, U2;
  FLOAT V, V0, V9;
  FLOAT W;
  FLOAT X, X1, X2, X8, Random1;
  FLOAT Y, Y1, Y2, Random2;
  FLOAT Z, PseudoZero, Z1, Z2, Z9;
  int ErrCnt[4];
  int Milestone;
  int PageNo;
  int M, N, N1;
  Guard GMult, GDiv, GAddSub;
  Rounding RMult, RDiv, RAddSub, RSqrt;
  int Break, Done, NotMonot, Monot, Anomaly, IEEE, SqRWrng, UfNGrad;
 
  /* Computed constants. */
  /*U1  gap below 1.0, i.e, 1.0-U1 is next number below 1.0 */
  /*U2  gap above 1.0, i.e, 1.0+U2 is next number above 1.0 */
 
  int main ();
 
  FLOAT Sign (FLOAT);
  FLOAT Random ();
  void Pause ();
  void BadCond (int, const char *);
  void SqXMinX (int);
  void TstCond (int, int, const char *);
  void notify (const char *);
  void IsYeqX ();
  void NewD ();
  void PrintIfNPositive ();
  void SR3750 ();
  void TstPtUf ();
 
  // Pretend we're bss.
  Paranoia() { memset(this, 0, sizeof (*this)); }
};
 
template<typename FLOAT>
int
Paranoia<FLOAT>::main()
{
  /* First two assignments use integer right-hand sides. */
  Zero = long(0);
  One = long(1);
  Two = long(2);
  Three = long(3);
  Four = long(4);
  Five = long(5);
  Eight = long(8);
  Nine = long(9);
  TwentySeven = long(27);
  ThirtyTwo = long(32);
  TwoForty = long(240);
  MinusOne = long(-1);
  Half = "0x1p-1";
  OneAndHalf = "0x3p-1";
  ErrCnt[Failure] = 0;
  ErrCnt[Serious] = 0;
  ErrCnt[Defect] = 0;
  ErrCnt[Flaw] = 0;
  PageNo = 1;
	/*=============================================*/
  Milestone = 7;
	/*=============================================*/
  printf ("Program is now RUNNING tests on small integers:\n");
 
  TstCond (Failure, (Zero + Zero == Zero), "0+0 != 0");
  TstCond (Failure, (One - One == Zero), "1-1 != 0");
  TstCond (Failure, (One > Zero), "1 <= 0");
  TstCond (Failure, (One + One == Two), "1+1 != 2");
 
  Z = -Zero;
  if (Z != Zero)
    {
      ErrCnt[Failure] = ErrCnt[Failure] + 1;
      printf ("Comparison alleges that -0.0 is Non-zero!\n");
      U2 = "0.001";
      Radix = 1;
      TstPtUf ();
    }
 
  TstCond (Failure, (Three == Two + One), "3 != 2+1");
  TstCond (Failure, (Four == Three + One), "4 != 3+1");
  TstCond (Failure, (Four + Two * (-Two) == Zero), "4 + 2*(-2) != 0");
  TstCond (Failure, (Four - Three - One == Zero), "4-3-1 != 0");
 
  TstCond (Failure, (MinusOne == (Zero - One)), "-1 != 0-1");
  TstCond (Failure, (MinusOne + One == Zero), "-1+1 != 0");
  TstCond (Failure, (One + MinusOne == Zero), "1+(-1) != 0");
  TstCond (Failure, (MinusOne + FABS (One) == Zero), "-1+abs(1) != 0");
  TstCond (Failure, (MinusOne + MinusOne * MinusOne == Zero),
	   "-1+(-1)*(-1) != 0");
 
  TstCond (Failure, Half + MinusOne + Half == Zero, "1/2 + (-1) + 1/2 != 0");
 
	/*=============================================*/
  Milestone = 10;
	/*=============================================*/
 
  TstCond (Failure, (Nine == Three * Three), "9 != 3*3");
  TstCond (Failure, (TwentySeven == Nine * Three), "27 != 9*3");
  TstCond (Failure, (Eight == Four + Four), "8 != 4+4");
  TstCond (Failure, (ThirtyTwo == Eight * Four), "32 != 8*4");
  TstCond (Failure, (ThirtyTwo - TwentySeven - Four - One == Zero),
	   "32-27-4-1 != 0");
 
  TstCond (Failure, Five == Four + One, "5 != 4+1");
  TstCond (Failure, TwoForty == Four * Five * Three * Four, "240 != 4*5*3*4");
  TstCond (Failure, TwoForty / Three - Four * Four * Five == Zero,
	   "240/3 - 4*4*5 != 0");
  TstCond (Failure, TwoForty / Four - Five * Three * Four == Zero,
	   "240/4 - 5*3*4 != 0");
  TstCond (Failure, TwoForty / Five - Four * Three * Four == Zero,
	   "240/5 - 4*3*4 != 0");
 
  if (ErrCnt[Failure] == 0)
    {
      printf ("-1, 0, 1/2, 1, 2, 3, 4, 5, 9, 27, 32 & 240 are O.K.\n");
      printf ("\n");
    }
  printf ("Searching for Radix and Precision.\n");
  W = One;
  do
    {
      W = W + W;
      Y = W + One;
      Z = Y - W;
      Y = Z - One;
    }
  while (MinusOne + FABS (Y) < Zero);
  /*.. now W is just big enough that |((W+1)-W)-1| >= 1 ... */
  Precision = Zero;
  Y = One;
  do
    {
      Radix = W + Y;
      Y = Y + Y;
      Radix = Radix - W;
    }
  while (Radix == Zero);
  if (Radix < Two)
    Radix = One;
  printf ("Radix = %s .\n", Radix.str());
  if (Radix != One)
    {
      W = One;
      do
	{
	  Precision = Precision + One;
	  W = W * Radix;
	  Y = W + One;
	}
      while ((Y - W) == One);
    }
  /*... now W == Radix^Precision is barely too big to satisfy (W+1)-W == 1
     ... */
  U1 = One / W;
  U2 = Radix * U1;
  printf ("Closest relative separation found is U1 = %s .\n\n", U1.str());
  printf ("Recalculating radix and precision\n ");
 
  /*save old values */
  E0 = Radix;
  E1 = U1;
  E9 = U2;
  E3 = Precision;
 
  X = Four / Three;
  Third = X - One;
  F6 = Half - Third;
  X = F6 + F6;
  X = FABS (X - Third);
  if (X < U2)
    X = U2;
 
  /*... now X = (unknown no.) ulps of 1+... */
  do
    {
      U2 = X;
      Y = Half * U2 + ThirtyTwo * U2 * U2;
      Y = One + Y;
      X = Y - One;
    }
  while (!((U2 <= X) || (X <= Zero)));
 
  /*... now U2 == 1 ulp of 1 + ... */
  X = Two / Three;
  F6 = X - Half;
  Third = F6 + F6;
  X = Third - Half;
  X = FABS (X + F6);
  if (X < U1)
    X = U1;
 
  /*... now  X == (unknown no.) ulps of 1 -... */
  do
    {
      U1 = X;
      Y = Half * U1 + ThirtyTwo * U1 * U1;
      Y = Half - Y;
      X = Half + Y;
      Y = Half - X;
      X = Half + Y;
    }
  while (!((U1 <= X) || (X <= Zero)));
  /*... now U1 == 1 ulp of 1 - ... */
  if (U1 == E1)
    printf ("confirms closest relative separation U1 .\n");
  else
    printf ("gets better closest relative separation U1 = %s .\n", U1.str());
  W = One / U1;
  F9 = (Half - U1) + Half;
 
  Radix = FLOOR (FLOAT ("0.01") + U2 / U1);
  if (Radix == E0)
    printf ("Radix confirmed.\n");
  else
    printf ("MYSTERY: recalculated Radix = %s .\n", Radix.str());
  TstCond (Defect, Radix <= Eight + Eight,
	   "Radix is too big: roundoff problems");
  TstCond (Flaw, (Radix == Two) || (Radix == 10)
	   || (Radix == One), "Radix is not as good as 2 or 10");
	/*=============================================*/
  Milestone = 20;
	/*=============================================*/
  TstCond (Failure, F9 - Half < Half,
	   "(1-U1)-1/2 < 1/2 is FALSE, prog. fails?");
  X = F9;
  I = 1;
  Y = X - Half;
  Z = Y - Half;
  TstCond (Failure, (X != One)
	   || (Z == Zero), "Comparison is fuzzy,X=1 but X-1/2-1/2 != 0");
  X = One + U2;
  I = 0;
	/*=============================================*/
  Milestone = 25;
	/*=============================================*/
  /*... BMinusU2 = nextafter(Radix, 0) */
  BMinusU2 = Radix - One;
  BMinusU2 = (BMinusU2 - U2) + One;
  /* Purify Integers */
  if (Radix != One)
    {
      X = -TwoForty * LOG (U1) / LOG (Radix);
      Y = FLOOR (Half + X);
      if (FABS (X - Y) * Four < One)
	X = Y;
      Precision = X / TwoForty;
      Y = FLOOR (Half + Precision);
      if (FABS (Precision - Y) * TwoForty < Half)
	Precision = Y;
    }
  if ((Precision != FLOOR (Precision)) || (Radix == One))
    {
      printf ("Precision cannot be characterized by an Integer number\n");
      printf
	("of significant digits but, by itself, this is a minor flaw.\n");
    }
  if (Radix == One)
    printf
      ("logarithmic encoding has precision characterized solely by U1.\n");
  else
    printf ("The number of significant digits of the Radix is %s .\n",
	    Precision.str());
  TstCond (Serious, U2 * Nine * Nine * TwoForty < One,
	   "Precision worse than 5 decimal figures  ");
	/*=============================================*/
  Milestone = 30;
	/*=============================================*/
  /* Test for extra-precise subexpressions */
  X = FABS (((Four / Three - One) - One / Four) * Three - One / Four);
  do
    {
      Z2 = X;
      X = (One + (Half * Z2 + ThirtyTwo * Z2 * Z2)) - One;
    }
  while (!((Z2 <= X) || (X <= Zero)));
  X = Y = Z = FABS ((Three / Four - Two / Three) * Three - One / Four);
  do
    {
      Z1 = Z;
      Z = (One / Two - ((One / Two - (Half * Z1 + ThirtyTwo * Z1 * Z1))
			+ One / Two)) + One / Two;
    }
  while (!((Z1 <= Z) || (Z <= Zero)));
  do
    {
      do
	{
	  Y1 = Y;
	  Y =
	    (Half - ((Half - (Half * Y1 + ThirtyTwo * Y1 * Y1)) + Half)) +
	    Half;
	}
      while (!((Y1 <= Y) || (Y <= Zero)));
      X1 = X;
      X = ((Half * X1 + ThirtyTwo * X1 * X1) - F9) + F9;
    }
  while (!((X1 <= X) || (X <= Zero)));
  if ((X1 != Y1) || (X1 != Z1))
    {
      BadCond (Serious, "Disagreements among the values X1, Y1, Z1,\n");
      printf ("respectively  %s,  %s,  %s,\n", X1.str(), Y1.str(), Z1.str());
      printf ("are symptoms of inconsistencies introduced\n");
      printf ("by extra-precise evaluation of arithmetic subexpressions.\n");
      notify ("Possibly some part of this");
      if ((X1 == U1) || (Y1 == U1) || (Z1 == U1))
	printf ("That feature is not tested further by this program.\n");
    }
  else
    {
      if ((Z1 != U1) || (Z2 != U2))
	{
	  if ((Z1 >= U1) || (Z2 >= U2))
	    {
	      BadCond (Failure, "");
	      notify ("Precision");
	      printf ("\tU1 = %s, Z1 - U1 = %s\n", U1.str(), (Z1 - U1).str());
	      printf ("\tU2 = %s, Z2 - U2 = %s\n", U2.str(), (Z2 - U2).str());
	    }
	  else
	    {
	      if ((Z1 <= Zero) || (Z2 <= Zero))
		{
		  printf ("Because of unusual Radix = %s", Radix.str());
		  printf (", or exact rational arithmetic a result\n");
		  printf ("Z1 = %s, or Z2 = %s ", Z1.str(), Z2.str());
		  notify ("of an\nextra-precision");
		}
	      if (Z1 != Z2 || Z1 > Zero)
		{
		  X = Z1 / U1;
		  Y = Z2 / U2;
		  if (Y > X)
		    X = Y;
		  Q = -LOG (X);
		  printf ("Some subexpressions appear to be calculated "
			  "extra precisely\n");
		  printf ("with about %s extra B-digits, i.e.\n",
			  (Q / LOG (Radix)).str());
		  printf ("roughly %s extra significant decimals.\n",
			  (Q / LOG (FLOAT (10))).str());
		}
	      printf
		("That feature is not tested further by this program.\n");
	    }
	}
    }
  Pause ();
	/*=============================================*/
  Milestone = 35;
	/*=============================================*/
  if (Radix >= Two)
    {
      X = W / (Radix * Radix);
      Y = X + One;
      Z = Y - X;
      T = Z + U2;
      X = T - Z;
      TstCond (Failure, X == U2,
	       "Subtraction is not normalized X=Y,X+Z != Y+Z!");
      if (X == U2)
	printf ("Subtraction appears to be normalized, as it should be.");
    }
  printf ("\nChecking for guard digit in *, /, and -.\n");
  Y = F9 * One;
  Z = One * F9;
  X = F9 - Half;
  Y = (Y - Half) - X;
  Z = (Z - Half) - X;
  X = One + U2;
  T = X * Radix;
  R = Radix * X;
  X = T - Radix;
  X = X - Radix * U2;
  T = R - Radix;
  T = T - Radix * U2;
  X = X * (Radix - One);
  T = T * (Radix - One);
  if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero))
    GMult = Yes;
  else
    {
      GMult = No;
      TstCond (Serious, false, "* lacks a Guard Digit, so 1*X != X");
    }
  Z = Radix * U2;
  X = One + Z;
  Y = FABS ((X + Z) - X * X) - U2;
  X = One - U2;
  Z = FABS ((X - U2) - X * X) - U1;
  TstCond (Failure, (Y <= Zero)
	   && (Z <= Zero), "* gets too many final digits wrong.\n");
  Y = One - U2;
  X = One + U2;
  Z = One / Y;
  Y = Z - X;
  X = One / Three;
  Z = Three / Nine;
  X = X - Z;
  T = Nine / TwentySeven;
  Z = Z - T;
  TstCond (Defect, X == Zero && Y == Zero && Z == Zero,
	   "Division lacks a Guard Digit, so error can exceed 1 ulp\n"
	   "or  1/3  and  3/9  and  9/27 may disagree");
  Y = F9 / One;
  X = F9 - Half;
  Y = (Y - Half) - X;
  X = One + U2;
  T = X / One;
  X = T - X;
  if ((X == Zero) && (Y == Zero) && (Z == Zero))
    GDiv = Yes;
  else
    {
      GDiv = No;
      TstCond (Serious, false, "Division lacks a Guard Digit, so X/1 != X");
    }
  X = One / (One + U2);
  Y = X - Half - Half;
  TstCond (Serious, Y < Zero, "Computed value of 1/1.000..1 >= 1");
  X = One - U2;
  Y = One + Radix * U2;
  Z = X * Radix;
  T = Y * Radix;
  R = Z / Radix;
  StickyBit = T / Radix;
  X = R - X;
  Y = StickyBit - Y;
  TstCond (Failure, X == Zero && Y == Zero,
	   "* and/or / gets too many last digits wrong");
  Y = One - U1;
  X = One - F9;
  Y = One - Y;
  T = Radix - U2;
  Z = Radix - BMinusU2;
  T = Radix - T;
  if ((X == U1) && (Y == U1) && (Z == U2) && (T == U2))
    GAddSub = Yes;
  else
    {
      GAddSub = No;
      TstCond (Serious, false,
	       "- lacks Guard Digit, so cancellation is obscured");
    }
  if (F9 != One && F9 - One >= Zero)
    {
      BadCond (Serious, "comparison alleges  (1-U1) < 1  although\n");
      printf ("  subtraction yields  (1-U1) - 1 = 0 , thereby vitiating\n");
      printf ("  such precautions against division by zero as\n");
      printf ("  ...  if (X == 1.0) {.....} else {.../(X-1.0)...}\n");
    }
  if (GMult == Yes && GDiv == Yes && GAddSub == Yes)
    printf
      ("     *, /, and - appear to have guard digits, as they should.\n");
	/*=============================================*/
  Milestone = 40;
	/*=============================================*/
  Pause ();
  printf ("Checking rounding on multiply, divide and add/subtract.\n");
  RMult = Other;
  RDiv = Other;
  RAddSub = Other;
  RadixD2 = Radix / Two;
  A1 = Two;
  Done = false;
  do
    {
      AInvrse = Radix;
      do
	{
	  X = AInvrse;
	  AInvrse = AInvrse / A1;
	}
      while (!(FLOOR (AInvrse) != AInvrse));
      Done = (X == One) || (A1 > Three);
      if (!Done)
	A1 = Nine + One;
    }
  while (!(Done));
  if (X == One)
    A1 = Radix;
  AInvrse = One / A1;
  X = A1;
  Y = AInvrse;
  Done = false;
  do
    {
      Z = X * Y - Half;
      TstCond (Failure, Z == Half, "X * (1/X) differs from 1");
      Done = X == Radix;
      X = Radix;
      Y = One / X;
    }
  while (!(Done));
  Y2 = One + U2;
  Y1 = One - U2;
  X = OneAndHalf - U2;
  Y = OneAndHalf + U2;
  Z = (X - U2) * Y2;
  T = Y * Y1;
  Z = Z - X;
  T = T - X;
  X = X * Y2;
  Y = (Y + U2) * Y1;
  X = X - OneAndHalf;
  Y = Y - OneAndHalf;
  if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T <= Zero))
    {
      X = (OneAndHalf + U2) * Y2;
      Y = OneAndHalf - U2 - U2;
      Z = OneAndHalf + U2 + U2;
      T = (OneAndHalf - U2) * Y1;
      X = X - (Z + U2);
      StickyBit = Y * Y1;
      S = Z * Y2;
      T = T - Y;
      Y = (U2 - Y) + StickyBit;
      Z = S - (Z + U2 + U2);
      StickyBit = (Y2 + U2) * Y1;
      Y1 = Y2 * Y1;
      StickyBit = StickyBit - Y2;
      Y1 = Y1 - Half;
      if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero)
	  && (StickyBit == Zero) && (Y1 == Half))
	{
	  RMult = Rounded;
	  printf ("Multiplication appears to round correctly.\n");
	}
      else if ((X + U2 == Zero) && (Y < Zero) && (Z + U2 == Zero)
	       && (T < Zero) && (StickyBit + U2 == Zero) && (Y1 < Half))
	{
	  RMult = Chopped;
	  printf ("Multiplication appears to chop.\n");
	}
      else
	printf ("* is neither chopped nor correctly rounded.\n");
      if ((RMult == Rounded) && (GMult == No))
	notify ("Multiplication");
    }
  else
    printf ("* is neither chopped nor correctly rounded.\n");
	/*=============================================*/
  Milestone = 45;
	/*=============================================*/
  Y2 = One + U2;
  Y1 = One - U2;
  Z = OneAndHalf + U2 + U2;
  X = Z / Y2;
  T = OneAndHalf - U2 - U2;
  Y = (T - U2) / Y1;
  Z = (Z + U2) / Y2;
  X = X - OneAndHalf;
  Y = Y - T;
  T = T / Y1;
  Z = Z - (OneAndHalf + U2);
  T = (U2 - OneAndHalf) + T;
  if (!((X > Zero) || (Y > Zero) || (Z > Zero) || (T > Zero)))
    {
      X = OneAndHalf / Y2;
      Y = OneAndHalf - U2;
      Z = OneAndHalf + U2;
      X = X - Y;
      T = OneAndHalf / Y1;
      Y = Y / Y1;
      T = T - (Z + U2);
      Y = Y - Z;
      Z = Z / Y2;
      Y1 = (Y2 + U2) / Y2;
      Z = Z - OneAndHalf;
      Y2 = Y1 - Y2;
      Y1 = (F9 - U1) / F9;
      if ((X == Zero) && (Y == Zero) && (Z == Zero) && (T == Zero)
	  && (Y2 == Zero) && (Y2 == Zero) && (Y1 - Half == F9 - Half))
	{
	  RDiv = Rounded;
	  printf ("Division appears to round correctly.\n");
	  if (GDiv == No)
	    notify ("Division");
	}
      else if ((X < Zero) && (Y < Zero) && (Z < Zero) && (T < Zero)
	       && (Y2 < Zero) && (Y1 - Half < F9 - Half))
	{
	  RDiv = Chopped;
	  printf ("Division appears to chop.\n");
	}
    }
  if (RDiv == Other)
    printf ("/ is neither chopped nor correctly rounded.\n");
  BInvrse = One / Radix;
  TstCond (Failure, (BInvrse * Radix - Half == Half),
	   "Radix * ( 1 / Radix ) differs from 1");
	/*=============================================*/
  Milestone = 50;
	/*=============================================*/
  TstCond (Failure, ((F9 + U1) - Half == Half)
	   && ((BMinusU2 + U2) - One == Radix - One),
	   "Incomplete carry-propagation in Addition");
  X = One - U1 * U1;
  Y = One + U2 * (One - U2);
  Z = F9 - Half;
  X = (X - Half) - Z;
  Y = Y - One;
  if ((X == Zero) && (Y == Zero))
    {
      RAddSub = Chopped;
      printf ("Add/Subtract appears to be chopped.\n");
    }
  if (GAddSub == Yes)
    {
      X = (Half + U2) * U2;
      Y = (Half - U2) * U2;
      X = One + X;
      Y = One + Y;
      X = (One + U2) - X;
      Y = One - Y;
      if ((X == Zero) && (Y == Zero))
	{
	  X = (Half + U2) * U1;
	  Y = (Half - U2) * U1;
	  X = One - X;
	  Y = One - Y;
	  X = F9 - X;
	  Y = One - Y;
	  if ((X == Zero) && (Y == Zero))
	    {
	      RAddSub = Rounded;
	      printf ("Addition/Subtraction appears to round correctly.\n");
	      if (GAddSub == No)
		notify ("Add/Subtract");
	    }
	  else
	    printf ("Addition/Subtraction neither rounds nor chops.\n");
	}
      else
	printf ("Addition/Subtraction neither rounds nor chops.\n");
    }
  else
    printf ("Addition/Subtraction neither rounds nor chops.\n");
  S = One;
  X = One + Half * (One + Half);
  Y = (One + U2) * Half;
  Z = X - Y;
  T = Y - X;
  StickyBit = Z + T;
  if (StickyBit != Zero)
    {
      S = Zero;
      BadCond (Flaw, "(X - Y) + (Y - X) is non zero!\n");
    }
  StickyBit = Zero;
  if ((GMult == Yes) && (GDiv == Yes) && (GAddSub == Yes)
      && (RMult == Rounded) && (RDiv == Rounded)
      && (RAddSub == Rounded) && (FLOOR (RadixD2) == RadixD2))
    {
      printf ("Checking for sticky bit.\n");
      X = (Half + U1) * U2;
      Y = Half * U2;
      Z = One + Y;
      T = One + X;
      if ((Z - One <= Zero) && (T - One >= U2))
	{
	  Z = T + Y;
	  Y = Z - X;
	  if ((Z - T >= U2) && (Y - T == Zero))
	    {
	      X = (Half + U1) * U1;
	      Y = Half * U1;
	      Z = One - Y;
	      T = One - X;
	      if ((Z - One == Zero) && (T - F9 == Zero))
		{
		  Z = (Half - U1) * U1;
		  T = F9 - Z;
		  Q = F9 - Y;
		  if ((T - F9 == Zero) && (F9 - U1 - Q == Zero))
		    {
		      Z = (One + U2) * OneAndHalf;
		      T = (OneAndHalf + U2) - Z + U2;
		      X = One + Half / Radix;
		      Y = One + Radix * U2;
		      Z = X * Y;
		      if (T == Zero && X + Radix * U2 - Z == Zero)
			{
			  if (Radix != Two)
			    {
			      X = Two + U2;
			      Y = X / Two;
			      if ((Y - One == Zero))
				StickyBit = S;
			    }
			  else
			    StickyBit = S;
			}
		    }
		}
	    }
	}
    }
  if (StickyBit == One)
    printf ("Sticky bit apparently used correctly.\n");
  else
    printf ("Sticky bit used incorrectly or not at all.\n");
  TstCond (Flaw, !(GMult == No || GDiv == No || GAddSub == No ||
		   RMult == Other || RDiv == Other || RAddSub == Other),
	   "lack(s) of guard digits or failure(s) to correctly round or chop\n\
(noted above) count as one flaw in the final tally below");
	/*=============================================*/
  Milestone = 60;
	/*=============================================*/
  printf ("\n");
  printf ("Does Multiplication commute?  ");
  printf ("Testing on %d random pairs.\n", NoTrials);
  Random9 = SQRT (FLOAT (3));
  Random1 = Third;
  I = 1;
  do
    {
      X = Random ();
      Y = Random ();
      Z9 = Y * X;
      Z = X * Y;
      Z9 = Z - Z9;
      I = I + 1;
    }
  while (!((I > NoTrials) || (Z9 != Zero)));
  if (I == NoTrials)
    {
      Random1 = One + Half / Three;
      Random2 = (U2 + U1) + One;
      Z = Random1 * Random2;
      Y = Random2 * Random1;
      Z9 = (One + Half / Three) * ((U2 + U1) + One) - (One + Half /
						       Three) * ((U2 + U1) +
								 One);
    }
  if (!((I == NoTrials) || (Z9 == Zero)))
    BadCond (Defect, "X * Y == Y * X trial fails.\n");
  else
    printf ("     No failures found in %d integer pairs.\n", NoTrials);
	/*=============================================*/
  Milestone = 70;
	/*=============================================*/
  printf ("\nRunning test of square root(x).\n");
  TstCond (Failure, (Zero == SQRT (Zero))
	   && (-Zero == SQRT (-Zero))
	   && (One == SQRT (One)), "Square root of 0.0, -0.0 or 1.0 wrong");
  MinSqEr = Zero;
  MaxSqEr = Zero;
  J = Zero;
  X = Radix;
  OneUlp = U2;
  SqXMinX (Serious);
  X = BInvrse;
  OneUlp = BInvrse * U1;
  SqXMinX (Serious);
  X = U1;
  OneUlp = U1 * U1;
  SqXMinX (Serious);
  if (J != Zero)
    Pause ();
  printf ("Testing if sqrt(X * X) == X for %d Integers X.\n", NoTrials);
  J = Zero;
  X = Two;
  Y = Radix;
  if ((Radix != One))
    do
      {
	X = Y;
	Y = Radix * Y;
      }
    while (!((Y - X >= NoTrials)));
  OneUlp = X * U2;
  I = 1;
  while (I <= NoTrials)
    {
      X = X + One;
      SqXMinX (Defect);
      if (J > Zero)
	break;
      I = I + 1;
    }
  printf ("Test for sqrt monotonicity.\n");
  I = -1;
  X = BMinusU2;
  Y = Radix;
  Z = Radix + Radix * U2;
  NotMonot = false;
  Monot = false;
  while (!(NotMonot || Monot))
    {
      I = I + 1;
      X = SQRT (X);
      Q = SQRT (Y);
      Z = SQRT (Z);
      if ((X > Q) || (Q > Z))
	NotMonot = true;
      else
	{
	  Q = FLOOR (Q + Half);
	  if (!(I > 0 || Radix == Q * Q))
	    Monot = true;
	  else if (I > 0)
	    {
	      if (I > 1)
		Monot = true;
	      else
		{
		  Y = Y * BInvrse;
		  X = Y - U1;
		  Z = Y + U1;
		}
	    }
	  else
	    {
	      Y = Q;
	      X = Y - U2;
	      Z = Y + U2;
	    }
	}
    }
  if (Monot)
    printf ("sqrt has passed a test for Monotonicity.\n");
  else
    {
      BadCond (Defect, "");
      printf ("sqrt(X) is non-monotonic for X near %s .\n", Y.str());
    }
	/*=============================================*/
  Milestone = 110;
	/*=============================================*/
  printf ("Seeking Underflow thresholds UfThold and E0.\n");
  D = U1;
  if (Precision != FLOOR (Precision))
    {
      D = BInvrse;
      X = Precision;
      do
	{
	  D = D * BInvrse;
	  X = X - One;
	}
      while (X > Zero);
    }
  Y = One;
  Z = D;
  /* ... D is power of 1/Radix < 1. */
  do
    {
      C = Y;
      Y = Z;
      Z = Y * Y;
    }
  while ((Y > Z) && (Z + Z > Z));
  Y = C;
  Z = Y * D;
  do
    {
      C = Y;
      Y = Z;
      Z = Y * D;
    }
  while ((Y > Z) && (Z + Z > Z));
  if (Radix < Two)
    HInvrse = Two;
  else
    HInvrse = Radix;
  H = One / HInvrse;
  /* ... 1/HInvrse == H == Min(1/Radix, 1/2) */
  CInvrse = One / C;
  E0 = C;
  Z = E0 * H;
  /* ...1/Radix^(BIG Integer) << 1 << CInvrse == 1/C */
  do
    {
      Y = E0;
      E0 = Z;
      Z = E0 * H;
    }
  while ((E0 > Z) && (Z + Z > Z));
  UfThold = E0;
  E1 = Zero;
  Q = Zero;
  E9 = U2;
  S = One + E9;
  D = C * S;
  if (D <= C)
    {
      E9 = Radix * U2;
      S = One + E9;
      D = C * S;
      if (D <= C)
	{
	  BadCond (Failure,
		   "multiplication gets too many last digits wrong.\n");
	  Underflow = E0;
	  Y1 = Zero;
	  PseudoZero = Z;
	  Pause ();
	}
    }
  else
    {
      Underflow = D;
      PseudoZero = Underflow * H;
      UfThold = Zero;
      do
	{
	  Y1 = Underflow;
	  Underflow = PseudoZero;
	  if (E1 + E1 <= E1)
	    {
	      Y2 = Underflow * HInvrse;
	      E1 = FABS (Y1 - Y2);
	      Q = Y1;
	      if ((UfThold == Zero) && (Y1 != Y2))
		UfThold = Y1;
	    }
	  PseudoZero = PseudoZero * H;
	}
      while ((Underflow > PseudoZero)
	     && (PseudoZero + PseudoZero > PseudoZero));
    }
  /* Comment line 4530 .. 4560 */
  if (PseudoZero != Zero)
    {
      printf ("\n");
      Z = PseudoZero;
      /* ... Test PseudoZero for "phoney- zero" violates */
      /* ... PseudoZero < Underflow or PseudoZero < PseudoZero + PseudoZero
         ... */
      if (PseudoZero <= Zero)
	{
	  BadCond (Failure, "Positive expressions can underflow to an\n");
	  printf ("allegedly negative value\n");
	  printf ("PseudoZero that prints out as: %s .\n", PseudoZero.str());
	  X = -PseudoZero;
	  if (X <= Zero)
	    {
	      printf ("But -PseudoZero, which should be\n");
	      printf ("positive, isn't; it prints out as  %s .\n", X.str());
	    }
	}
      else
	{
	  BadCond (Flaw, "Underflow can stick at an allegedly positive\n");
	  printf ("value PseudoZero that prints out as %s .\n",
		  PseudoZero.str());
	}
      TstPtUf ();
    }
	/*=============================================*/
  Milestone = 120;
	/*=============================================*/
  if (CInvrse * Y > CInvrse * Y1)
    {
      S = H * S;
      E0 = Underflow;
    }
  if (!((E1 == Zero) || (E1 == E0)))
    {
      BadCond (Defect, "");
      if (E1 < E0)
	{
	  printf ("Products underflow at a higher");
	  printf (" threshold than differences.\n");
	  if (PseudoZero == Zero)
	    E0 = E1;
	}
      else
	{
	  printf ("Difference underflows at a higher");
	  printf (" threshold than products.\n");
	}
    }
  printf ("Smallest strictly positive number found is E0 = %s .\n", E0.str());
  Z = E0;
  TstPtUf ();
  Underflow = E0;
  if (N == 1)
    Underflow = Y;
  I = 4;
  if (E1 == Zero)
    I = 3;
  if (UfThold == Zero)
    I = I - 2;
  UfNGrad = true;
  switch (I)
    {
    case 1:
      UfThold = Underflow;
      if ((CInvrse * Q) != ((CInvrse * Y) * S))
	{
	  UfThold = Y;
	  BadCond (Failure, "Either accuracy deteriorates as numbers\n");
	  printf ("approach a threshold = %s\n", UfThold.str());
	  printf (" coming down from %s\n", C.str());
	  printf
	    (" or else multiplication gets too many last digits wrong.\n");
	}
      Pause ();
      break;
 
    case 2:
      BadCond (Failure,
	       "Underflow confuses Comparison, which alleges that\n");
      printf ("Q == Y while denying that |Q - Y| == 0; these values\n");
      printf ("print out as Q = %s, Y = %s .\n", Q.str(), Y2.str());
      printf ("|Q - Y| = %s .\n", FABS (Q - Y2).str());
      UfThold = Q;
      break;
 
    case 3:
      X = X;
      break;
 
    case 4:
      if ((Q == UfThold) && (E1 == E0) && (FABS (UfThold - E1 / E9) <= E1))
	{
	  UfNGrad = false;
	  printf ("Underflow is gradual; it incurs Absolute Error =\n");
	  printf ("(roundoff in UfThold) < E0.\n");
	  Y = E0 * CInvrse;
	  Y = Y * (OneAndHalf + U2);
	  X = CInvrse * (One + U2);
	  Y = Y / X;
	  IEEE = (Y == E0);
	}
    }
  if (UfNGrad)
    {
      printf ("\n");
      if (setjmp (ovfl_buf))
	{
	  printf ("Underflow / UfThold failed!\n");
	  R = H + H;
	}
      else
	R = SQRT (Underflow / UfThold);
      if (R <= H)
	{
	  Z = R * UfThold;
	  X = Z * (One + R * H * (One + H));
	}
      else
	{
	  Z = UfThold;
	  X = Z * (One + H * H * (One + H));
	}
      if (!((X == Z) || (X - Z != Zero)))
	{
	  BadCond (Flaw, "");
	  printf ("X = %s\n\tis not equal to Z = %s .\n", X.str(), Z.str());
	  Z9 = X - Z;
	  printf ("yet X - Z yields %s .\n", Z9.str());
	  printf ("    Should this NOT signal Underflow, ");
	  printf ("this is a SERIOUS DEFECT\nthat causes ");
	  printf ("confusion when innocent statements like\n");;
	  printf ("    if (X == Z)  ...  else");
	  printf ("  ... (f(X) - f(Z)) / (X - Z) ...\n");
	  printf ("encounter Division by Zero although actually\n");
	  if (setjmp (ovfl_buf))
	    printf ("X / Z fails!\n");
	  else
	    printf ("X / Z = 1 + %s .\n", ((X / Z - Half) - Half).str());
	}
    }
  printf ("The Underflow threshold is %s, below which\n", UfThold.str());
  printf ("calculation may suffer larger Relative error than ");
  printf ("merely roundoff.\n");
  Y2 = U1 * U1;
  Y = Y2 * Y2;
  Y2 = Y * U1;
  if (Y2 <= UfThold)
    {
      if (Y > E0)
	{
	  BadCond (Defect, "");
	  I = 5;
	}
      else
	{
	  BadCond (Serious, "");
	  I = 4;
	}
      printf ("Range is too narrow; U1^%d Underflows.\n", I);
    }
	/*=============================================*/
  Milestone = 130;
	/*=============================================*/
  Y = -FLOOR (Half - TwoForty * LOG (UfThold) / LOG (HInvrse)) / TwoForty;
  Y2 = Y + Y;
  printf ("Since underflow occurs below the threshold\n");
  printf ("UfThold = (%s) ^ (%s)\nonly underflow ", HInvrse.str(), Y.str());
  printf ("should afflict the expression\n\t(%s) ^ (%s);\n",
	  HInvrse.str(), Y2.str());
  printf ("actually calculating yields:");
  if (setjmp (ovfl_buf))
    {
      BadCond (Serious, "trap on underflow.\n");
    }
  else
    {
      V9 = POW (HInvrse, Y2);
      printf (" %s .\n", V9.str());
      if (!((V9 >= Zero) && (V9 <= (Radix + Radix + E9) * UfThold)))
	{
	  BadCond (Serious, "this is not between 0 and underflow\n");
	  printf ("   threshold = %s .\n", UfThold.str());
	}
      else if (!(V9 > UfThold * (One + E9)))
	printf ("This computed value is O.K.\n");
      else
	{
	  BadCond (Defect, "this is not between 0 and underflow\n");
	  printf ("   threshold = %s .\n", UfThold.str());
	}
    }
	/*=============================================*/
  Milestone = 160;
	/*=============================================*/
  Pause ();
  printf ("Searching for Overflow threshold:\n");
  printf ("This may generate an error.\n");
  Y = -CInvrse;
  V9 = HInvrse * Y;
  if (setjmp (ovfl_buf))
    {
      I = 0;
      V9 = Y;
      goto overflow;
    }
  do
    {
      V = Y;
      Y = V9;
      V9 = HInvrse * Y;
    }
  while (V9 < Y);
  I = 1;
overflow:
  Z = V9;
  printf ("Can `Z = -Y' overflow?\n");
  printf ("Trying it on Y = %s .\n", Y.str());
  V9 = -Y;
  V0 = V9;
  if (V - Y == V + V0)
    printf ("Seems O.K.\n");
  else
    {
      printf ("finds a ");
      BadCond (Flaw, "-(-Y) differs from Y.\n");
    }
  if (Z != Y)
    {
      BadCond (Serious, "");
      printf ("overflow past %s\n\tshrinks to %s .\n", Y.str(), Z.str());
    }
  if (I)
    {
      Y = V * (HInvrse * U2 - HInvrse);
      Z = Y + ((One - HInvrse) * U2) * V;
      if (Z < V0)
	Y = Z;
      if (Y < V0)
	V = Y;
      if (V0 - V < V0)
	V = V0;
    }
  else
    {
      V = Y * (HInvrse * U2 - HInvrse);
      V = V + ((One - HInvrse) * U2) * Y;
    }
  printf ("Overflow threshold is V  = %s .\n", V.str());
  if (I)
    printf ("Overflow saturates at V0 = %s .\n", V0.str());
  else
    printf ("There is no saturation value because "
	    "the system traps on overflow.\n");
  V9 = V * One;
  printf ("No Overflow should be signaled for V * 1 = %s\n", V9.str());
  V9 = V / One;
  printf ("                           nor for V / 1 = %s.\n", V9.str());
  printf ("Any overflow signal separating this * from the one\n");
  printf ("above is a DEFECT.\n");
	/*=============================================*/
  Milestone = 170;
	/*=============================================*/
  if (!(-V < V && -V0 < V0 && -UfThold < V && UfThold < V))
    {
      BadCond (Failure, "Comparisons involving ");
      printf ("+-%s, +-%s\nand +-%s are confused by Overflow.",
	      V.str(), V0.str(), UfThold.str());
    }
	/*=============================================*/
  Milestone = 175;
	/*=============================================*/
  printf ("\n");
  for (Indx = 1; Indx <= 3; ++Indx)
    {
      switch (Indx)
	{
	case 1:
	  Z = UfThold;
	  break;
	case 2:
	  Z = E0;
	  break;
	case 3:
	  Z = PseudoZero;
	  break;
	}
      if (Z != Zero)
	{
	  V9 = SQRT (Z);
	  Y = V9 * V9;
	  if (Y / (One - Radix * E9) < Z || Y > (One + Radix * E9) * Z)
	    {			/* dgh: + E9 --> * E9 */
	      if (V9 > U1)
		BadCond (Serious, "");
	      else
		BadCond (Defect, "");
	      printf ("Comparison alleges that what prints as Z = %s\n",
		      Z.str());
	      printf (" is too far from sqrt(Z) ^ 2 = %s .\n", Y.str());
	    }
	}
    }
	/*=============================================*/
  Milestone = 180;
	/*=============================================*/
  for (Indx = 1; Indx <= 2; ++Indx)
    {
      if (Indx == 1)
	Z = V;
      else
	Z = V0;
      V9 = SQRT (Z);
      X = (One - Radix * E9) * V9;
      V9 = V9 * X;
      if (((V9 < (One - Two * Radix * E9) * Z) || (V9 > Z)))
	{
	  Y = V9;
	  if (X < W)
	    BadCond (Serious, "");
	  else
	    BadCond (Defect, "");
	  printf ("Comparison alleges that Z = %s\n", Z.str());
	  printf (" is too far from sqrt(Z) ^ 2 (%s) .\n", Y.str());
	}
    }
	/*=============================================*/
  Milestone = 190;
	/*=============================================*/
  Pause ();
  X = UfThold * V;
  Y = Radix * Radix;
  if (X * Y < One || X > Y)
    {
      if (X * Y < U1 || X > Y / U1)
	BadCond (Defect, "Badly");
      else
	BadCond (Flaw, "");
 
      printf (" unbalanced range; UfThold * V = %s\n\t%s\n",
	      X.str(), "is too far from 1.\n");
    }
	/*=============================================*/
  Milestone = 200;
	/*=============================================*/
  for (Indx = 1; Indx <= 5; ++Indx)
    {
      X = F9;
      switch (Indx)
	{
	case 2:
	  X = One + U2;
	  break;
	case 3:
	  X = V;
	  break;
	case 4:
	  X = UfThold;
	  break;
	case 5:
	  X = Radix;
	}
      Y = X;
      if (setjmp (ovfl_buf))
	printf ("  X / X  traps when X = %s\n", X.str());
      else
	{
	  V9 = (Y / X - Half) - Half;
	  if (V9 == Zero)
	    continue;
	  if (V9 == -U1 && Indx < 5)
	    BadCond (Flaw, "");
	  else
	    BadCond (Serious, "");
	  printf ("  X / X differs from 1 when X = %s\n", X.str());
	  printf ("  instead, X / X - 1/2 - 1/2 = %s .\n", V9.str());
	}
    }
	/*=============================================*/
  Milestone = 210;
	/*=============================================*/
  MyZero = Zero;
  printf ("\n");
  printf ("What message and/or values does Division by Zero produce?\n");
  printf ("    Trying to compute 1 / 0 produces ...");
  if (!setjmp (ovfl_buf))
    printf ("  %s .\n", (One / MyZero).str());
  printf ("\n    Trying to compute 0 / 0 produces ...");
  if (!setjmp (ovfl_buf))
    printf ("  %s .\n", (Zero / MyZero).str());
	/*=============================================*/
  Milestone = 220;
	/*=============================================*/
  Pause ();
  printf ("\n");
  {
    static const char *msg[] = {
      "FAILUREs  encountered =",
      "SERIOUS DEFECTs  discovered =",
      "DEFECTs  discovered =",
      "FLAWs  discovered ="
    };
    int i;
    for (i = 0; i < 4; i++)
      if (ErrCnt[i])
	printf ("The number of  %-29s %d.\n", msg[i], ErrCnt[i]);
  }
  printf ("\n");
  if ((ErrCnt[Failure] + ErrCnt[Serious] + ErrCnt[Defect] + ErrCnt[Flaw]) > 0)
    {
      if ((ErrCnt[Failure] + ErrCnt[Serious] + ErrCnt[Defect] == 0)
	  && (ErrCnt[Flaw] > 0))
	{
	  printf ("The arithmetic diagnosed seems ");
	  printf ("Satisfactory though flawed.\n");
	}
      if ((ErrCnt[Failure] + ErrCnt[Serious] == 0) && (ErrCnt[Defect] > 0))
	{
	  printf ("The arithmetic diagnosed may be Acceptable\n");
	  printf ("despite inconvenient Defects.\n");
	}
      if ((ErrCnt[Failure] + ErrCnt[Serious]) > 0)
	{
	  printf ("The arithmetic diagnosed has ");
	  printf ("unacceptable Serious Defects.\n");
	}
      if (ErrCnt[Failure] > 0)
	{
	  printf ("Potentially fatal FAILURE may have spoiled this");
	  printf (" program's subsequent diagnoses.\n");
	}
    }
  else
    {
      printf ("No failures, defects nor flaws have been discovered.\n");
      if (!((RMult == Rounded) && (RDiv == Rounded)
	    && (RAddSub == Rounded) && (RSqrt == Rounded)))
	printf ("The arithmetic diagnosed seems Satisfactory.\n");
      else
	{
	  if (StickyBit >= One &&
	      (Radix - Two) * (Radix - Nine - One) == Zero)
	    {
	      printf ("Rounding appears to conform to ");
	      printf ("the proposed IEEE standard P");
	      if ((Radix == Two) &&
		  ((Precision - Four * Three * Two) *
		   (Precision - TwentySeven - TwentySeven + One) == Zero))
		printf ("754");
	      else
		printf ("854");
	      if (IEEE)
		printf (".\n");
	      else
		{
		  printf (",\nexcept for possibly Double Rounding");
		  printf (" during Gradual Underflow.\n");
		}
	    }
	  printf ("The arithmetic diagnosed appears to be Excellent!\n");
	}
    }
  printf ("END OF TEST.\n");
  return 0;
}
 
template<typename FLOAT>
FLOAT
Paranoia<FLOAT>::Sign (FLOAT X)
{
  return X >= FLOAT (long (0)) ? 1 : -1;
}
 
template<typename FLOAT>
void
Paranoia<FLOAT>::Pause ()
{
  if (do_pause)
    {
      fputs ("Press return...", stdout);
      fflush (stdout);
      getchar();
    }
  printf ("\nDiagnosis resumes after milestone Number %d", Milestone);
  printf ("          Page: %d\n\n", PageNo);
  ++Milestone;
  ++PageNo;
}
 
template<typename FLOAT>
void
Paranoia<FLOAT>::TstCond (int K, int Valid, const char *T)
{
  if (!Valid)
    {
      BadCond (K, T);
      printf (".\n");
    }
}
 
template<typename FLOAT>
void
Paranoia<FLOAT>::BadCond (int K, const char *T)
{
  static const char *msg[] = { "FAILURE", "SERIOUS DEFECT", "DEFECT", "FLAW" };
 
  ErrCnt[K] = ErrCnt[K] + 1;
  printf ("%s:  %s", msg[K], T);
}
 
/* Random computes
     X = (Random1 + Random9)^5
     Random1 = X - FLOOR(X) + 0.000005 * X;
   and returns the new value of Random1.  */
 
template<typename FLOAT>
FLOAT
Paranoia<FLOAT>::Random ()
{
  FLOAT X, Y;
 
  X = Random1 + Random9;
  Y = X * X;
  Y = Y * Y;
  X = X * Y;
  Y = X - FLOOR (X);
  Random1 = Y + X * FLOAT ("0.000005");
  return (Random1);
}
 
template<typename FLOAT>
void
Paranoia<FLOAT>::SqXMinX (int ErrKind)
{
  FLOAT XA, XB;
 
  XB = X * BInvrse;
  XA = X - XB;
  SqEr = ((SQRT (X * X) - XB) - XA) / OneUlp;
  if (SqEr != Zero)
    {
      if (SqEr < MinSqEr)
	MinSqEr = SqEr;
      if (SqEr > MaxSqEr)
	MaxSqEr = SqEr;
      J = J + 1;
      BadCond (ErrKind, "\n");
      printf ("sqrt(%s) - %s  = %s\n", (X * X).str(), X.str(),
	      (OneUlp * SqEr).str());
      printf ("\tinstead of correct value 0 .\n");
    }
}
 
template<typename FLOAT>
void
Paranoia<FLOAT>::NewD ()
{
  X = Z1 * Q;
  X = FLOOR (Half - X / Radix) * Radix + X;
  Q = (Q - X * Z) / Radix + X * X * (D / Radix);
  Z = Z - Two * X * D;
  if (Z <= Zero)
    {
      Z = -Z;
      Z1 = -Z1;
    }
  D = Radix * D;
}
 
template<typename FLOAT>
void
Paranoia<FLOAT>::SR3750 ()
{
  if (!((X - Radix < Z2 - Radix) || (X - Z2 > W - Z2)))
    {
      I = I + 1;
      X2 = SQRT (X * D);
      Y2 = (X2 - Z2) - (Y - Z2);
      X2 = X8 / (Y - Half);
      X2 = X2 - Half * X2 * X2;
      SqEr = (Y2 + Half) + (Half - X2);
      if (SqEr < MinSqEr)
	MinSqEr = SqEr;
      SqEr = Y2 - X2;
      if (SqEr > MaxSqEr)
	MaxSqEr = SqEr;
    }
}
 
template<typename FLOAT>
void
Paranoia<FLOAT>::IsYeqX ()
{
  if (Y != X)
    {
      if (N <= 0)
	{
	  if (Z == Zero && Q <= Zero)
	    printf ("WARNING:  computing\n");
	  else
	    BadCond (Defect, "computing\n");
	  printf ("\t(%s) ^ (%s)\n", Z.str(), Q.str());
	  printf ("\tyielded %s;\n", Y.str());
	  printf ("\twhich compared unequal to correct %s ;\n", X.str());
	  printf ("\t\tthey differ by %s .\n", (Y - X).str());
	}
      N = N + 1;		/* ... count discrepancies. */
    }
}
 
template<typename FLOAT>
void
Paranoia<FLOAT>::PrintIfNPositive ()
{
  if (N > 0)
    printf ("Similar discrepancies have occurred %d times.\n", N);
}
 
template<typename FLOAT>
void
Paranoia<FLOAT>::TstPtUf ()
{
  N = 0;
  if (Z != Zero)
    {
      printf ("Since comparison denies Z = 0, evaluating ");
      printf ("(Z + Z) / Z should be safe.\n");
      if (setjmp (ovfl_buf))
	goto very_serious;
      Q9 = (Z + Z) / Z;
      printf ("What the machine gets for (Z + Z) / Z is %s .\n", Q9.str());
      if (FABS (Q9 - Two) < Radix * U2)
	{
	  printf ("This is O.K., provided Over/Underflow");
	  printf (" has NOT just been signaled.\n");
	}
      else
	{
	  if ((Q9 < One) || (Q9 > Two))
	    {
	    very_serious:
	      N = 1;
	      ErrCnt[Serious] = ErrCnt[Serious] + 1;
	      printf ("This is a VERY SERIOUS DEFECT!\n");
	    }
	  else
	    {
	      N = 1;
	      ErrCnt[Defect] = ErrCnt[Defect] + 1;
	      printf ("This is a DEFECT!\n");
	    }
	}
      V9 = Z * One;
      Random1 = V9;
      V9 = One * Z;
      Random2 = V9;
      V9 = Z / One;
      if ((Z == Random1) && (Z == Random2) && (Z == V9))
	{
	  if (N > 0)
	    Pause ();
	}
      else
	{
	  N = 1;
	  BadCond (Defect, "What prints as Z = ");
	  printf ("%s\n\tcompares different from  ", Z.str());
	  if (Z != Random1)
	    printf ("Z * 1 = %s ", Random1.str());
	  if (!((Z == Random2) || (Random2 == Random1)))
	    printf ("1 * Z == %s\n", Random2.str());
	  if (!(Z == V9))
	    printf ("Z / 1 = %s\n", V9.str());
	  if (Random2 != Random1)
	    {
	      ErrCnt[Defect] = ErrCnt[Defect] + 1;
	      BadCond (Defect, "Multiplication does not commute!\n");
	      printf ("\tComparison alleges that 1 * Z = %s\n", Random2.str());
	      printf ("\tdiffers from Z * 1 = %s\n", Random1.str());
	    }
	  Pause ();
	}
    }
}
 
template<typename FLOAT>
void
Paranoia<FLOAT>::notify (const char *s)
{
  printf ("%s test appears to be inconsistent...\n", s);
  printf ("   PLEASE NOTIFY KARPINKSI!\n");
}
 
/* ====================================================================== */
 
int main(int ac, char **av)
{
  setbuf(stdout, NULL);
  setbuf(stderr, NULL);
 
  while (1)
    switch (getopt (ac, av, "pvg:fdl"))
      {
      case -1:
	return 0;
      case 'p':
	do_pause = true;
	break;
      case 'v':
	verbose = true;
	break;
      case 'g':
	{
	  static const struct {
	    const char *name;
	    const struct real_format *fmt;
	  } fmts[] = {
#define F(x) { #x, &x##_format }
	    F(ieee_single),
	    F(ieee_double),
	    F(ieee_extended_motorola),
	    F(ieee_extended_intel_96),
	    F(ieee_extended_intel_128),
	    F(ibm_extended),
	    F(ieee_quad),
	    F(vax_f),
	    F(vax_d),
	    F(vax_g),
	    F(i370_single),
	    F(i370_double),
	    F(real_internal),
#undef F
	  };
 
	  int i, n = sizeof (fmts)/sizeof(*fmts);
 
	  for (i = 0; i < n; ++i)
	    if (strcmp (fmts[i].name, optarg) == 0)
	      break;
 
	  if (i == n)
	    {
	      printf ("Unknown implementation \"%s\"; "
		      "available implementations:\n", optarg);
	      for (i = 0; i < n; ++i)
		printf ("\t%s\n", fmts[i].name);
	      return 1;
	    }
 
	  // We cheat and use the same mode all the time, but vary
	  // the format used for that mode.
	  real_format_for_mode[int(real_c_float::MODE) - int(QFmode)]
	    = fmts[i].fmt;
 
	  Paranoia<real_c_float>().main();
	  break;
	}
 
      case 'f':
	Paranoia < native_float<float> >().main();
	break;
      case 'd':
	Paranoia < native_float<double> >().main();
	break;
      case 'l':
#ifndef NO_LONG_DOUBLE
	Paranoia < native_float<long double> >().main();
#endif
	break;
 
      case '?':
	puts ("-p\tpause between pages");
	puts ("-g<FMT>\treal.c implementation FMT");
	puts ("-f\tnative float");
	puts ("-d\tnative double");
	puts ("-l\tnative long double");
	return 0;
      }
}
 
/* GCC stuff referenced by real.o.  */
 
extern "C" void
fancy_abort ()
{
  abort ();
}
 
int target_flags = 0;
 
extern "C" int
floor_log2_wide (unsigned HOST_WIDE_INT x)
{
  int log = -1;
  while (x != 0)
    log++,
    x >>= 1;
  return log;
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.