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

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.


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

#include <NTL/ZZ.h>


class xdouble {

public:

xdouble(); // = 0

xdouble(const xdouble& a);  // copy constructor

explicit xdouble(double a);  // promotion constructor

xdouble& operator=(const xdouble& a);  // assignment operator
xdouble& operator=(double a);

~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+(const xdouble& a, const xdouble& b);
xdouble operator-(const xdouble& a, const xdouble& b);
xdouble operator*(const xdouble& a, const xdouble& b);
xdouble operator/(const xdouble& a, const xdouble& b);

// PROMOTIONS: +, -, *, / promote double to xdouble on (a, b).

xdouble operator-(const xdouble& a);

xdouble& operator+=(xdouble& a, const xdouble& b);
xdouble& operator+=(xdouble& a, double b);

xdouble& operator-=(xdouble& a, const xdouble& b);
xdouble& operator-=(xdouble& a, double b);

xdouble& operator*=(xdouble& a, const xdouble& b);
xdouble& operator*=(xdouble& a, double b);

xdouble& operator/=(xdouble& a, const xdouble& b);
xdouble& operator/=(xdouble& a, xdouble b);

xdouble& operator++(xdouble& a); // prefix
void operator++(xdouble& a, int); // postfix

xdouble& operator--(xdouble& a); // prefix
void operator--(xdouble& a, int); // postfix



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

                                  Comparison

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

long sign(const xdouble& a);
// returns sign (+1, -1, 0) of a

long compare(const xdouble& a, const xdouble& b);
// returns sign of a - b

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

// PROMOTIONS: compare and operators ==, ..., > promote double to xdouble
// on (a, b).



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

                               Input/Output
Input Syntax:

<number>: [ "-" ] <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 e10 e-10 e+10 1.5e10 .5e10 .5E10

Note that the number of decimal digits of precision that are used
for output can be set to any number p >= 1 by calling
the routine xdouble::SetOutputPrecision(p).  
The default value of p is 10.
The current value of p is returned by a call to xdouble::OutputPrecision().

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



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

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


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

                                  Miscellaneous

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



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

double log(const xdouble& a);  // returns log(a) (note return val is double!)
xdouble xexp(double a);        // returns exp(a) (note argument is double!)
xdouble exp(const double& a);  // equivalent to xexp(to_double(a))


void power(xdouble& z, const xdouble& a, const ZZ& e);
xdouble power(const xdouble& a, const ZZ& e);

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

void power2(xdouble& z, long e);
xdouble power2_xdouble(long e);
// z = 2^e, e may be negative

void MulAdd(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c);
xdouble MulAdd(const xdouble& a, const xdouble& b, const xdouble& c);
// z = a + b*c, but faster

void MulSub(xdouble& z, const xdouble& a, const xdouble& b, const xdouble& c);
xdouble MulSub(const xdouble& a, const xdouble& b, const xdouble& c);
// z = a - b*c, but faster


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

Implementation details:

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 * NTL_XD_BOUND^e, where

  NTL_XD_BOUND = NTL_XD_HBOUND^2, and
  NTL_XD_HBOUND = 2^{(max(NTL_DOUBLE_PRECISION,NTL_BITS_PER_LONG)+4)}.

Also, the mantissa x satisfies 1/NTL_XD_HBOUND <= |x| <= NTL_XD_HBOUND, except
that the number 0 is always represented as (0, 0).  
Both NTL_XD_BOUND and NTL_XD_HBOUND are macros defined in <NTL/xdouble.h>.

SIZE INVARIANT: |e| < 2^(NTL_BITS_PER_LONG-4).

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