/*
**  CXSC is a C++ library for eXtended Scientific Computing
**
**  Copyright (C) 1990-2000 Institut fuer Angewandte Mathematik,
**                          Universitaet Karlsruhe, Germany
**            (C) 2000-2001 Wiss. Rechnen/Softwaretechnologie
**                          Universitaet Wuppertal, Germany   
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Library General Public
**  License as published by the Free Software Foundation; either
**  version 2 of the License, or (at your option) any later version.
**
**  This library is distributed in the hope that it will be useful,
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
**  Library General Public License for more details.
**
**  You should have received a copy of the GNU Library General Public
**  License along with this library; if not, write to the Free
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/* CVS $Id: real.inl,v 1.3 2001/08/09 11:37:59 cxsc Exp $ */

#ifdef real_hpp_included

namespace cxsc {

inline real operator -(const real &a) throw()       { return -a.w; }
inline real operator +(const real &a) throw()       { return a; }

inline real operator +(const real &a,const real &b) throw () { return a.w+b.w; }
inline real operator -(const real &a,const real &b) throw () { return a.w-b.w; }
inline real operator *(const real &a,const real &b) throw () { return a.w*b.w; }
inline real operator /(const real &a,const real &b) throw () { return a.w/b.w; }

inline real& operator +=(real &a, const real &b) throw () { a.w+=b.w; return a; }
inline real& operator -=(real &a, const real &b) throw () { a.w-=b.w; return a; }
inline real& operator *=(real &a, const real &b) throw () { a.w*=b.w; return a; }
inline real& operator /=(real &a, const real &b) throw () { a.w/=b.w; return a; }

inline bool operator!  (const real& a)                throw () { return !a.w; }
inline bool operator== (const real& a, const real& b) throw () { return a.w==b.w; }
inline bool operator!= (const real& a, const real& b) throw () { return a.w!=b.w; }
inline bool operator<  (const real& a, const real& b) throw () { return a.w<b.w;  }
inline bool operator<= (const real& a, const real& b) throw () { return a.w<=b.w; }
inline bool operator>= (const real& a, const real& b) throw () { return a.w>=b.w; }
inline bool operator>  (const real& a, const real& b) throw () { return a.w>b.w;  }

inline bool operator== (const real& a, const int & b) throw () { return a.w==b; }
inline bool operator!= (const real& a, const int & b) throw () { return a.w!=b; }
inline bool operator== (const int & a, const real& b) throw () { return a==b.w; }
inline bool operator!= (const int & a, const real& b) throw () { return a!=b.w; }
inline bool operator== (const real& a, const long & b) throw () { return a.w==b; }
inline bool operator!= (const real& a, const long & b) throw () { return a.w!=b; }
inline bool operator== (const long & a, const real& b) throw () { return a==b.w; }
inline bool operator!= (const long & a, const real& b) throw () { return a!=b.w; }
inline bool operator== (const real& a, const float & b) throw () { return a.w==b; }
inline bool operator!= (const real& a, const float & b) throw () { return a.w!=b; }
inline bool operator== (const float & a, const real& b) throw () { return a==b.w; }
inline bool operator!= (const float & a, const real& b) throw () { return a!=b.w; }
inline bool operator== (const real& a, const double & b) throw () { return a.w==b; }
inline bool operator!= (const real& a, const double & b) throw () { return a.w!=b; }
inline bool operator== (const double & a, const real& b) throw () { return a==b.w; }
inline bool operator!= (const double & a, const real& b) throw () { return a!=b.w; }


inline real abs(const real &a) throw()
{
   if(a.w>=0)
      return a.w;
   return -a.w;
}

inline int sign(const real &a) throw()
{
   if(a.w>0)
      return 1;
   else
      if(a.w)
         return -1;
      else 
         return 0;
}   


// ------- Verknuepfungen mit nach oben bzw. unten gerichteter Rundung ------
// ------- (Operators with rounding direction upwards or downwards) ---------

} // namespace cxsc

#include "rts_real.hpp"

namespace cxsc {

inline real addup(const real &x, const real &y)
{
	a_real ret;
	#if ( OPT80387 )
		ret = r_addu80387(_a_real(x.w), _a_real(y.w));
	#else
		ret = r_addu(_a_real(x.w), _a_real(y.w));
	#endif
	#if HP_9000_CPP+SUN4_CPP_C
		r_lfsr();
	#endif
	return _real(ret);
}

inline real adddown(const real &x, const real &y)
{
	a_real ret;
	#if ( OPT80387 )
		ret = r_addd80387(_a_real(x.w), _a_real(y.w));
	#else
		ret = r_addd(_a_real(x.w), _a_real(y.w));
	#endif
	#if HP_9000_CPP+SUN4_CPP_C
		r_lfsr();
	#endif
	return _real(ret);
}

inline real subup(const real &x, const real &y)
{
	a_real ret;
	#if ( OPT80387 )
		ret = r_subu80387(_a_real(x.w), _a_real(y.w));
	#else
		ret = r_subu(_a_real(x.w), _a_real(y.w));
	#endif
	#if HP_9000_CPP+SUN4_CPP_C
		r_lfsr();
	#endif
	return _real(ret);
}

inline real subdown(const real &x, const real &y)
{
	a_real ret;
	#if ( OPT80387 )
		ret = r_subd80387(_a_real(x.w), _a_real(y.w));
	#else
		ret = r_subd(_a_real(x.w), _a_real(y.w));
	#endif
	#if HP_9000_CPP+SUN4_CPP_C
		r_lfsr();
	#endif
	return _real(ret);
}

inline real multup(const real &x, const real &y)
{
	a_real ret;
	#if ( OPT80387 )
		ret = r_mulu80387(_a_real(x.w), _a_real(y.w));
	#else
		ret = r_mulu(_a_real(x.w), _a_real(y.w));
	#endif
	#if HP_9000_CPP+SUN4_CPP_C
		r_lfsr();
	#endif
	return _real(ret);
}

inline real multdown(const real &x, const real &y)
{
	a_real ret;
	#if ( OPT80387 )
		ret = r_muld80387(_a_real(x.w), _a_real(y.w));
	#else
		ret = r_muld(_a_real(x.w), _a_real(y.w));
	#endif
	#if HP_9000_CPP+SUN4_CPP_C
		r_lfsr();
	#endif
	return _real(ret);
}

inline real divup(const real &x, const real &y)
{
	a_real ret;
	#if ( OPT80387 )
		ret = r_divu80387(_a_real(x.w), _a_real(y.w));
	#else
		ret = r_divu(_a_real(x.w), _a_real(y.w));
	#endif
	#if HP_9000_CPP+SUN4_CPP_C
		r_lfsr();
	#endif
	return _real(ret);
}

inline real divdown(const real &x, const real &y)
{
	a_real ret;
	#if ( OPT80387 )
		ret = r_divd80387(_a_real(x.w), _a_real(y.w));
	#else
		ret = r_divd(_a_real(x.w), _a_real(y.w));
	#endif
	#if HP_9000_CPP+SUN4_CPP_C
		r_lfsr();
	#endif
	return _real(ret);
}

//----------------------------------------------------------------------------
// IsInfinity - prueft ob die uebergebene IEEE 64-Bit Gleitkommazahl
//              'Unendlich' darstellt, dies ist der Fall, falls:
//                alle Bits des Exponenten 1 sind
//                alle Bits der Mantisse 0 sind
//
inline bool IsInfinity (const real &a) 
{
   if ((((a_btyp*)&a)[HIGHREAL] & 0x7FF00000L) != 0x7FF00000L) 
      return false;
   if ((((a_btyp*)&a)[HIGHREAL] & 0x000FFFFFL) != 0L) 
      return false;
   if (((a_btyp*)&a)[LOWREAL] != 0L) 
      return false;
  return true;  // a ist 'unendlich'
}

//----------------------------------------------------------------------------
// IsNan      - prueft ob die uebergebene IEEE 64-Bit Gleitkommazahl
//              eine ungueltige Zahl (Not a number) darstellt,
//              dies ist der Fall, falls:
//                alle Bits des Exponenten 1 sind
//                und nicht alle Bits der Mantisse 0 sind
//
inline bool IsQuietNaN (const real &a) 
{
   if ((((a_btyp*)&a)[HIGHREAL] & 0x7FF00000L) != 0x7FF00000L) 
      return false;

   if ((((a_btyp*)&a)[HIGHREAL] & 0x000FFFFFL) == 0L) 
   {
      if (((a_btyp*)&a)[LOWREAL] == 0L) 
         return false;
   }
   return true;
}

//----------------------------------------------------------------------------
// IsSignalingNaN - prueft ob die uebergebene IEEE 64-Bit Gleitkommazahl
//              undefiniert ist (z.B. Berechnung der Wurzel einer negativen
//              Zahl), dies ist der Fall, falls
//                das Vorzeichenbit 1 ist
//                alle Bits des Exponenten 1 sind
//                das hoechste Bit der Mantisse 1 ist
//                und alle anderen Bits der Mantisse 0 sind
//
inline bool IsSignalingNaN (const real &a) 
{
   if ((((a_btyp*)&a)[HIGHREAL] & 0xFFF00000L) != 0xFFF00000L) 
      return false;
   if ((((a_btyp*)&a)[HIGHREAL] & 0x000FFFFFL) != 0x00080000L) 
      return false;
   if (((a_btyp*)&a)[LOWREAL] != 0L) 
      return false;
   return true;
}

extern "C"
{
   double q_pred(double);
   double q_succ(double);
   a_real r_comp(a_real,a_intg);
   a_real r_mant(a_real);
   a_intg r_expo(a_real);
}

inline real pred(const real& r) throw()
{
   a_real ret;
   ret = q_pred(r.w);
   return real(ret);
}

inline real succ(const real& r) throw()
{
   a_real ret;
   ret = q_succ(r.w);
   return real(ret);
}

inline a_intg expo(const real &r) throw()
{
   return r_expo(*(a_real*)&r.w);
}

inline real comp(const real &r, a_intg i) throw()
{
   return real(r_comp(*(a_real*)&r.w,i));
}

inline real mant(const real &r) throw()
{
   return real(r_mant(*(a_real*)&r.w));
}
      
} // namespace cxsc

#endif //CXSC_REAL_HPP_INCLUDED
