/*
%Z%  FILE: %M%  RELEASE: %I%  DATE: %G%, %U%
*/
/*******************************************************************************

    VeryLong.hh

    VeryLong Class Definitions.

*******************************************************************************/

#ifndef  VERYLONG_HH		// Has the file been INCLUDE'd already?
#define  VERYLONG_HH  yes


#include  <cstdio>			/* Standard I/O definitions. */
#include  <cstring>			// Standard C string functions.
#include  <iostream.h>			// I/O stream definitions.


#define  NUMBYTES  ((precision + 8 - 1) / 8)
#define  NUMLONGS  ((NUMBYTES + sizeof (long) - 1) / sizeof (long))


/*******************************************************************************
    VeryLong Class.
*******************************************************************************/

template <
    unsigned int precision>
class  VeryLong {

					// Arithmetic operators.
    friend  VeryLong  operator+ (const VeryLong& lhs,
                                 const VeryLong& rhs) ;
    friend  VeryLong  operator- (const VeryLong& lhs) ;
    friend  VeryLong  operator- (const VeryLong& lhs,
                                 const VeryLong& rhs) ;
    friend  VeryLong  operator* (const VeryLong& lhs,
                                 const VeryLong& rhs) ;
    friend  VeryLong  operator/ (const VeryLong& lhs,
                                 const VeryLong& rhs) ;
    friend  VeryLong  operator% (const VeryLong& lhs,
                                 const VeryLong& rhs) ;
					// Bitwise operators.
    friend  VeryLong  operator& (const VeryLong& lhs,
                                 const VeryLong& rhs) ;
    friend  VeryLong  operator| (const VeryLong& lhs,
                                 const VeryLong& rhs) ;
    friend  VeryLong  operator~ (const VeryLong& lhs) ;
    friend  VeryLong  operator<< (const VeryLong& lhs,
                                  unsigned int numBitsToShift) ;
    friend  VeryLong  operator>> (const VeryLong& lhs,
                                  unsigned int numBitsToShift) ;
					// Relational operators.
    friend  int  operator== (const VeryLong& lhs,
                             const VeryLong& rhs) ;
    friend  int  operator< (const VeryLong& lhs,
                            const VeryLong& rhs) ;
    friend  int  operator> (const VeryLong& lhs,
                            const VeryLong& rhs) ;
					// I/O operators.
    friend  istream&  operator>> (istream& stream,
                                  VeryLong& value) ;
    friend  ostream&  operator<< (ostream& stream,
                                  const VeryLong& value) ;

    static  VeryLong  Decode (const char *string) ;

  public:

    typedef  enum  VeryLongState {
        Uninitialized, Valid, Overflow, Underflow
    }  VeryLongState ;

    VeryLong () ;			// Create uninitialized value.
    VeryLong (long leastSignificant) ;	// Create initialized value.
//    VeryLong (long mostSignificant,	// Create initialized value.
//              ...) ;
    ~VeryLong () ;			// Destroy value.

    const  char  *Encode () const ;	// Return ASCII encoding.

    operator double () const ;		// "(double)" cast of very long value.

    VeryLong  operator++ () ;		// Increment a very long value.
    VeryLong  operator++ (int) ;

    VeryLong  operator-- () ;		// Decrement a very long value.
    VeryLong  operator-- (int) ;

  private:

    VeryLongState  state ;		// Validity of value.
    long  value[NUMLONGS] ;		// Multi-longword value.

} ;

/*******************************************************************************
    Inline Arithmetic Operators.
*******************************************************************************/

template <				// Negate a very long value.
    unsigned int precision>
inline  VeryLong<precision>  operator- (const VeryLong<precision>& lhs) {
    return (~lhs + 1) ;
}

template <				// Subtract one very long value from another.
    unsigned int precision>
inline  VeryLong<precision>  operator- (const VeryLong<precision>& lhs,
                                        const VeryLong<precision>& rhs) {
    return (lhs + (-rhs)) ;
}

template <				// Increment a very long value.
    unsigned int precision>
inline  VeryLong<precision>  VeryLong<precision>::operator++ () {
    return (*this = (*this + 1)) ;
}

template <				// Increment a very long value.
    unsigned int precision>
inline  VeryLong<precision>  VeryLong<precision>::operator++ (int) {
    VeryLong<precision>  previousValue = *this ;
    return ((*this = *this + 1), previousValue) ;
}

template <				// Decrement a very long value.
    unsigned int precision>
inline  VeryLong<precision>  VeryLong<precision>::operator-- () {
    return (*this = (*this - 1)) ;
}

template <				// Decrement a very long value.
    unsigned int precision>
inline  VeryLong<precision>  VeryLong<precision>::operator-- (int) {
    VeryLong<precision>  previousValue = *this ;
    return ((*this = *this - 1), previousValue) ;
}

template <				// Compute remainder of division.
    unsigned int precision>
inline  VeryLong<precision>  operator% (const VeryLong<precision>& lhs,
                                        const VeryLong<precision>& rhs) {
    return (lhs - ((lhs / rhs) * rhs)) ;
}


/*******************************************************************************
    Inline Relational Operators.
*******************************************************************************/

template <				// Q1 != Q2?
    unsigned int precision>
inline  int  operator!= (const VeryLong<precision>& lhs,
                         const VeryLong<precision>& rhs) {
    return (!(lhs == rhs)) ;
}

template <				// Q1 <= Q2?
    unsigned int precision>
inline  int  operator<= (const VeryLong<precision>& lhs,
                         const VeryLong<precision>& rhs) {
    return (!(lhs > rhs)) ;
}

template <				// Q1 >= Q2?
    unsigned int precision>
inline  int  operator>= (const VeryLong<precision>& lhs,
                         const VeryLong<precision>& rhs) {
    return (!(lhs < rhs)) ;
}


/*******************************************************************************
    Inline I/O Functions.
*******************************************************************************/

template <
    unsigned int precision>
inline  ostream&  operator<< (ostream& stream,
                              const VeryLong<precision>& value) {
    return (stream << value.Encode ()) ;
}


#ifndef  VeryLong_Implementation
#    include  "VeryLong.cc"
#endif


#endif				// If this file was not INCLUDE'd previously.
