#ifdef __ZTC__
#include <stream.hpp>
#endif
#ifdef __TURBOC__
#include <iostream.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>	// for exit() prototype

/* define only on of these to 1 */
/* #define BIT32 */
#define BIT16	1			/* we have a 16-bit compiler */

#ifdef BIT32
#define INT	int
#else
#define INT long			/* for 16-bit C++ compilers */
#endif

const unsigned INT QNAN =   0x7FFFFFFF;
const unsigned INT SNAN =   0x7FC00000;
const unsigned INT INF  =   0x7F800000;
const unsigned INT ZERO =   0x00000000;
const unsigned INT DENORM = 0x00000001;
const unsigned INT NORM =   0x00800000;

//
//  This is a class definition for single precision IEEE-854-Std arithmetic.
//  class real is by no means complete - it is the basic outline for
//  implementing a portable numerics system.
//

class real {
   private:
      union {
	 float f;
	 unsigned INT i;
	 };
   public:

      // constructors

      real();         
      real(char *);   
      real(float f);
      real(double d);
      real(char c);
      real(short s);
      real(INT i);

      // No destructors really necessary

      // some basic primitives

      inline friend int isqnan(real &r);
      inline friend int issnan(real &r);
      inline friend int iszero(real &r);
      inline friend int isinf(real &r);
      inline friend int isdenorm(real &r);
      inline friend int isnorm(real &r);

      // overloaded operators
       
      friend real operator+( real &, real & );
      friend real operator-( real &, real & );
      friend real operator*( real &, real & );
      friend real &operator/( real &, real & );

      friend int operator==( real &, real & );
      friend int operator!=( real &, real & );
      friend int operator> ( real &, real & );
      friend int operator>=( real &, real & );
      friend int operator<=( real &, real & );
      friend int operator< ( real &, real & );

      inline void print(void) { cout << f; }

      }; // end of class real

// I/O related overloads

ostream &operator << (ostream &out, real &r) {
/*   r.print();		this was an error in magazine listing */
   if (isqnan(r)) cout << " QNAN ";
   else if (issnan(r)) cout << " SNAN ";
   else if (isinf(r)) cout << " INF ";
   else if (isdenorm(r)) cout << " DENORM ";
   else r.print();

   return out;
   }

istream &operator >> (istream &in, real &r) {

   return in;
   }

real::real() {}  // allow uninitialized variables

real::real(char *str){
   if (strcmp(str,"INF") == 0)
      i = INF;
   else if (strcmp(str,"QNAN") == 0)
      i = QNAN;
   else if (strcmp(str,"SNAN") == 0)
      i = SNAN;
   else if (strcmp(str,"ZERO") == 0)
      i = ZERO;
   else if (strcmp(str,"DENORM") == 0)
      i = DENORM;
   else if (strcmp(str,"NORM") == 0)
      i = NORM;
   else {
      cout << "Unrecognized string format :" << str << ":\n";
      exit(1);
      }
   }

real::real(float fl){ f = fl; }

real::real(double d){ f = float(d); }

real::real(char c){ f = float(c); }

real::real(short s){ f = float(s); }

real::real(INT I){ f = float(I); }

int isqnan( real &r ){
   unsigned INT i = r.i;
   if ((i >= 0x7FC00000) && (i <= 0x7FFFFFFF))
      return 1;
   return 0;
   }

int issnan( real &r ){
   unsigned INT i = r.i;
   if ((i >= 0x7F800001) && (i <= 0x7FBFFFFF))
      return 1;
   return 0;
   }

int iszero( real &r ){
   unsigned INT i = r.i;
   if (i == 0)
      return 1;
   return 0;
   }

int isinf( real &r ){
   unsigned INT i = r.i;
   if (i == 0x7F800000)
      return 1;
   return 0;
   }

int isdenorm( real &r ){
   unsigned INT i = r.i;
   if ((i >= 0x00000001) && (i <= 0x007FFFFF))
      return 1;
   return 0;
   }

int isnorm( real &r ){
   unsigned INT i = r.i;
   if ((i >= 0x00800000) && (i <= 0x7F7FFFFF))
      return 1;
   return 0; 
   }

int operator==( real &num, real &dem ){
   // this is a skeleton == operator for reals
   if (isnorm(num) && isnorm(num)) return (num.i == dem.i);
   else if (isqnan(num) && isqnan(dem)) return 1;
   else if (issnan(num) && issnan(dem)) return 1;
   else if (isinf(num) && isinf(dem)) return 1;
   else if (isdenorm(num) && isdenorm(dem)) return 1;
   return 0; 
   }

const char DIV_BY_NAN = 0;
const char DIV_BY_QNAN = 1;
const char DIV_BY_ZERO = 2;
const char INVALID_OP = 3;
const char DIV_BY_INF = 4;

void set_psr(char c){
   // a stub for setting a user controlled processor control word
   }

real result;

real& operator/(real &nom, real &dem) {
   if (isqnan(nom) || isqnan(dem) || issnan(nom) || issnan(dem)){
      set_psr(DIV_BY_NAN);
      result.i = QNAN;
      return result;
      }
   else if (iszero(nom) && iszero(dem)){
      set_psr( DIV_BY_QNAN );
      result.i = QNAN;
      return result;
      }
   else if (iszero(dem)) {
      set_psr( DIV_BY_ZERO );
      result.i = INF;
      return result;
      }
   else if (isinf(nom) && isinf(dem)) {
      set_psr( INVALID_OP );
      result.i = QNAN;
      return result;
      }
   else if (isinf(nom) && isnorm(dem)) {
      set_psr( DIV_BY_INF );
      result.i = INF;
      return result;
      }
   else if ((isnorm(nom) || iszero(nom)) && isinf(dem)) {
      result.i = ZERO;
      return result;
      }
   result.f = float(nom.f) / float(dem.f);
   return result;
   }  // end of real::operator/

/*
**  A very simple program showing real assignments, divide operations,
**  output routines, and comparisons.
*/

int main(void) {

   real r1;
   real r2 = 0.0;
   real r3 = 1.0;
   real rinf = "INF";
   real rqnan = "QNAN";
   real rsnan = "SNAN";
   real rzero = "ZERO";
   real rdenorm = "DENORM";

   cout << "r1 = " << r1 << "\n";
   cout << "r2 = " << r2 << "\n";
   cout << "r3 = " << r3 << "\n";
   cout << "rinf = " << rinf << "\n";
   cout << "rqnan = " << rqnan << "\n";
   cout << "rsnan = " << rsnan << "\n";
   cout << "rzero = " << rzero << "\n";
   cout << "rdenorm = " << rdenorm << "\n";

   r1 = r3 / r2;   // this should generate an INF
   cout << "r1 = INF ?? " << r1 << "\n";

   r1 = rqnan / rqnan;  // this should generate a QNAN
   cout << "rqnan = QNAN ?? " << rqnan << "\n";

   if (r1 == rsnan)
      cout << "WRONG!!! QNAN == SNAN\n";
   else
      cout << "RIGHT!!! QNAN != SNAN\n";

   } // end of main
