

/*****************************************************************************\

MODULE: xdouble 

SUMMARY:

The class xdouble is used to represent floating point numbers with
the same precision as a 'double', but with extended exponent range
(offering a few more bits than that of a 'long' for the exponent).

The programming interface for xdoubles is almost identical to
that of ordinary doubles.

Here is a simple program that reads two numbers and prints their product:

#include "ZZ.h"

main()
{
   xdouble a, b, prod; 

   cin >> a; 
   cin >> b; 
   prod = b*c;
   cout << prod << "\n";
}

An xdouble is represented as a mantissa/exponent pair (x, e),
where x is a double and e is a long.
The real number represented by (x, e) is x * XD_BOUND^e,
where 

  XD_BOUND = XD_HBOUND^2, and
  XD_HBOUND = 2^{(max(ZZ_DOUBLE_PRECISION,ZZ_BITS_PER_LONG)+4)}.

Also, the mantissa x satisfies |x| <= XD_HBOUND.
The number 0 is always represented as (0, 0).
Both XD_BOUND and XD_HBOUND are macros defined in "xdouble.h".



\*****************************************************************************/

#include "ZZ.h"


class xdouble {

public:

xdouble(); // = 0
xdouble(int a); // = a
xdouble(long a); // = a
xdouble(double a); // = a
xdouble(float a); // = a

xdouble(const xdouble& a);  // standard copy constructor
xdouble& operator=(const xdouble& a);  // standard assignment operator

~xdouble();


double mantissa() const;  // read-only access to mantissa
long exponent() const;  // read-only access to exponenent



static void SetOutputPrecision(long p);
// This sets the number of decimal digits to be output.
// Default is 10.

static long OutputPrecision();
// returns current output precision.

};




/*****************************************************************************\

                             Arithmetic Operations

The following are the standard arithmetic operators, whose meaning should 
be clear.

\*****************************************************************************/


xdouble operator+(xdouble a, xdouble b);
xdouble operator-(xdouble a, xdouble b);
xdouble operator-(xdouble a);
xdouble operator*(xdouble a, xdouble b);
xdouble operator/(xdouble a, xdouble b);



void operator+=(xdouble& a, xdouble b);
void operator-=(xdouble& a, xdouble b);
void operator*=(xdouble& a, xdouble b);
void operator/=(xdouble& a, xdouble b);
void operator++(xdouble& a); // prefix
void operator++(xdouble& a, int); // postfix
void operator--(xdouble& a); // prefix
void operator--(xdouble& a, int); // postfix



/*****************************************************************************\

                                  Comparison

\*****************************************************************************/


long compare(xdouble a, xdouble b); // returns sign (+1, -1, 0) of a - b

long operator==(xdouble a, xdouble b);
long operator!=(xdouble a, xdouble b);
long operator<=(xdouble a, xdouble b);
long operator>=(xdouble a, xdouble b);
long operator <(xdouble a, xdouble b);
long operator >(xdouble a, xdouble b);



/*****************************************************************************\

                                  Conversion

\*****************************************************************************/


void operator<<(ZZ& x, xdouble a);
// x = floor(a)

xdouble XDouble(const ZZ& a);
// return xdouble approximation to a

void operator<<(xdouble& z, const ZZ& a);
// z = xdouble approximation to a

void operator<<(double& x, xdouble a);
// x = a, may cause overflow

double Double(xdouble a);
// return double representing a, may cause overflow


void operator<<(long& x, xdouble a);
// x = floor(a), may cause overflow

long Long(xdouble a);
// return floor(a), may cause overflow


/*****************************************************************************\

                               Input/Output
Input Syntax:

<number>: [ white-space ] [ "-" ] [ white-space ] <unsigned-number>
<unsigned-number>: <dotted-number> [ <e-part> ] | <e-part>
<dotted-number>: <digits> | <digits> "." <digits> | "." <digits> | <digits> "."
<digits>: <digit> <digits> | <digit>
<digit>: "0" | ... | "9"
<e-part>: ( "E" | "e" ) [ "+" | "-" ] <digits>

Examples of valid input:

17 
1.5
0.5
.5
5.  
-.5
  -  .5
e10
e-10
e+10
1.5e10
.5e10
.5E10

Examples of invalid input:

.e10
1.5e - 10
1.5 e10


\*****************************************************************************/



ostream& operator<<(ostream& s, xdouble a);

istream& operator>>(istream& s, xdouble& x);


/*****************************************************************************\

                                  Miscellaneous

\*****************************************************************************/



xdouble trunc(xdouble a);  // returns integer obtained by truncating
xdouble floor(xdouble a);  // returns greatest integer <= a
xdouble ceil(xdouble a);   // returns smallest integer >= a
xdouble fabs(xdouble a);   // returns |a|
xdouble sqrt(xdouble a);   // returns a^{1/2}; error is raised if a < 0


void power(xdouble& z, xdouble a, const ZZ& e);
void power(xdouble& z, xdouble a, long e);
// z = a^e, e may be negative
