# int128_t

## Introduction

The int128_t module implements the int128_t and uint128_t integer data types via C++ classes. These types are largely identical in behavior to how a compiler's built-in int128_t / uint128_t would be. These classes exist because compilers don't provide true 128 bit data types. The most you'll typically see from a compiler is int64_t / uint64_t.

128 bit integers are useful for things such as the following:

- Storing very large numbers or bitfields. This can be useful when attempting to simulate city or world economies, for example.
- Implementing 64 * 64 bit multiplication without losing data.
- Implementing very precise fixed point mathematics.

## Example usage

For the most part, you can use int128_t the same way you would use int64_t.

Mixed integer math expressions:

    int            a(17);
    short          b(26);
    int128_t       c(45);
    int64_t        d(77);
    unsigned short e(25);
    uint128_t      x(13);
    uint128_t      y;

    y = (((x + (a + b) * 37) / c) * x) % (d + e);

Logical expressions:

    uint128_t x;
    uint128_t y("0x11111111000100001111111100000001", 16);   // Assign a full 128 bit value of base 16 via a string.
    uint128_t z("0x22222222000100002222222200000001", 16);

    x = (y ^ z) + (y & z) + (y | z);

Floating point:

    uint128_t x = 143249.f;
    x *= 32245.6f

    printf("%f", x.AsFloat());

Mixture of int128_t and uint128_t:

    int128_t  x(-1000000000);
    uint128_t y(120);

    x *= y;

Converting int128_t to a string:

    char     buffer[64];
    int128_t x = 10345;

    s.Int128ToStr(buffer, NULL, 10); // Just like strtol().

Set int128_t as a very large value from a string:

    uint128_t x("141183460469231731687303715884105728");

Set int128_t as a very large value from two 64 bit values:

    uint128_t x(0x1122334455667788);
    x <<= 64;
    x |= 0x8877665544332211;

## Limitations

The primary differences between our int128_t and a hypothetical built-in version are:

- int128_t doesn't implement cast operators to lesser integer types. Instead, provides explicit converters such as AsInt32, AsInt64, etc. This is by design, as such casting operators result in ambiguous conversions and would need built-in compiler knowledge to resolve the situation.
- Standard library functions such as sprintf have no support for such 128 bit types. We partially rectify this by providing StrToInt128 and Int128ToStr functions.
- 128 bit contant literals aren't supported by the compiler, so we implement them via strings (and indirectly via shifting). You can assign an 8 through 64 bit integral constant to int128_t, but if you want to assign a full 128 bit constant to an int128_t, you'll need to use a string or use two 64 bit constants, one for low and one for high.

## Interface

    class int128_t
    {
    public:
        int128_t();
        int128_t(uint32_t nPart0, uint32_t nPart1, uint32_t nPart2, uint32_t nPart3);
        int128_t(uint64_t nPart0, uint64_t nPart1);

        int128_t(int8_t value);
        int128_t(uint8_t value);

        int128_t(int16_t value);
        int128_t(uint16_t value);

        int128_t(int32_t value);
        int128_t(uint32_t value);

        int128_t(int64_t value);
        int128_t(uint64_t value);

        int128_t(const int128_t& value);

        int128_t(const float value);
        int128_t(const double value);

        int128_t(const char* pValue, int nBase = 10);
        int128_t(const wchar_t* pValue, int nBase = 10);

        // Assignment operator
        int128_t& operator=(const int128_t_base& value);

        // Unary arithmetic/logic operators
        int128_t  operator-() const;
        int128_t& operator++();
        int128_t& operator--();
        int128_t  operator++(int);
        int128_t  operator--(int);
        int128_t  operator~() const;
        int128_t  operator+() const;

        // Math operators
        friend int128_t operator+(const int128_t& value1, const int128_t& value2);
        friend int128_t operator-(const int128_t& value1, const int128_t& value2);
        friend int128_t operator*(const int128_t& value1, const int128_t& value2);
        friend int128_t operator/(const int128_t& value1, const int128_t& value2);
        friend int128_t operator%(const int128_t& value1, const int128_t& value2);

        int128_t& operator+=(const int128_t& value);
        int128_t& operator-=(const int128_t& value);
        int128_t& operator*=(const int128_t& value);
        int128_t& operator/=(const int128_t& value);
        int128_t& operator%=(const int128_t& value);

        // Shift operators
        int128_t  operator>> (int nShift) const;
        int128_t  operator<< (int nShift) const;
        int128_t& operator>>=(int nShift);
        int128_t& operator<<=(int nShift);

        // Logical operators
        friend int128_t operator^(const int128_t& value1, const int128_t& value2);
        friend int128_t operator|(const int128_t& value1, const int128_t& value2);
        friend int128_t operator&(const int128_t& value1, const int128_t& value2);

        int128_t& operator^= (const int128_t& value);
        int128_t& operator|= (const int128_t& value);
        int128_t& operator&= (const int128_t& value);

        // Equality operators
        friend int  compare   (const int128_t& value1, const int128_t& value2);
        friend bool operator==(const int128_t& value1, const int128_t& value2);
        friend bool operator!=(const int128_t& value1, const int128_t& value2);
        friend bool operator> (const int128_t& value1, const int128_t& value2);
        friend bool operator>=(const int128_t& value1, const int128_t& value2);
        friend bool operator< (const int128_t& value1, const int128_t& value2);
        friend bool operator<=(const int128_t& value1, const int128_t& value2);

        // Operators to convert back to basic types
        int8_t  AsInt8()   const;
        int16_t AsInt16()  const;
        int32_t AsInt32()  const;
        int64_t AsInt64()  const;
        float   AsFloat()  const;
        double  AsDouble() const;

        // Misc. Functions
        void    Negate();
        bool    IsNegative() const;
        bool    IsPositive() const;
        void    Modulus(const int128_t& divisor, int128_t& quotient, int128_t& remainder) const;

        // String conversion functions
        int128_t StrToInt128(const char* pValue, char** ppEnd, int base) const;
        int128_t StrToInt128(const wchar_t* pValue, wchar_t** ppEnd, int base) const;
        void     Int128ToStr(char* pValue, char** ppEnd, int base) const;
        void     Int128ToStr(wchar_t* pValue, wchar_t** ppEnd, int base) const;

    }; // class int128_t

    class uint128_t
    {
    public:
        uint128_t();
        uint128_t(uint32_t nPart0, uint32_t nPart1, uint32_t nPart2, uint32_t nPart3);
        uint128_t(uint64_t nPart0, uint64_t nPart1);

        uint128_t(int8_t value);
        uint128_t(uint8_t value);

        uint128_t(int16_t value);
        uint128_t(uint16_t value);

        uint128_t(int32_t value);
        uint128_t(uint32_t value);

        uint128_t(int64_t value);
        uint128_t(uint64_t value);

        uint128_t(const int128_t& value);
        uint128_t(const uint128_t& value);

        uint128_t(const float value);
        uint128_t(const double value);

        uint128_t(const char* pValue, int nBase = 10);
        uint128_t(const wchar_t* pValue, int nBase = 10);

        // Assignment operator
        uint128_t& operator=(const int128_t_base& value);

        // Unary arithmetic/logic operators
        uint128_t  operator-() const;
        uint128_t& operator++();
        uint128_t& operator--();
        uint128_t  operator++(int);
        uint128_t  operator--(int);
        uint128_t  operator~() const;
        uint128_t  operator+() const;

        // Math operators
        friend uint128_t operator+(const uint128_t& value1, const uint128_t& value2);
        friend uint128_t operator-(const uint128_t& value1, const uint128_t& value2);
        friend uint128_t operator*(const uint128_t& value1, const uint128_t& value2);
        friend uint128_t operator/(const uint128_t& value1, const uint128_t& value2);
        friend uint128_t operator%(const uint128_t& value1, const uint128_t& value2);

        uint128_t& operator+=(const uint128_t& value);
        uint128_t& operator-=(const uint128_t& value);
        uint128_t& operator*=(const uint128_t& value);
        uint128_t& operator/=(const uint128_t& value);
        uint128_t& operator%=(const uint128_t& value);

        // Shift operators
        uint128_t  operator>> (int nShift) const;
        uint128_t  operator<< (int nShift) const;
        uint128_t& operator>>=(int nShift);
        uint128_t& operator<<=(int nShift);

        // Logical operators
        friend uint128_t operator^(const uint128_t& value1, const uint128_t& value2);
        friend uint128_t operator|(const uint128_t& value1, const uint128_t& value2);
        friend uint128_t operator&(const uint128_t& value1, const uint128_t& value2);
        uint128_t& operator^= (const uint128_t& value);
        uint128_t& operator|= (const uint128_t& value);
        uint128_t& operator&= (const uint128_t& value);

        // Equality operators
        friend int  compare   (const uint128_t& value1, const uint128_t& value2);
        friend bool operator==(const uint128_t& value1, const uint128_t& value2);
        friend bool operator!=(const uint128_t& value1, const uint128_t& value2);
        friend bool operator> (const uint128_t& value1, const uint128_t& value2);
        friend bool operator>=(const uint128_t& value1, const uint128_t& value2);
        friend bool operator< (const uint128_t& value1, const uint128_t& value2);
        friend bool operator<=(const uint128_t& value1, const uint128_t& value2);

        // Operators to convert back to basic types
        int8_t  AsInt8()   const;
        int16_t AsInt16()  const;
        int32_t AsInt32()  const;
        int64_t AsInt64()  const;
        float   AsFloat()  const;
        double  AsDouble() const;

        // Misc. Functions
        void    Negate();
        bool    IsNegative() const;
        bool    IsPositive() const;
        void    Modulus(const uint128_t& divisor, uint128_t& quotient, uint128_t& remainder) const;

        // String conversion functions
        uint128_t StrToInt128(const char* pValue, char** ppEnd, int base) const;
        uint128_t StrToInt128(const wchar_t* pValue, wchar_t** ppEnd, int base) const;
        void      Int128ToStr(char* pValue, char** ppEnd, int base) const;
        void      Int128ToStr(wchar_t* pValue, wchar_t** ppEnd, int base) const;

    }; // class uint128_t