// ------------------
// Purenum 0.4d alpha
// ------------------
// integer.h
// ------------------

// the "CONFIGURATION" section below must be correct

// see file: "integer.txt" for more info about class Integer


#ifndef INTEGER_H
#define INTEGER_H


////////////////////////////////////////////////////////////////////////////////
// CONFIGURATION (must be reconfigured for each system this is compiled on!)
// CONFIGURATION (must be reconfigured for each system this is compiled on!)
// CONFIGURATION (must be reconfigured for each system this is compiled on!)
// 
// INTEGER_H_BITS --  What is the hardware bit width of the CPU chip?  Must
//     correctly specify the bit width of INTEGER_H_DIGITTYPE (see below) or
//     this software will not work.  (the default digit type is 'unsigned int')
//     Most modern computers are 32-bit, as of November 2000.
// 
//#define INTEGER_H_BITS 8     // base 256 math (2^8)
//#define INTEGER_H_BITS 16    // base 65536 math (2^16)
#define INTEGER_H_BITS 32      // base 4294967296 math (2^32)
//#define INTEGER_H_BITS 64    // base 18446744073709551616 math (2^64)
//
// INTEGER_H_INITZERO --  For easier programming, all Integers may be
// automatically initialized to zero while being constructed, whenever the
// programmer does not specify an immediate initializer.  This prevents the
// tricky bugs which can result from the use of uninitialized values, but is
// slower.  Zeroing is the default because ease-of-use is the top priority for
// this software.  Experts who are confident of their ability to remember to
// initialize all values before use can disable this option for a (usually
// small) speed increase.
// 
#define INTEGER_H_INITZERO    // init Integers to zero during construction
// 
// INTEGER_H_DIGITTYPE --  
// 
//#define INTEGER_H_DIGITTYPE unsigned char     // type of Integer::atom
//#define INTEGER_H_DIGITTYPE unsigned short    // type of Integer::atom
#define INTEGER_H_DIGITTYPE unsigned int        // type of Integer::atom
//#define INTEGER_H_DIGITTYPE unsigned long     // type of Integer::atom
//
//#define INTEGER_H_SDIGITTYPE signed char      // type of Integer::satom
//#define INTEGER_H_SDIGITTYPE signed short     // type of Integer::satom
#define INTEGER_H_SDIGITTYPE signed int         // type of Integer::satom
//#define INTEGER_H_SDIGITTYPE signed long      // type of Integer::satom
// 
// USE FAST BIGNUM ALGORITHMS --  Should the fast, but complicated and tricky,
// code for wide multiplication and wide division be enabled?  Without enabling
// these the simple, reliable, and very, very, very slow code is used.  Very,
// very, very slow!  Does not affect thin integer math, which is always fast.
// FIXME: remove the slow wide mul/div code before final release
// 
#define INTEGER_H_FASTMUL    // enable fast wide multiplication code
#define INTEGER_H_FASTDIV    // enable fast wide division code
// 
// FAKE CPU BIT WIDTH --  Pretend to be on a CPU with a smaller hardware bit
//     width, specified here.  The true hardware bit width must be specified
//     correctly in INTEGER_H_BITS (above) or this software will not work.
//     FIXME: the INTEGER_H_FAKEBITS functionality is incomplete, beware.
//
//#define INTEGER_H_FAKEBITS 8     // base 256 math (2^8)
//#define INTEGER_H_FAKEBITS 16    // base 65536 math (2^16)
//#define INTEGER_H_FAKEBITS 32    // base 4294967296 math (2^32)
// 
// DECIMAL DEBUGGING --  During development some parts of this software used
// decimal math (almost 4-bit math) because it was easier to debug numbers when
// they could be directly printed in decimal form.  Probably does not work
// anymore and will be removed sometime.  FIXME
// 
//#define INTEGER_H_DECIMAL    // DO NOT DEFINE, FOR DEBUGGING PURPOSES ONLY
// 
////////////////////////////////////////////////////////////////////////////////

#define PURENUM_STRING_CONSTRUCTOR_EXPLICIT
// (SR) FIXME needs to be put into rascal sources... ;)

#ifndef PURENUM_STRING_CONSTRUCTOR_EXPLICIT
#define EX
#else    // PURENUM_STRING_CONSTRUCTOR_EXPLICIT
#define EX explicit
#endif    // PURENUM_STRING_CONSTRUCTOR_EXPLICIT


// FIXME: delete the following <iostream> include?
#include <iostream>

class Integer
{
public:
    typedef INTEGER_H_DIGITTYPE atom;
    typedef INTEGER_H_SDIGITTYPE satom;
    enum sign { positive, negative };

    inline Integer();                           // see INTEGER_H_INITZERO above
    inline Integer(sign, atom);                 // init from a hardware number
    inline Integer(atom);                       // init from a hardware value
    inline Integer(satom);                      // init from a hardware value
    inline Integer(const Integer &);            // init from another Integer
EX  inline Integer(const char *ascii);          // init from a string number
    inline ~Integer();                          // destructor

    // conversion operators
    // FIXME: need signed int conversion operator
    inline operator bool() const;
    inline operator signed int() const;
    inline operator unsigned int() const;

    // unary math operators (members)
    inline Integer &operator++();      // prefix
    inline Integer operator++(int);    // postfix
    inline Integer &operator--();      // prefix
    inline Integer operator--(int);    // postfix

    // binary math operators (members)
    inline Integer &operator=(const Integer &);
    inline Integer &operator=(const atom &);
    inline Integer &operator=(const satom &);
    inline Integer &operator+=(const Integer &);
    inline Integer &operator+=(const atom &);
    inline Integer &operator+=(const satom &);
    inline Integer &operator-=(const Integer &);
    inline Integer &operator-=(const atom &);
    inline Integer &operator-=(const satom &);
    inline Integer &operator*=(const Integer &);
    inline Integer &operator*=(const atom &);
    inline Integer &operator*=(const satom &);
    inline Integer &operator/=(const Integer &);
    inline Integer &operator/=(const atom &);
    inline Integer &operator/=(const satom &);
    inline Integer &operator%=(const Integer &);
    inline Integer &operator%=(const atom &);
    inline Integer &operator%=(const satom &);

    // friends: unary math operators (global functions)
    friend Integer operator~(const Integer &);
    friend bool operator!(const Integer &);
    friend Integer operator-(const Integer &);
    friend Integer operator+(const Integer &);

    // friends: binary math operators (global functions)
    friend Integer operator+(const Integer &, const Integer &);
    friend Integer operator+(const Integer &, const atom &);
    friend Integer operator+(const atom &, const Integer &);
    friend Integer operator+(const Integer &, const satom &);
    friend Integer operator+(const satom &, const Integer &);
    friend Integer operator-(const Integer &, const Integer &);
    friend Integer operator-(const Integer &, const atom &);
    friend Integer operator-(const atom &, const Integer &);
    friend Integer operator-(const Integer &, const satom &);
    friend Integer operator-(const satom &, const Integer &);
    friend Integer operator*(const Integer &, const Integer &);
    friend Integer operator*(const Integer &, const atom &);
    friend Integer operator*(const atom &, const Integer &);
    friend Integer operator*(const Integer &, const satom &);
    friend Integer operator*(const satom &, const Integer &);
    friend Integer operator/(const Integer &, const Integer &);
    friend Integer operator/(const Integer &, const atom &);
    friend Integer operator/(const atom &, const Integer &);
    friend Integer operator/(const Integer &, const satom &);
    friend Integer operator/(const satom &, const Integer &);
    friend Integer operator%(const Integer &, const Integer &);
    friend Integer operator%(const Integer &, const atom &);
    friend Integer operator%(const atom &, const Integer &);
    friend Integer operator%(const Integer &, const satom &);
    friend Integer operator%(const satom &, const Integer &);
    friend bool operator==(const Integer &, const Integer &);
    friend bool operator==(const Integer &, const atom &);
    friend bool operator==(const atom &, const Integer &);
    friend bool operator==(const Integer &, const satom &);
    friend bool operator==(const satom &, const Integer &);
    friend bool operator!=(const Integer &, const Integer &);
    friend bool operator!=(const Integer &, const atom &);
    friend bool operator!=(const atom &, const Integer &);
    friend bool operator!=(const Integer &, const satom &);
    friend bool operator!=(const satom &, const Integer &);
    friend bool operator>(const Integer &, const Integer &);
    friend bool operator>(const Integer &, const atom &);
    friend bool operator>(const atom &, const Integer &);
    friend bool operator>(const Integer &, const satom &);
    friend bool operator>(const satom &, const Integer &);
    friend bool operator>=(const Integer &, const Integer &);
    friend bool operator>=(const Integer &, const atom &);
    friend bool operator>=(const atom &, const Integer &);
    friend bool operator>=(const Integer &, const satom &);
    friend bool operator>=(const satom &, const Integer &);
    friend bool operator<(const Integer &, const Integer &);
    friend bool operator<(const Integer &, const atom &);
    friend bool operator<(const atom &, const Integer &);
    friend bool operator<(const Integer &, const satom &);
    friend bool operator<(const satom &, const Integer &);
    friend bool operator<=(const Integer &, const Integer &);
    friend bool operator<=(const Integer &, const atom &);
    friend bool operator<=(const atom &, const Integer &);
    friend bool operator<=(const Integer &, const satom &);
    friend bool operator<=(const satom &, const Integer &);
    friend bool operator&&(const Integer &, const Integer &);
    friend bool operator&&(const Integer &, const bool);
    friend bool operator&&(const bool, const Integer &);
    friend bool operator||(const Integer &, const Integer &);
    friend bool operator||(const Integer &, const bool);
    friend bool operator||(const bool, const Integer &);

    // FIXME: move these to a seperate optional file?
    // other/math functions (global functions)
    friend ostream &operator<<(ostream &, const Integer &);  // FIXME delete?
    friend void swap(Integer &, Integer &);
    friend Integer abs(const Integer &);
    friend Integer min(const Integer &, const Integer &);
    friend Integer max(const Integer &, const Integer &);
    friend Integer fac(const Integer &);
    friend Integer pow(const Integer &, const Integer &);

    // exceptions
    // FIXME: throw outofmemory when 'new' fails?  or not?
    class exception { };
    class divisionbyzero : public exception { };   // division by zero
    class outofmemory : public exception { };      // software integer overflow
    class outofrange : public exception { };       // hardware integer overflow
    class badstring : public exception { };        // non-numeric initializer
    class negativefactorial : public exception {}; // can't do x! for x < 0

    // ascii string input and output           FIXME: not internationalized
    char *ascii(const Integer base = 10) const;                    // out new[]
    void ascii(atom size, char *, const Integer base = 10) const;  // output
    void ascii(const char *, const Integer base = 10);             // input

#if 0
    // string input and output, digits are zero-based (no character set)
    char *string(atom base = 10) const;                      // output to new[]
    void string(atom size, char *, atom base = 10) const;    // buffer output
    void string(const char *, atom base = 10);               // buffer input

    // bitstream input and output, a string() with a header and a footer
    atom *bitstream(atom base = maxatom_) const;
    void bitstream(atom size, atom *a, atom base = maxatom_) const;
    void bitstream(const atom *a, atom base = maxatom_);
#endif    // 0

private:
    // internal representation of the integer value (this is the entire state)
    atom memorysize_;               // number of atoms in memory_
    bool negative_;                 // is this Integer negative?
    union optimizedmemory_          // .fast needs no heap allocation, speedy!
    {
        atom fast;                  // storage for a thin integer (one digit)
        atom *slow;                 // storage for a wide integer (many digits)
    } memory_;
    static const atom maxatom_;     // largest legal value in an Integer digit
#ifdef INTEGER_H_FASTMUL
    static const atom smallmaxatom_;    // used for wide multiply optimization
#endif    // INTEGER_H_FASTMUL
#ifdef INTEGER_H_FAKEBITS
    static const atom truemaxatom_;     // see INTEGER_H_FAKEBITS above
#endif    // INTEGER_H_FAKEBITS

    // private thin math (single-atom) subroutines used by public functions
    inline void addatomzero(atom &left, bool &carry) const;
    inline void subatomzero(atom &left, bool &borrow) const;
    inline void addatoms(atom &left, const atom &right, bool &carry) const;
    inline void subatoms(atom &left, const atom &right, bool &borrow) const;
    inline void mulatoms(atom &left, const atom &right, atom &carry) const;

    // private wide math (multi-atom) subroutines used by public functions
    inline void incinner(atom *&);
    inline void decinner(atom *&);
    inline void addinner(const Integer &, atom *&, const atom *&);
    inline void subinner(const Integer &, atom *&, const atom *&);
#ifdef INTEGER_H_FASTDIV
    inline void divbyatom(const atom &, Integer &, Integer &);
    inline void divinner(const Integer &, Integer &, Integer &);
#endif    // INTEGER_H_FASTDIV

    // private wide math (multi-atom) functions used by public functions
    void inc();                         // operator++ prefix
    void dec();                         // operator-- prefix
    void add(const Integer &);          // operator+=
    void sub(const Integer &);          // operator-=
    void mul(const Integer &);          // operator*=
    void div(const Integer &);          // operator/=
    void mod(const Integer &);          // operator%=
    bool equ(const Integer &) const;    // operator== and operator!=
    bool grt(const Integer &) const;    // operator>
    bool gre(const Integer &) const;    // operator>=
    bool let(const Integer &) const;    // operator<
    bool lee(const Integer &) const;    // operator<=

    // private wide math (multi-atom) functions used by private functions
    inline bool largerthan(const Integer &right) const;     // size greaterthan
    inline bool largerorequal(const Integer &right) const;
    inline bool smallerthan(const Integer &right) const;    // size lessthan
    inline bool smallerorequal(const Integer &right) const;

    // private utility functions
    inline void shiftup(atom places);    // append zeros (in base: maxatom+1)
    inline void shiftdown(atom places);  // truncate places (in base: maxatom+1)
};

//#if 0
// functions to help measure code speed (tricks compiler into not optimizing)
void touch(const Integer &);          // empty function, for testing only
void touch(const Integer::atom &);    // empty function, for testing only
//#endif    // 0

// unary math operators (global functions)
inline Integer operator~(const Integer &left);
inline bool operator!(const Integer &left);
inline Integer operator-(const Integer &left);
inline Integer operator+(const Integer &left);

// binary math operators (global functions)
inline Integer operator+(const Integer &left, const Integer &right);
inline Integer operator+(const Integer &left, const Integer::atom &rightatom);
inline Integer operator+(const Integer::atom &leftatom, const Integer &right);
inline Integer operator+(const Integer &left, const Integer::satom &rightatom);
inline Integer operator+(const Integer::satom &leftatom, const Integer &right);
inline Integer operator-(const Integer &left, const Integer &right);
inline Integer operator-(const Integer &left, const Integer::atom &rightatom);
inline Integer operator-(const Integer::atom &leftatom, const Integer &right);
inline Integer operator-(const Integer &left, const Integer::satom &rightatom);
inline Integer operator-(const Integer::satom &leftatom, const Integer &right);
inline Integer operator*(const Integer &left, const Integer &right);
inline Integer operator*(const Integer &left, const Integer::atom &rightatom);
inline Integer operator*(const Integer::atom &leftatom, const Integer &right);
inline Integer operator*(const Integer &left, const Integer::satom &rightatom);
inline Integer operator*(const Integer::satom &leftatom, const Integer &right);
inline Integer operator/(const Integer &left, const Integer &right);
inline Integer operator/(const Integer &left, const Integer::atom &rightatom);
inline Integer operator/(const Integer::atom &leftatom, const Integer &right);
inline Integer operator/(const Integer &left, const Integer::satom &rightatom);
inline Integer operator/(const Integer::satom &leftatom, const Integer &right);
inline Integer operator%(const Integer &left, const Integer &right);
inline Integer operator%(const Integer &left, const Integer::atom &rightatom);
inline Integer operator%(const Integer::atom &leftatom, const Integer &right);
inline Integer operator%(const Integer &left, const Integer::satom &rightatom);
inline Integer operator%(const Integer::satom &leftatom, const Integer &right);
inline bool operator==(const Integer &left, const Integer &right);
inline bool operator==(const Integer &left, const Integer::atom &rightatom);
inline bool operator==(const Integer::atom &leftatom, const Integer &right);
inline bool operator==(const Integer &left, const Integer::satom &rightatom);
inline bool operator==(const Integer::satom &leftatom, const Integer &right);
inline bool operator!=(const Integer &left, const Integer &right);
inline bool operator!=(const Integer &left, const Integer::atom &rightatom);
inline bool operator!=(const Integer::atom &leftatom, const Integer &right);
inline bool operator!=(const Integer &left, const Integer::satom &rightatom);
inline bool operator!=(const Integer::satom &leftatom, const Integer &right);
inline bool operator>(const Integer &left, const Integer &right);
inline bool operator>(const Integer &left, const Integer::atom &rightatom);
inline bool operator>(const Integer::atom &leftatom, const Integer &right);
inline bool operator>(const Integer &left, const Integer::satom &rightatom);
inline bool operator>(const Integer::satom &leftatom, const Integer &right);
inline bool operator>=(const Integer &left, const Integer &right);
inline bool operator>=(const Integer &left, const Integer::atom &rightatom);
inline bool operator>=(const Integer::atom &leftatom, const Integer &right);
inline bool operator>=(const Integer &left, const Integer::satom &rightatom);
inline bool operator>=(const Integer::satom &leftatom, const Integer &right);
inline bool operator<(const Integer &left, const Integer &right);
inline bool operator<(const Integer &left, const Integer::atom &rightatom);
inline bool operator<(const Integer::atom &leftatom, const Integer &right);
inline bool operator<(const Integer &left, const Integer::satom &rightatom);
inline bool operator<(const Integer::satom &leftatom, const Integer &right);
inline bool operator<=(const Integer &left, const Integer &right);
inline bool operator<=(const Integer &left, const Integer::atom &rightatom);
inline bool operator<=(const Integer::atom &leftatom, const Integer &right);
inline bool operator<=(const Integer &left, const Integer::satom &rightatom);
inline bool operator<=(const Integer::satom &leftatom, const Integer &right);
inline bool operator&&(const Integer &left, const Integer &right);
inline bool operator&&(const Integer &left, const bool right);
inline bool operator&&(const bool left, const Integer &right);
inline bool operator||(const Integer &left, const Integer &right);
inline bool operator||(const Integer &left, const bool right);
inline bool operator||(const bool left, const Integer &right);
inline ostream &operator<<(ostream &, const Integer &);
inline void swap(Integer &, Integer &);
inline Integer abs(const Integer &);
inline Integer min(const Integer &, const Integer &);
inline Integer max(const Integer &, const Integer &);
inline Integer fac(const Integer &);
inline Integer pow(const Integer &, const Integer &);

#ifdef INTEGER_H_INITZERO
inline
Integer::Integer()
: memorysize_(1), negative_(false)
{
    memory_.fast = 0;
}
#else
inline
Integer::Integer()
: memorysize_(1)
{
}
#endif    // INTEGER_H_INITZERO

inline
Integer::Integer(Integer::sign s, Integer::atom a)
: memorysize_(1), negative_(s == negative && a != 0)
{
    memory_.fast = a;
}

#ifndef INTEGER_H_DECIMAL
inline
Integer::Integer(Integer::atom a)
: memorysize_(1), negative_(false)
{
    memory_.fast = a;
}
#else
inline
Integer::Integer(Integer::atom a)
: negative_(false)
{
    if (a <= maxatom_)
    {
        memorysize_ = 1;
        memory_.fast = a;
    }
    else
    {
        atom digits = 1;
        atom tempa;
        for (tempa = a; tempa > maxatom_; tempa /= maxatom_ + 1)
            ++digits;
        atom *newmemory = new atom[digits];
        atom count;
        tempa = a;
        for (count = 0; count < digits; ++count)
        {
            newmemory[count] = tempa % (maxatom_ + 1);
            tempa /= maxatom_ + 1;
        }
        memorysize_ = digits;
        memory_.slow = newmemory;
    }
}
#endif    // INTEGER_H_DECIMAL

inline
Integer::Integer(Integer::satom i)
{
#ifndef INTEGER_H_FAKEBITS
    if (i >= 0)
    {
        memorysize_ = 1;
        memory_.fast = i;
        negative_ = false;
        return;
    }
    else
    {
        // test correctness of the hardware negation operation
        Integer::satom a = i, b = i;
        b = -b;
        Integer::satom c = a + b;
        if (c == 0)
        {
            memorysize_ = 1;
            memory_.fast = b;
            negative_ = true;
            return;
        }
    }

    throw outofrange();    // what is this crazy hardware?

    // NOTE: One of the most confusing things about signed integers is that on
    //       most systems (two's-complement systems) there are a different
    //       number of positive numbers available than negative ones.  So this
    //       constructor can not simply invert the sign of negative int numbers
    //       passed to it or it will not be portable, it must go thru
    //       contortions to preserve both the magnitude and the sign.  Imagine
    //       the case where -32768 is passed in but where the highest positive
    //       number able to be stored in a signed int is 32767 (this case
    //       happens to be true for 16-bit signed ints on most PCs) so
    //       inverting the -32768 sign will not work or could even crash.  ANSI
    //       C++ does not define the result, but on my x86 PC it happens that
    //       -(-32768) is equal to (-32768), clearly unacceptable.  Similarly
    //       for 32-bit ints... -(-2147483648) == (-2147483648).

#else    // INTEGER_H_FAKEBITS

    throw outofrange();

#endif    // INTEGER_H_FAKEBITS
}

inline
Integer::Integer(const Integer &other)
: memorysize_(other.memorysize_), negative_(other.negative_)
{
    if (memorysize_ == 1)
        memory_.fast = other.memory_.fast;
    else    // FIXME: make a function call to this smarter logic
    {
        memory_.slow = new atom[memorysize_];
        for (atom a = 0; a < memorysize_; ++a)
            memory_.slow[a] = other.memory_.slow[a];
    }
}

inline
Integer::~Integer()
{
    // (minor) FIXME: use function call here if shorter than delete [] for x86?
    if (memorysize_ > 1) delete [] memory_.slow;
}

inline
Integer::operator bool() const
{
    if (memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (memory_.fast == 0)
            return false;
        else
            return true;
    }
    return true;    // zero is always stored within one memory location
}

inline
Integer::operator signed int() const
{    // FIXME: this is not portable but should work on most computers for now
    if (memorysize_ != 1) throw outofrange();
    signed int i = memory_.fast;
    if (i < 0) throw outofrange();
    return i;
}

inline
Integer::operator unsigned int() const
{
#ifndef INTEGER_H_FAKEBITS
    // FIXME: is this correct when atom is not an unsigned int?
    if (memorysize_ != 1) throw outofrange();
    return memory_.fast;
#else    // INTEGER_H_FAKEBITS
    atom base = maxatom_ + 1;
    atom result = 0, shift = 0, a, loop;
    Integer i = *this;
    for (;;)
    {
        if (i.memorysize_ == 1)
            a = i.memory_.fast;
        else
            a = i.memory_.slow[0];
        for (loop = 0; loop < shift; ++loop)
        {
            if (a > truemaxatom_ / base) throw outofrange();
            a *= base;
        }
        if (result > truemaxatom_ - a) throw outofrange();
        result += a;
        if (i.memorysize_ == 1) return result;
        i.shiftdown(1);
        ++shift;
    }
#endif    // INTEGER_H_FAKEBITS
}

inline Integer &
Integer::operator++()    // prefix
{
    if (memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (!negative_)
        {
            atom &leftatom = memory_.fast;
            if (leftatom < maxatom_)    // overflow prediction
            {
                ++leftatom;
                return *this;
            }
        }
        else
        {
            atom &leftatom = memory_.fast;
            --leftatom;
            if (leftatom == 0) negative_ = false;
            return *this;
        }
    }
    inc();    // fall back to slow multi-atom case
    return *this;
}

inline Integer
Integer::operator++(int)    // postfix
{
    Integer result = *this;
    this->operator++();
    return result;
}

inline Integer &
Integer::operator--()    // prefix
{
    if (memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (negative_)
        {
            atom &leftatom = memory_.fast;
            if (leftatom < maxatom_)    // overflow prediction
            {
                ++leftatom;
                return *this;
            }
        }
        else
        {
            atom &leftatom = memory_.fast;
            if (leftatom != 0)    // underflow prediction
            {
                --leftatom;
                if (leftatom == 0) negative_ = false;
                return *this;
            }
            else
            {
                leftatom = 1U;
                negative_ = true;
                return *this;
            }
        }
    }
    dec();    // fall back to slow multi-atom case
    return *this;
}

inline Integer
Integer::operator--(int)    // postfix
{
    Integer result = *this;
    this->operator--();
    return result;
}

inline Integer &
Integer::operator=(const Integer &right)
{
    if (right.memorysize_ == 1)
    {
        if (memorysize_ > 1) delete [] memory_.slow;
        memorysize_ = right.memorysize_;
        negative_ = right.negative_;
        memory_.fast = right.memory_.fast;
    }
    else    // FIXME: make a function call to this smarter logic
    {
        if (memory_.slow != right.memory_.slow)    // catch assignment to self
        {
            if (memorysize_ > 1) delete [] memory_.slow;
            memorysize_ = right.memorysize_;
            negative_ = right.negative_;
            memory_.slow = new atom[memorysize_];
            for (atom a = 0; a < memorysize_; ++a)
                memory_.slow[a] = right.memory_.slow[a];
        }
    }
    return *this;
}

inline Integer &
Integer::operator=(const atom &rightatom)
{
    if (memorysize_ > 1) delete [] memory_.slow;
    memorysize_ = 1;
    negative_ = false;

#ifndef INTEGER_H_FAKEBITS
    memory_.fast = rightatom;
#else    // INTEGER_H_FAKEBITS
    if (rightatom <= maxatom_)
    {
        memory_.fast = rightatom;
    }
    else
    {
        memory_.fast = 0;
        atom base = maxatom_ + 1;
        atom shift = 0;
        atom a = rightatom;
        Integer i = 0;
        while (a > maxatom_)
        {
            i = (a % base);
            i.shiftup(shift);
            *this += i;
            a /= base;
            ++shift;
        }
    }
#endif    // INTEGER_H_FAKEBITS

    return *this;
}

inline Integer &
Integer::operator=(const satom &rightatom)
{
    return *this = Integer(rightatom);
}

inline Integer &
Integer::operator+=(const Integer &right)
{
    if (memorysize_ == 1 &&
        right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (negative_ == right.negative_)
        {
            atom &leftatom = memory_.fast;
            const atom &rightatom = right.memory_.fast;
            if (leftatom <= maxatom_ - rightatom)    // overflow prediction
            {
                leftatom += rightatom;
                return *this;
            }
        }
        else
        {
            atom &leftatom = memory_.fast;
            const atom &rightatom = right.memory_.fast;
            if (leftatom >= rightatom)    // underflow prediction
            {
                leftatom -= rightatom;
                if (leftatom == 0)
                    negative_ = false;
                return *this;
            }
            else
            {
                leftatom = rightatom - leftatom;
                negative_ = !negative_;
                return *this;
            }
        }
    }
    add(right);    // fall back to slow multi-atom case
    return *this;
}

inline Integer &
Integer::operator+=(const atom &rightatom)
{
    if (memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (!negative_)
        {
            atom &leftatom = memory_.fast;
            if (leftatom <= maxatom_ - rightatom)    // overflow prediction
            {
                leftatom += rightatom;
                return *this;
            }
        }
        else
        {
            atom &leftatom = memory_.fast;
            if (leftatom >= rightatom)    // underflow prediction
            {
                leftatom -= rightatom;
                if (leftatom == 0)
                    negative_ = false;
                return *this;
            }
            else
            {
                leftatom = rightatom - leftatom;
                negative_ = !negative_;
                return *this;
            }
        }
    }
    add(Integer(rightatom));    // fall back to slow multi-atom case
    return *this;
}

inline Integer &
Integer::operator+=(const satom &rightatom)
{
    return *this += Integer(rightatom);
}

inline Integer &
Integer::operator-=(const Integer &right)
{
    if (memorysize_ == 1 &&
        right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (negative_ != right.negative_)
        {
            atom &leftatom = memory_.fast;
            const atom &rightatom = right.memory_.fast;
            if (leftatom <= maxatom_ - rightatom)    // overflow prediction
            {
                leftatom += rightatom;
                return *this;
            }
        }
        else
        {
            atom &leftatom = memory_.fast;
            const atom &rightatom = right.memory_.fast;
            if (leftatom >= rightatom)    // underflow prediction
            {
                leftatom -= rightatom;
                if (leftatom == 0)
                    negative_ = false;
                return *this;
            }
            else
            {
                leftatom = rightatom - leftatom;
                negative_ = !negative_;
                return *this;
            }
        }
    }
    sub(right);    // fall back to slow multi-atom case
    return *this;
}

inline Integer &
Integer::operator-=(const atom &rightatom)
{
    if (memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (negative_)
        {
            atom &leftatom = memory_.fast;
            if (leftatom <= maxatom_ - rightatom)    // overflow prediction
            {
                leftatom += rightatom;
                return *this;
            }
        }
        else
        {
            atom &leftatom = memory_.fast;
            if (leftatom >= rightatom)    // underflow prediction
            {
                leftatom -= rightatom;
                if (leftatom == 0)
                    negative_ = false;
                return *this;
            }
            else
            {
                leftatom = rightatom - leftatom;
                negative_ = !negative_;
                return *this;
            }
        }
    }
    sub(Integer(rightatom));    // fall back to slow multi-atom case
    return *this;
}

inline Integer &
Integer::operator-=(const satom &rightatom)
{
    return *this -= Integer(rightatom);
}

inline Integer &
Integer::operator*=(const Integer &right)
{
    if (memorysize_ == 1 &&
        right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        atom &leftatom = memory_.fast;
        const atom &rightatom = right.memory_.fast;
        if (rightatom == 0 || leftatom <= maxatom_ / rightatom)
        {                                               // overflow prediction
            leftatom *= rightatom;
            if (leftatom == 0)
                negative_ = false;
            else if (right.negative_)
                negative_ = !negative_;
            return *this;
        }
    }
    mul(right);    // fall back to slow multi-atom case
    return *this;
}

inline Integer &
Integer::operator*=(const atom &rightatom)
{
    if (memorysize_ == 1)    // optimize for fast single-atom case
    {
        atom &leftatom = memory_.fast;
        if (rightatom == 0 || leftatom <= maxatom_ / rightatom)
        {                                               // overflow prediction
            leftatom *= rightatom;
            if (leftatom == 0)
                negative_ = false;
            return *this;
        }
    }
    mul(Integer(rightatom));    // fall back to slow multi-atom case
    return *this;
}

inline Integer &
Integer::operator*=(const satom &rightatom)
{
    return *this *= Integer(rightatom);
}

inline Integer &
Integer::operator/=(const Integer &right)
{
    if (memorysize_ == 1 &&
        right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        atom &leftatom = memory_.fast;
        const atom &rightatom = right.memory_.fast;
        if (rightatom != 0)    // division by zero prediction
        {
            leftatom /= rightatom;
            if (leftatom == 0)
                negative_ = false;
            else if (right.negative_)
                negative_ = !negative_;
            return *this;
        }
        else
        {
//            if (leftatom == 0)    // dividing zero by zero is okay
//                return *this;
            throw divisionbyzero();
        }
    }
    div(right);    // fall back to slow multi-atom case
    return *this;
}

inline Integer &
Integer::operator/=(const atom &rightatom)
{
    if (memorysize_ == 1)    // optimize for fast single-atom case
    {
        atom &leftatom = memory_.fast;
        if (rightatom != 0)    // division by zero prediction
        {
            leftatom /= rightatom;
            if (leftatom == 0)
                negative_ = false;
            return *this;
        }
        else
        {
//            if (leftatom == 0)    // dividing zero by zero is okay
//                return *this;
            throw divisionbyzero();
        }
    }
    div(Integer(rightatom));    // fall back to slow multi-atom case
    return *this;
}

inline Integer &
Integer::operator/=(const satom &rightatom)
{
    return *this /= Integer(rightatom);
}

inline Integer &
Integer::operator%=(const Integer &right)
{
    if (memorysize_ == 1 &&
        right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        atom &leftatom = memory_.fast;
        const atom &rightatom = right.memory_.fast;
        if (rightatom != 0)    // division by zero prediction
        {
            leftatom %= rightatom;
            if (leftatom == 0)
                negative_ = false;
            return *this;
        }
        else
        {
//            if (leftatom == 0)    // dividing zero by zero is okay
//                return *this;
            throw divisionbyzero();
        }
    }
    mod(right);    // fall back to slow multi-atom case
    return *this;
}

inline Integer &
Integer::operator%=(const atom &rightatom)
{
    if (memorysize_ == 1)    // optimize for fast single-atom case
    {
        atom &leftatom = memory_.fast;
        if (rightatom != 0)    // division by zero prediction
        {
            leftatom %= rightatom;
            if (leftatom == 0)
                negative_ = false;
            return *this;
        }
        else
        {
//            if (leftatom == 0)    // dividing zero by zero is okay
//                return *this;
            throw divisionbyzero();
        }
    }
    mod(Integer(rightatom));    // fall back to slow multi-atom case
    return *this;
}

inline Integer &
Integer::operator%=(const satom &rightatom)
{
    return *this %= Integer(rightatom);
}

inline Integer
operator~(const Integer &left)    // FIXME see integer.txt complement info
{
    Integer result = left;

    if (result.memorysize_ == 1)    // optimize for fast single-atom case
    {
#ifndef INTEGER_H_DECIMAL
        result.memory_.fast = ~result.memory_.fast;
        return result;
#else
        result.memory_.fast = Integer::maxatom_;
        result.memory_.fast -= left.memory_.fast;
        return result;
#endif    // INTEGER_H_DECIMAL
    }

    Integer::atom a = 0;
    for (; a < result.memorysize_; ++a)
#ifndef INTEGER_H_DECIMAL
        result.memory_.slow[a] = ~result.memory_.slow[a];
#else
    {
        result.memory_.slow[a] = Integer::maxatom_;
        result.memory_.slow[a] -= left.memory_.slow[a];
    }
#endif    // INTEGER_H_DECIMAL
    return result;
}

inline bool
operator!(const Integer &left)
{
    if (left.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (!left.memory_.fast)
            return false;
        else
            return true;
    }
    Integer right = 0U;
    return !left.equ(right);    // fall back to slow multi-atom case
}

inline Integer
operator-(const Integer &left)
{
    Integer result = left;
    if (result.memorysize_ == 1 && result.memory_.fast == 0)
        result.negative_ = false;
    else
        result.negative_ = !result.negative_;
    return result;
}

inline Integer
operator+(const Integer &left)
{
    Integer result = left;
    return result;
}

inline Integer
operator+(const Integer &left, const Integer &right)
{
    Integer result = left;
    result += right;
    return result;
}

inline Integer
operator+(const Integer &left, const Integer::atom &rightatom)
{
    Integer result = left;
    result += rightatom;
    return result;
}

inline Integer
operator+(const Integer::atom &leftatom, const Integer &right)
{
    Integer result = leftatom;
    result += right;
    return result;
}

inline Integer
operator+(const Integer &left, const Integer::satom &rightatom)
{
    Integer result = left;
    result += rightatom;
    return result;
}

inline Integer
operator+(const Integer::satom &leftatom, const Integer &right)
{
    Integer result = leftatom;
    result += right;
    return result;
}

inline Integer
operator-(const Integer &left, const Integer &right)
{
    Integer result = left;
    result -= right;
    return result;
}

inline Integer
operator-(const Integer &left, const Integer::atom &rightatom)
{
    Integer result = left;
    result -= rightatom;
    return result;
}

inline Integer
operator-(const Integer::atom &leftatom, const Integer &right)
{
    Integer result = leftatom;
    result -= right;
    return result;
}

inline Integer
operator-(const Integer &left, const Integer::satom &rightatom)
{
    Integer result = left;
    result -= rightatom;
    return result;
}

inline Integer
operator-(const Integer::satom &leftatom, const Integer &right)
{
    Integer result = leftatom;
    result -= right;
    return result;
}

inline Integer
operator*(const Integer &left, const Integer &right)
{
    Integer result = left;
    result *= right;
    return result;
}

inline Integer
operator*(const Integer &left, const Integer::atom &rightatom)
{
    Integer result = left;
    result *= rightatom;
    return result;
}

inline Integer
operator*(const Integer::atom &leftatom, const Integer &right)
{
    Integer result = leftatom;
    result *= right;
    return result;
}

inline Integer
operator*(const Integer &left, const Integer::satom &rightatom)
{
    Integer result = left;
    result *= rightatom;
    return result;
}

inline Integer
operator*(const Integer::satom &leftatom, const Integer &right)
{
    Integer result = leftatom;
    result *= right;
    return result;
}

inline Integer
operator/(const Integer &left, const Integer &right)
{
    Integer result = left;
    result /= right;
    return result;
}

inline Integer
operator/(const Integer &left, const Integer::atom &rightatom)
{
    Integer result = left;
    result /= rightatom;
    return result;
}

inline Integer
operator/(const Integer::atom &leftatom, const Integer &right)
{
    Integer result = leftatom;
    result /= right;
    return result;
}

inline Integer
operator/(const Integer &left, const Integer::satom &rightatom)
{
    Integer result = left;
    result /= rightatom;
    return result;
}

inline Integer
operator/(const Integer::satom &leftatom, const Integer &right)
{
    Integer result = leftatom;
    result /= right;
    return result;
}

inline Integer
operator%(const Integer &left, const Integer &right)
{
    Integer result = left;
    result %= right;
    return result;
}

inline Integer
operator%(const Integer &left, const Integer::atom &rightatom)
{
    Integer result = left;
    result %= rightatom;
    return result;
}

inline Integer
operator%(const Integer::atom &leftatom, const Integer &right)
{
    Integer result = leftatom;
    result %= right;
    return result;
}

inline Integer
operator%(const Integer &left, const Integer::satom &rightatom)
{
    Integer result = left;
    result %= rightatom;
    return result;
}

inline Integer
operator%(const Integer::satom &leftatom, const Integer &right)
{
    Integer result = leftatom;
    result %= right;
    return result;
}

inline bool
operator==(const Integer &left, const Integer &right)
{
    if (left.memorysize_ == 1 &&
        right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (left.negative_ != right.negative_)
            return false;
        return left.memory_.fast == right.memory_.fast;
    }
    return left.equ(right);    // fall back to slow multi-atom case
}

inline bool
operator==(const Integer &left, const Integer::atom &rightatom)
{
#ifndef INTEGER_H_FAKEBITS
    if (left.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (left.negative_)
            return false;
        else
            return left.memory_.fast == rightatom;
    }
    Integer right = rightatom;
    return left.equ(right);    // fall back to slow multi-atom case
#else    // INTEGER_H_FAKEBITS
    return left == Integer(rightatom);
#endif    // INTEGER_H_FAKEBITS
}

inline bool
operator==(const Integer::atom &leftatom, const Integer &right)
{
#ifndef INTEGER_H_FAKEBITS
    if (right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (right.negative_)
            return false;
        else
            return leftatom == right.memory_.fast;
    }
    Integer left = leftatom;
    return left.equ(right);    // fall back to slow multi-atom case
#else    // INTEGER_H_FAKEBITS
    return Integer(leftatom) == right;
#endif    // INTEGER_H_FAKEBITS
}

inline bool
operator==(const Integer &left, const Integer::satom &rightatom)
{
    return left == Integer(rightatom);
}

inline bool
operator==(const Integer::satom &leftatom, const Integer &right)
{
    return Integer(leftatom) == right;
}

inline bool
operator!=(const Integer &left, const Integer &right)
{
    if (left.memorysize_ == 1 &&
        right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (left.negative_ != right.negative_)
            return true;
        return left.memory_.fast != right.memory_.fast;
    }
    return !left.equ(right);    // fall back to slow multi-atom case
}

inline bool
operator!=(const Integer &left, const Integer::atom &rightatom)
{
#ifndef INTEGER_H_FAKEBITS
    if (left.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (left.negative_)
            return true;
        else
            return left.memory_.fast != rightatom;
    }
    Integer right = rightatom;
    return !left.equ(right);    // fall back to slow multi-atom case
#else    // INTEGER_H_FAKEBITS
    return left != Integer(rightatom);
#endif    // INTEGER_H_FAKEBITS
}

inline bool
operator!=(const Integer::atom &leftatom, const Integer &right)
{
#ifndef INTEGER_H_FAKEBITS
    if (right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (right.negative_)
            return true;
        else
            return leftatom != right.memory_.fast;
    }
    Integer left = leftatom;
    return !left.equ(right);    // fall back to slow multi-atom case
#else    // INTEGER_H_FAKEBITS
    return Integer(leftatom) != right;
#endif    // INTEGER_H_FAKEBITS
}

inline bool
operator!=(const Integer &left, const Integer::satom &rightatom)
{
    return left != Integer(rightatom);
}

inline bool
operator!=(const Integer::satom &leftatom, const Integer &right)
{
    return Integer(leftatom) != right;
}

inline bool
operator>(const Integer &left, const Integer &right)
{
    if (left.memorysize_ == 1 &&
        right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (left.negative_ != right.negative_)
            return !left.negative_;
        if (!left.negative_)
            return left.memory_.fast > right.memory_.fast;
        else
            return left.memory_.fast < right.memory_.fast;
    }
    return left.grt(right);    // fall back to slow multi-atom case
}

inline bool
operator>(const Integer &left, const Integer::atom &rightatom)
{
#ifndef INTEGER_H_FAKEBITS
    if (left.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (left.negative_)
            return false;
        else
            return left.memory_.fast > rightatom;
    }
    Integer right = rightatom;
    return left.grt(right);    // fall back to slow multi-atom case
#else    // INTEGER_H_FAKEBITS
    return left > Integer(rightatom);
#endif    // INTEGER_H_FAKEBITS
}

inline bool
operator>(const Integer::atom &leftatom, const Integer &right)
{
#ifndef INTEGER_H_FAKEBITS
    if (right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (right.negative_)
            return true;
        else
            return leftatom > right.memory_.fast;
    }
    Integer left = leftatom;
    return left.grt(right);    // fall back to slow multi-atom case
#else    // INTEGER_H_FAKEBITS
    return Integer(leftatom) > right;
#endif    // INTEGER_H_FAKEBITS
}

inline bool
operator>(const Integer &left, const Integer::satom &rightatom)
{
    return left > Integer(rightatom);
}

inline bool
operator>(const Integer::satom &leftatom, const Integer &right)
{
    return Integer(leftatom) > right;
}

inline bool
operator>=(const Integer &left, const Integer &right)
{
    if (left.memorysize_ == 1 &&
        right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (left.negative_ != right.negative_)
            return !left.negative_;
        if (!left.negative_)
            return left.memory_.fast >= right.memory_.fast;
        else
            return left.memory_.fast <= right.memory_.fast;
    }
    return left.gre(right);    // fall back to slow multi-atom case
}

inline bool
operator>=(const Integer &left, const Integer::atom &rightatom)
{
#ifndef INTEGER_H_FAKEBITS
    if (left.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (left.negative_)
            return false;
        else
            return left.memory_.fast >= rightatom;
    }
    Integer right = rightatom;
    return left.gre(right);    // fall back to slow multi-atom case
#else    // INTEGER_H_FAKEBITS
    return left >= Integer(rightatom);
#endif    // INTEGER_H_FAKEBITS
}

inline bool
operator>=(const Integer::atom &leftatom, const Integer &right)
{
#ifndef INTEGER_H_FAKEBITS
    if (right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (right.negative_)
            return true;
        else
            return leftatom >= right.memory_.fast;
    }
    Integer left = leftatom;
    return left.gre(right);    // fall back to slow multi-atom case
#else    // INTEGER_H_FAKEBITS
    return Integer(leftatom) == right;
#endif    // INTEGER_H_FAKEBITS
}

inline bool
operator>=(const Integer &left, const Integer::satom &rightatom)
{
    return left >= Integer(rightatom);
}

inline bool
operator>=(const Integer::satom &leftatom, const Integer &right)
{
    return Integer(leftatom) == right;
}

inline bool
operator<(const Integer &left, const Integer &right)
{
    if (left.memorysize_ == 1 &&
        right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (left.negative_ != right.negative_)
            return left.negative_;
        if (!left.negative_)
            return left.memory_.fast < right.memory_.fast;
        else
            return left.memory_.fast > right.memory_.fast;
    }
    return left.let(right);    // fall back to slow multi-atom case
}

inline bool
operator<(const Integer &left, const Integer::atom &rightatom)
{
#ifndef INTEGER_H_FAKEBITS
    if (left.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (left.negative_)
            return true;
        else
            return left.memory_.fast < rightatom;
    }
    Integer right = rightatom;
    return left.let(right);    // fall back to slow multi-atom case
#else    // INTEGER_H_FAKEBITS
    return left < Integer(rightatom);
#endif    // INTEGER_H_FAKEBITS
}

inline bool
operator<(const Integer::atom &leftatom, const Integer &right)
{
#ifndef INTEGER_H_FAKEBITS
    if (right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (right.negative_)
            return false;
        else
            return leftatom < right.memory_.fast;
    }
    Integer left = leftatom;
    return left.let(right);    // fall back to slow multi-atom case
#else    // INTEGER_H_FAKEBITS
    return Integer(leftatom) == right;
#endif    // INTEGER_H_FAKEBITS
}

inline bool
operator<(const Integer &left, const Integer::satom &rightatom)
{
    return left < Integer(rightatom);
}

inline bool
operator<(const Integer::satom &leftatom, const Integer &right)
{
    return Integer(leftatom) == right;
}

inline bool
operator<=(const Integer &left, const Integer &right)
{
    if (left.memorysize_ == 1 &&
        right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (left.negative_ != right.negative_)
            return left.negative_;
        if (!left.negative_)
            return left.memory_.fast <= right.memory_.fast;
        else
            return left.memory_.fast >= right.memory_.fast;
    }
    return left.lee(right);    // fall back to slow multi-atom case
}

inline bool
operator<=(const Integer &left, const Integer::atom &rightatom)
{
#ifndef INTEGER_H_FAKEBITS
    if (left.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (left.negative_)
            return true;
        else
            return left.memory_.fast <= rightatom;
    }
    Integer right = rightatom;
    return left.lee(right);    // fall back to slow multi-atom case
#else    // INTEGER_H_FAKEBITS
    return left <= Integer(rightatom);
#endif    // INTEGER_H_FAKEBITS
}

inline bool
operator<=(const Integer::atom &leftatom, const Integer &right)
{
#ifndef INTEGER_H_FAKEBITS
    if (right.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (right.negative_)
            return false;
        else
            return leftatom <= right.memory_.fast;
    }
    Integer left = leftatom;
    return left.lee(right);    // fall back to slow multi-atom case
#else    // INTEGER_H_FAKEBITS
    return Integer(leftatom) <= right;
#endif    // INTEGER_H_FAKEBITS
}

inline bool
operator<=(const Integer &left, const Integer::satom &rightatom)
{
    return left <= Integer(rightatom);
}

inline bool
operator<=(const Integer::satom &leftatom, const Integer &right)
{
    return Integer(leftatom) <= right;
}

inline bool
operator&&(const Integer &left, const Integer &right)
{
    return (bool)left && (bool)right;
}

inline bool
operator&&(const Integer &left, const bool right)
{
    return (bool)left && right;
}

inline bool
operator&&(const bool left, const Integer &right)
{
    return left && (bool)right;
}

inline bool
operator||(const Integer &left, const Integer &right)
{
    return (bool)left || (bool)right;
}

inline bool
operator||(const Integer &left, const bool right)
{
    return (bool)left || right;
}

inline bool
operator||(const bool left, const Integer &right)
{
    return left || (bool)right;
}

//#include <unistd.h>    // FIXME:  delete this line?

inline ostream &
operator<<(ostream &s, const Integer &i)    // FIXME:  needs io manips?
{
    if (i.memorysize_ == 1)    // optimize for fast single-atom case
    {
        if (i.negative_)
            s << "-";
        return s << i.memory_.fast;
    }

    char *output;
    output = i.ascii();    // FIXME: this defaults allowing base 10 output only
    s << output;

    delete [] output;
    return s;


#ifdef BETTERCODE
    const Integer base = 10U;
    Integer i2, digits = 1U;
    for (i2 = i; i2 >= base; i2 /= base)    // FIXME: incorrectly optimized
        digits++;
    const unsigned int fastresultsize = 100;
    unsigned char fastresult[fastresultsize];
    unsigned char *result;
    if (digits > fastresultsize)
        result = new unsigned char[(Integer::atom)digits];
        // FIXME: previous line can go out of range
    else
        result = fastresult;
    Integer::atom place = digits;
    for (i2 = i; i2 >= base; i2 /= base)
        result[--place] = ((Integer::atom)(i2 % base));
    result[--place] = ((Integer::atom)i2);
    for (; place < digits; ++place)
        s << (unsigned char)(result[place] + '0');
    if (digits > fastresultsize)
        delete [] result;
#endif    // BETTERCODE
}

inline void
swap(Integer &left, Integer &right)
{
    bool negative = right.negative_;
    right.negative_ = left.negative_;
    left.negative_ = negative;

    Integer::atom memorysize = right.memorysize_;
    right.memorysize_ = left.memorysize_;
    left.memorysize_ = memorysize;

    Integer::optimizedmemory_ memory;
    if (memorysize == 1)
        memory.fast = right.memory_.fast;
    else
        memory.slow = right.memory_.slow;
    if (right.memorysize_ == 1)
        right.memory_.fast = left.memory_.fast;
    else
        right.memory_.slow = left.memory_.slow;
    if (left.memorysize_ == 1)
        left.memory_.fast = memory.fast;
    else
        left.memory_.slow = memory.slow;
}

inline Integer
abs(const Integer &other)
{
    Integer result = other;
    if (result.negative_) result.negative_ = false;
    return result;
}

inline Integer
min(const Integer &left, const Integer &right)
{
    if (left < right)
        return left;
    else
        return right;
}

inline Integer
max(const Integer &left, const Integer &right)
{
    if (left > right)
        return left;
    else
        return right;
}

inline Integer
fac(const Integer &value)
{
    if (value < 0) throw Integer::negativefactorial();
    Integer result = 1;
    if (value > 1)
    {
        Integer next = value;
        do
        {
            result *= next;
            --next;
        }
        while (next > 1);
    }
    return result;
}

inline Integer
pow(const Integer &value, const Integer &exponent)
{
    if (exponent == 0) return 1;
    Integer result = value;
    Integer count = abs(exponent);
    for (--count; count > 0; --count)
        result *= value;
    if (exponent < 0) return 1 / result;    // always rounds to zero!
    return result;
}

inline    // FIXME: probably should not be inline?
Integer::Integer(const char *asciiz)
{
    // FIXME: decimal string assumed, need to allow base 2, 8, 16, etc.
    // FIXME: also need to check that the base is not larger than maxatom

    memorysize_ = 1;
    negative_ = false;
    memory_.fast = 0;

    unsigned long len = 0;
    for (; asciiz[len] != 0; ++len)
        if (asciiz[len] == ' ') throw badstring();    // no spaces allowed
    if (len == 0) throw badstring();

    Integer &result = *this, digit, shift, i2;
    unsigned long i = len - 1;
    Integer::atom value;
    for (;; i--)
    {
        if (asciiz[i] == '-')    // FIXME: what is this crap?
        {
            if (result.memorysize_ != 1 || result.memory_.fast != 0)
                result.negative_ = true;
            break;
        }
        value = asciiz[i] - '0';
        shift = 1;
        for (i2 = 0; i2 < digit; i2++)
            shift *= 10;    // FIXME: only works for base 10 strings
        result += Integer(value) * shift;
        ++digit;
        if (i == 0) break;
    }

//    memorysize_ = 1;
//    *this = result;
}

#ifdef PURENUM_SETTING_INT_DEFAULT
typedef Integer Int;
#endif    // PURENUM_SETTING_INT_DEFAULT

#undef EX

#endif    // INTEGER_H



syntax highlighted by Code2HTML, v. 0.9.1