uint128_t

Description

uint128_t is an unsigned 128-bit integer.

#include <boost/int128.hpp>

namespace boost {
namespace int128 {

struct uint128_t {

    #if BOOST_INT128_ENDIAN_LITTLE_BYTE
    std::uint64_t low {};
    std::uint64_t high {};
    #else
    std::uint64_t high {};
    std::uint64_t low {};
    #endif

    // Constructors, conversion operators, and member operators
    // documented in detail below...
};

} // namespace int128
} // namespace boost

The type provides:

  • Constructors from all built-in integer types and int128_t

  • Conversion operators to built-in integer and floating-point types

  • Full set of comparison operators (<, , >, >=, ==, !=)

  • Bitwise operators (~, |, &, ^, <<, >>)

  • Arithmetic operators (+, -, *, /, %)

  • Compound assignment variants of all binary operators

  • Increment and decrement operators (++, --)

Alignment

If your platform has a native 128-bit unsigned integer, the struct is defined as so:

struct alignas(alignof(unsigned __int128)) uint128_t

Otherwise, it is

struct alignas(sizeof(std::uint64_t) * 2) uint128_t

Operator Behavior

For all the following operators use of signed overloads will error from static_assert by default. This is the library’s way of enforcing the behavior of -Wsign-conversion and -Wsign-comparison in a library type. If you want to compare with signed types you must define BOOST_INT128_ALLOW_SIGN_COMPARE, and similarly you must define BOOST_INT128_ALLOW_SIGN_CONVERSION for other operations with mixed signedness. These will both cast the signed integer to an unsigned integer and then perform the operation.

Sign Compare Behavior Deviation

The behavior of uint128_t will deviate from the behavior of builtin unsigned integers with mixed sign comparisons in hopefully a less surprising way. A built-in sign compare looks something like

template <typename UnsignedInteger, typename SignedInteger>
constexpr bool operator>(const UnsignedInteger lhs, const SignedInteger rhs)
{
    return lhs > static_cast<UnsignedInteger>(rhs)
}

If you were to call this function with arguments 5U and -5, you would get the surprising answer of false. Why? The two’s complement representation of -5 has its most significant bit set (along with many other high bits). When cast to unsigned, this bit pattern is reinterpreted as a huge positive number, far greater than 5.

With uint128_t we have checks even in this case like so:

template <typename SignedInteger>
constexpr bool operator>(const uint128_t lhs, const SignedInteger rhs) noexcept
{
    if (rhs >= 0)
    {
        return lhs > static_cast<uint128_t>(rhs);
    }
    else
    {
        return true;
    }
}

This allows the library to return the correct answer even when mixing signs.

Constructors

namespace boost {
namespace int128 {

struct uint128_t
{
    ...

    // Defaulted basic construction
    constexpr uint128_t() noexcept = default;
    constexpr uint128_t(const uint128_t&) noexcept = default;
    constexpr uint128_t(uint128_t&&) noexcept = default;
    constexpr uint128_t& operator=(const uint128_t&) noexcept = default;
    constexpr uint128_t& operator=(uint128_t&&) noexcept = default;

    constexpr uint128_t(const int128_t& v) noexcept;

    // Construct from integral types
    constexpr uint128_t(const std::uint64_t hi, const std::uint64_t lo) noexcept;

    template <BOOST_INT128_SIGNED_INTEGER_CONCEPT SignedInteger>
    constexpr uint128_t(const SignedInteger v) noexcept;

    template <BOOST_INT128_UNSIGNED_INTEGER_CONCEPT UnsignedInteger>
    constexpr uint128_t(const UnsignedInteger v) noexcept;

    #ifdef BOOST_INT128_HAS_INT128

    // Typically a typedef from __int128
    constexpr uint128_t(const detail::builtin_i128 v) noexcept;

    // Typically a typedef unsigned __int128
    constexpr uint128_t(const detail::builtin_u128 v) noexcept;

    #endif // BOOST_INT128_HAS_INT128
};

} // namespace int128
} // namespace boost

All constructors are only defined for integers and are subject to mixed sign limitations discussed above. None are marked explicit in order to match the implicit conversion behavior of the built-in integer types.

Conversions

namespace boost {
namespace int128 {

struct uint128_t
{
    ...

    // Integer conversion operators
    constexpr operator bool() const noexcept;

    template <BOOST_INT128_SIGNED_INTEGER_CONCEPT SignedInteger>
    explicit constexpr operator SignedInteger() const noexcept;

    template <BOOST_INT128_UNSIGNED_INTEGER_CONCEPT UnsignedInteger>
    explicit constexpr operator UnsignedInteger() const noexcept;

    #ifdef BOOST_INT128_HAS_INT128

    explicit constexpr operator detail::builtin_i128() const noexcept;

    explicit constexpr operator detail::builtin_u128() const noexcept;

    #endif // BOOST_INT128_HAS_INT128

    // Conversion to float
    explicit constexpr operator float() const noexcept;
    explicit constexpr operator double() const noexcept;
    explicit constexpr operator long double() const noexcept;
};

} // namespace int128
} // namespace boost

Conversions to signed integers are subject to mixed sign limitations discussed above. Conversion to bool is not marked explicit to match the behavior of built-in integer types. Conversions to floating point types may not be lossless depending on the value of the uint128_t at time of conversion, as the number of digits it represents can exceed the precision of the significand in floating point types.

Comparison Operators

Less Than

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr bool operator<(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr bool operator<(const Integer lhs, const uint128_t rhs) noexcept;

constexpr bool operator<(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns if the lhs value is less than the rhs value without exception. This operation is only defined for integers and is subject to mixed sign limitations discussed above.

Less Than or Equal To

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr bool operator<=(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr bool operator<=(const Integer lhs, const uint128_t rhs) noexcept;

constexpr bool operator<=(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns if the lhs value is less than or equal to the rhs value without exception. This operation is only defined for integers and is subject to mixed sign limitations discussed above.

Greater Than

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr bool operator>(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr bool operator>(const Integer lhs, const uint128_t rhs) noexcept;

constexpr bool operator>(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns if the lhs value is greater than the rhs value without exception. This operation is only defined for integers and is subject to mixed sign limitations discussed above.

Greater Than or Equal To

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr bool operator>=(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr bool operator>=(const Integer lhs, const uint128_t rhs) noexcept;

constexpr bool operator>=(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns if the lhs value is greater than or equal to the rhs value without exception. This operation is only defined for integers and is subject to mixed sign limitations discussed above.

Equality

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr bool operator==(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr bool operator==(const Integer lhs, const uint128_t rhs) noexcept;

constexpr bool operator==(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns if the lhs value is equal to the rhs value without exception. This operation is only defined for integers and is subject to mixed sign limitations discussed above.

Inequality

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr bool operator!=(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr bool operator!=(const Integer lhs, const uint128_t rhs) noexcept;

constexpr bool operator!=(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns if the lhs value is not equal to the rhs value without exception. This operation is only defined for integers and is subject to mixed sign limitations discussed above.

Spaceship Operator (Requires C++20)

constexpr std::strong_ordering operator<=>(const uint128_t lhs, const uint128_t rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr std::strong_ordering operator<=>(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr std::strong_ordering operator<=>(const Integer lhs, const uint128_t rhs) noexcept;

Returns one of the following without exception:

  • std::strong_ordering::less if lhs < rhs

  • std::strong_ordering::equivalent if lhs == rhs

  • std::strong_ordering::greater otherwise (implies lhs > rhs)

Bitwise Operators

Negation

constexpr uint128_t operator~(const uint128_t rhs) noexcept

Returns the bitwise negation of rhs without exception.

Or

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator|(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator|(const Integer lhs, const uint128_t rhs) noexcept;

constexpr uint128_t operator|(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns the bitwise or of lhs and rhs without exception. This operation is subject to mixed sign limitations discussed above.

And

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator&(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator&(const Integer lhs, const uint128_t rhs) noexcept;

constexpr uint128_t operator&(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns the bitwise and of lhs and rhs without exception. This operation is subject to mixed sign limitations discussed above.

Xor

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator^(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator^(const Integer lhs, const uint128_t rhs) noexcept;

constexpr uint128_t operator^(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns the bitwise xor of lhs and rhs without exception. This operation is subject to mixed sign limitations discussed above.

Left Shift

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator<<(const uint128_t lhs, const Integer rhs) noexcept;

template <typename Integer, std::enable_if_t<std::is_integral<Integer>::value && (sizeof(Integer) * 8 > 16), bool> = true>
constexpr Integer operator<<(const Integer lhs, const uint128_t rhs) noexcept;

template <typename SignedInteger, std::enable_if_t<detail::is_signed_integer_v<SignedInteger> && (sizeof(SignedInteger) * 8 <= 16), bool> = true>
constexpr int operator<<(const SignedInteger lhs, const uint128_t rhs) noexcept;

template <typename UnsignedInteger, std::enable_if_t<detail::is_unsigned_integer_v<UnsignedInteger> && (sizeof(UnsignedInteger) * 8 <= 16), bool> = true>
constexpr unsigned int operator<<(const UnsignedInteger lhs, const uint128_t rhs) noexcept;

constexpr uint128_t operator<<(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns the bitwise left shift of lhs without exception. The return type is dependent on the type of Integer when it is the lhs value to match the promotion behavior of built-in integer types. This operation is subject to mixed sign limitations discussed above.

Right Shift

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator<<(const uint128_t lhs, const Integer rhs) noexcept;

template <typename Integer, std::enable_if_t<std::is_integral<Integer>::value && (sizeof(Integer) * 8 > 16), bool> = true>
constexpr Integer operator<<(const Integer lhs, const uint128_t rhs) noexcept;

template <typename SignedInteger, std::enable_if_t<detail::is_signed_integer_v<SignedInteger> && (sizeof(SignedInteger) * 8 <= 16), bool> = true>
constexpr int operator<<(const SignedInteger lhs, const uint128_t rhs) noexcept;

template <typename UnsignedInteger, std::enable_if_t<detail::is_unsigned_integer_v<UnsignedInteger> && (sizeof(UnsignedInteger) * 8 <= 16), bool> = true>
constexpr unsigned int operator<<(const UnsignedInteger lhs, const uint128_t rhs) noexcept;

constexpr uint128_t operator<<(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns the bitwise right shift of lhs without exception. The return type is dependent on the type of Integer when it is the lhs value to match the promotion behavior of built-in integer types. This operation is subject to mixed sign limitations discussed above.

Arithmetic Operators

Addition

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator+(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator+(const Integer lhs, const uint128_t rhs) noexcept;

constexpr uint128_t operator+(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns as a uint128_t the sum of lhs and rhs. If the sum is greater than is representable by a uint128_t, the operation silently performs unsigned rollover in the direction of 0. This operation is only defined for integers and is subject to mixed sign limitations discussed above.

Subtraction

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator-(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator-(const Integer lhs, const uint128_t rhs) noexcept;

constexpr uint128_t operator-(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns as a uint128_t the difference of lhs and rhs. If the difference is less than is representable by a uint128_t, the operation silently performs unsigned rollover in the direction of BOOST_INT128_UINT128_MAX. This operation is only defined for integers and is subject to mixed sign limitations discussed above.

Multiplication

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator*(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator*(const Integer lhs, const uint128_t rhs) noexcept;

constexpr uint128_t operator*(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns as a uint128_t the product of lhs and rhs. If the product is greater than is representable by a uint128_t, the operation silently performs unsigned rollover in the direction of 0. This operation is only defined for integers and is subject to mixed sign limitations discussed above.

Division

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator/(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator/(const Integer lhs, const uint128_t rhs) noexcept;

constexpr uint128_t operator/(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns as a uint128_t the quotient of lhs and rhs without exception. This operation is only defined for integers and is subject to mixed sign limitations discussed above.

Modulo

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator%(const uint128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_INTEGER_CONCEPT Integer>
constexpr uint128_t operator%(const Integer lhs, const uint128_t rhs) noexcept;

constexpr uint128_t operator%(const uint128_t lhs, const uint128_t rhs) noexcept;

Returns as a uint128_t the remainder of lhs and rhs without exception. This operation is only defined for integers and is subject to mixed sign limitations discussed above.