Int128: Portable and Performant 128-bit integers

Matt Borland

Overview

Description

Boost.Int128 is a portable implementation of a signed, and an unsigned 128-bit integer and related functionality (e.g. bit counting).

The library is header-only, has no dependencies, and requires only C++14.

Motivation

128-bit integers are remarkably useful in a number of domains, but portability is often an issue. An example is a 64-bit machine running Linux (say Ubuntu 24.04) has __int128, but the same exact machine running Windows does not have this type.

Use Cases

Anywhere 128-bits are needed.

Supported Compilers

Boost.Int128 is tested natively on Ubuntu (x86_64, s390x, and aarch64), macOS (x86_64, and Apple Silicon), and Windows (x32 and x64); as well as emulated PPC64LE and STM32 using QEMU with the following compilers:

  • GCC 5 and later

  • Clang 5 and later

  • Visual Studio 2017 (14.1) and later

  • Intel OneAPI DPC++ 2024.2 and later

Tested on Github Actions and Drone. Coverage can be found on Codecov.

API Reference

Namespaces

  • boost::int128 contains all components of the library

Literals

Functions

Listed by analogous STL header.

<cmath>

  • abs - Absolute Value

<iostream>

Enums

  • None

Constants

  • None

Macros

Configuration

  • BOOST_INT128_ALLOW_SIGN_CONVERSION - Allows operations between this library’s types, and built-in types of opposite signedness. DISABLED BY DEFAULT FOR CORRECTNESS

Concepts

The following are the definitions of the concepts used throughout the library to ensure consistency.

Signed Integer

This is an extension of the <type_traits> definition to allow builtin __int128 to be used.

namespace boost {
namespace int128 {
namespace detail {

template <typename T>
struct signed_integer
{
    static constexpr bool value = (std::is_signed<T>::value && std::is_integral<T>::value)
    #ifdef BOOST_INT128_HAS_INT128
    || std::is_same<T, builtin_i128>::value;
    #endif
    ;
};

template <typename T>
static constexpr bool is_signed_integer_v = signed_integer<T>::value;

#define BOOST_INT128_DEFAULTED_SIGNED_INTEGER_CONCEPT typename SignedInteger, std::enable_if_t<detail::is_signed_integer_v<SignedInteger>, bool> = true

#define BOOST_INT128_SIGNED_INTEGER_CONCEPT typename SignedInteger, std::enable_if_t<detail::is_signed_integer_v<SignedInteger>, bool>

} // namespace detail
} // namespace int128
} // namespace boost

Unsigned Integer

This is an extension of the <type_traits> definition to allow builtin unsigned __int128 to be used.

namespace boost {
namespace int128 {
namespace detail {

template <typename T>
struct unsigned_integer
{
    static constexpr bool value = (std::is_unsigned<T>::value && std::is_integral<T>::value)
    #ifdef BOOST_INT128_HAS_INT128
    || std::is_same<T, builtin_u128>::value;
    #endif
    ;
};

template <typename T>
static constexpr bool is_unsigned_integer_v = unsigned_integer<T>::value;

#define BOOST_INT128_DEFAULTED_UNSIGNED_INTEGER_CONCEPT typename UnsignedInteger, std::enable_if_t<detail::is_unsigned_integer_v<UnsignedInteger>, bool> = true

#define BOOST_INT128_UNSIGNED_INTEGER_CONCEPT typename UnsignedInteger, std::enable_if_t<detail::is_unsigned_integer_v<UnsignedInteger>, bool>

} // namespace detail
} // namespace int128
} // namespace boost

Integer

This is a combination of the above two in which any integer can be detected

namespace boost {
namespace int128 {
namespace detail {

template <typename T>
static constexpr bool is_any_integer_v = signed_integer<T>::value || unsigned_integer<T>::value;

#define BOOST_INT128_DEFAULTED_INTEGER_CONCEPT typename Integer, std::enable_if_t<detail::is_any_integer_v<Integer>, bool> = true

#define BOOST_INT128_INTEGER_CONCEPT typename Integer, std::enable_if_t<detail::is_any_integer_v<Integer>, bool>

} // namespace detail
} // namespace int128
} // namespace boost

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 // BOOST_INT128_ENDIAN_LITTLE_BYTE

    // 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;

    // Requires conversion file to be implemented
    constexpr uint128_t(const int128_t& v) noexcept;

    // Construct from integral types
    #if BOOST_INT128_ENDIAN_LITTLE_BYTE

    constexpr uint128_t(const std::uint64_t hi, const std::uint64_t lo) noexcept;

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

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

    #ifdef BOOST_INT128_HAS_INT128

    constexpr uint128_t(const detail::builtin_i128 v) noexcept;

    constexpr uint128_t(const detail::builtin_u128 v) noexcept;

    #endif // BOOST_INT128_HAS_INT128

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

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

    template <BOOST_INT128_DEFAULTED_UNSIGNED_INTEGER_CONCEPT>
    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
    // This is basically the same as ldexp(static_cast<T>(high), 64) + static_cast<T>(low),
    // but can be constexpr at C++11 instead of C++26
    explicit constexpr operator float() const noexcept;
    explicit constexpr operator double() const noexcept;
    explicit constexpr operator long double() const noexcept;

    // Compound OR
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr uint128_t& operator|=(Integer rhs) noexcept;

    constexpr uint128_t& operator|=(uint128_t rhs) noexcept;

    // Compound AND
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr uint128_t& operator&=(Integer rhs) noexcept;

    constexpr uint128_t& operator&=(uint128_t rhs) noexcept;

    // Compound XOR
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr uint128_t& operator^=(Integer rhs) noexcept;

    constexpr uint128_t& operator^=(uint128_t rhs) noexcept;

    // Compound Left Shift
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr uint128_t& operator<<=(Integer rhs) noexcept;

    constexpr uint128_t& operator<<=(uint128_t rhs) noexcept;

    // Compound Right Shift
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr uint128_t& operator>>=(Integer rhs) noexcept;

    constexpr uint128_t& operator>>=(uint128_t rhs) noexcept;

    constexpr uint128_t& operator++() noexcept;
    constexpr uint128_t& operator++(int) noexcept;
    constexpr uint128_t& operator--() noexcept;
    constexpr uint128_t& operator--(int) noexcept;

    // Compound Addition
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr uint128_t& operator+=(Integer rhs) noexcept;

    constexpr uint128_t& operator+=(uint128_t rhs) noexcept;

    // Compound Subtraction
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr uint128_t& operator-=(Integer rhs) noexcept;

    constexpr uint128_t& operator-=(uint128_t rhs) noexcept;

    // Compound Multiplication
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr uint128_t& operator*=(Integer rhs) noexcept;

    constexpr uint128_t& operator*=(uint128_t rhs) noexcept;

    // Compound Division
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr uint128_t& operator/=(Integer rhs) noexcept;

    constexpr uint128_t& operator/=(uint128_t rhs) noexcept;

    // Compound modulo
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr uint128_t& operator%=(Integer rhs) noexcept;

    constexpr uint128_t& operator%=(uint128_t rhs) noexcept;

}; // struct uint128_t

} //namespace int128
} //namespace boost

We also have the following non-member free functions:

namespace boost {
namespace int128 {

//=====================================
// Comparison Operators
//=====================================

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

//=====================================
// Bit-wise Operators
//=====================================

constexpr uint128_t operator~(const uint128_t rhs) noexcept

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

template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
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;

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

template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
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;

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

template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
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;

// Shift operators have a number of overloads to ensure they return type matches the behavior of built-in types

template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
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;

template <typename Integer, std::enable_if_t<std::is_integral<Integer>::value, bool> = true>
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 operator>>(UnsignedInteger lhs, const uint128_t rhs) noexcept;

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

//=====================================
// Increment and Decrement Operators
//=====================================

constexpr uint128_t& uint128_t::operator++() noexcept;

constexpr uint128_t& uint128_t::operator++(int) noexcept;

constexpr uint128_t& uint128_t::operator--() noexcept;

constexpr uint128_t& uint128_t::operator--(int) noexcept;

//=====================================
// Add, Sub, Mul, Div, Mod
//=====================================

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

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
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;

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

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
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;

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

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
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;

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

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
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;

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

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
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;

} // namespace int128
} // namespace boost

int128_t

Description

int128_t is a signed 128-bit integer

#include <boost/int128.hpp>

namespace boost {
namespace int128 {

struct int128_t {

    #if BOOST_INT128_ENDIAN_LITTLE_BYTE

    std::uint64_t low {};
    std::int64_t high {};

    #else

    std::int64_t high {};
    std::uint64_t low {};

    #endif

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

    // Requires conversion file to be implemented
    constexpr int128_t(const uint128_t& v) noexcept;

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

    template <BOOST_INT128_DEFAULTED_SIGNED_INTEGER_CONCEPT>
    constexpr int128_t(const SignedInteger v) noexcept;

    template <BOOST_INT128_DEFAULTED_UNSIGNED_INTEGER_CONCEPT>
    constexpr int128_t(const UnsignedInteger v) noexcept;

    #ifdef BOOST_INT128_HAS_INT128

    constexpr int128_t(const detail::builtin_i128 v) noexcept;

    constexpr int128_t(const detail::builtin_u128 v) noexcept;

    #endif // BOOST_INT128_HAS_INT128

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

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

    template <BOOST_INT128_DEFAULTED_UNSIGNED_INTEGER_CONCEPT>
    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
    // This is basically the same as ldexp(static_cast<T>(high), 64) + static_cast<T>(low),
    // but can be constexpr at C++11 instead of C++26
    explicit constexpr operator float() const noexcept;
    explicit constexpr operator double() const noexcept;
    explicit constexpr operator long double() const noexcept;

    // Compound Or
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr int128_t& operator|=(Integer rhs) noexcept;

    constexpr int128_t& operator|=(int128_t rhs) noexcept;

    // Compound And
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr int128_t& operator&=(Integer rhs) noexcept;

    constexpr int128_t& operator&=(int128_t rhs) noexcept;

    // Compound XOR
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr int128_t& operator^=(Integer rhs) noexcept;

    constexpr int128_t& operator^=(int128_t rhs) noexcept;

    // Compound Left Shift
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr int128_t& operator<<=(Integer rhs) noexcept;

    constexpr int128_t& operator<<=(int128_t rhs) noexcept;

    // Compound Right Shift
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr int128_t& operator>>=(Integer rhs) noexcept;

    constexpr int128_t& operator>>=(int128_t rhs) noexcept;

    // Prefix and postfix increment
    constexpr int128_t& operator++() noexcept;
    constexpr int128_t& operator++(int) noexcept;

    // Prefix and postfix decrment
    constexpr int128_t& operator--() noexcept;
    constexpr int128_t& operator--(int) noexcept;

    // Compound Addition
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr int128_t& operator+=(Integer rhs) noexcept;

    constexpr int128_t& operator+=(int128_t rhs) noexcept;

    // Compound Subtraction
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr int128_t& operator-=(Integer rhs) noexcept;

    constexpr int128_t& operator-=(int128_t rhs) noexcept;

    // Compound Multiplication
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr int128_t& operator*=(Integer rhs) noexcept;

    constexpr int128_t& operator*=(int128_t rhs) noexcept;

    // Compound Division
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr int128_t& operator/=(Integer rhs) noexcept;

    constexpr int128_t& operator/=(int128_t rhs) noexcept;

    // Compound Modulo
    template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
    constexpr int128_t& operator%=(Integer rhs) noexcept;

    constexpr int128_t& operator%=(int128_t rhs) noexcept;

}; // struct int128_t

} //namespace int128
} //namespace boost

We also have the following non-member free functions:

namespace boost {
namespace int128 {

//=====================================
// Comparison Operators
//=====================================

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr bool operator<(const int128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr bool operator<(const Integer lhs, const int128_t rhs) noexcept;

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

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

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

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

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr bool operator>(const int128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr bool operator>(const Integer lhs, const int128_t rhs) noexcept;

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

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

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

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

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

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

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

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

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

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

//=====================================
// Bit-wise Operators
//=====================================

constexpr int128_t operator~(const int128_t rhs) noexcept

template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
constexpr int128_t operator|(const int128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
constexpr int128_t operator|(const Integer lhs, const int128_t rhs) noexcept;

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

template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
constexpr int128_t operator&(const int128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
constexpr int128_t operator&(const Integer lhs, const int128_t rhs) noexcept;

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

template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
constexpr int128_t operator^(const int128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
constexpr int128_t operator^(const Integer lhs, const int128_t rhs) noexcept;

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

// Shift operators have a number of overloads to ensure they return type matches the behavior of built-in types

template <BOOST_INT128_DEFAULTED_INTEGER_CONCEPT>
constexpr int128_t operator<<(const int128_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 int128_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 int128_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 int128_t rhs) noexcept;

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

template <typename Integer, std::enable_if_t<std::is_integral<Integer>::value, bool> = true>
constexpr int128_t operator>>(const int128_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 int128_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 int128_t rhs) noexcept;

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

constexpr int128_t operator>>(const int128_t lhs, const int128_t rhs) noexcept;

//=====================================
// Increment and Decrement Operators
//=====================================

constexpr int128_t& int128_t::operator++() noexcept;

constexpr int128_t& int128_t::operator++(int) noexcept;

constexpr int128_t& int128_t::operator--() noexcept;

constexpr int128_t& int128_t::operator--(int) noexcept;

//=====================================
// Add, Sub, Mul, Div, Mod
//=====================================

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr int128_t operator+(const int128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr int128_t operator+(const Integer lhs, const int128_t rhs) noexcept;

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

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr int128_t operator-(const int128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr int128_t operator-(const Integer lhs, const int128_t rhs) noexcept;

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

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr int128_t operator*(const int128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr int128_t operator*(const Integer lhs, const int128_t rhs) noexcept;

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

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr int128_t operator/(const int128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr int128_t operator/(const Integer lhs, const int128_t rhs) noexcept;

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

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr int128_t operator%(const int128_t lhs, const Integer rhs) noexcept;

template <BOOST_INT128_DEFAULTED_INTEGER_TYPE>
constexpr int128_t operator%(const Integer lhs, const int128_t rhs) noexcept;

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

} // namespace int128
} // namespace boost

Mixed Type Operations

Conversions

The ability to convert between the two types via static_cast is available as documented in the above class descriptions.

Comparisons and Arithmetics

The following operations are ALL ILLEGAL. Since we can not enforce -Wsign-conversion and -Wsign-compare through the compiler we instead static_assert that the operation is unavailable, and that the USER MUST CAST TO A COMMON TYPE. This removes a common source of error (search "Sign Conversion" on Stack Overflow)

namespace boost {
namespace int128 {

//=====================================
// Comparison Operators
//=====================================

constexpr bool operator==(uint128_t lhs, int128_t rhs);

constexpr bool operator==(int128_t lhs, uint128_t rhs);

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

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

constexpr bool operator<(uint128_t lhs, int128_t rhs);

constexpr bool operator<(int128_t lhs, uint128_t rhs);

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

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

constexpr bool operator>(uint128_t lhs, int128_t rhs);

constexpr bool operator>(int128_t lhs, uint128_t rhs);

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

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

//=====================================
// Arithmetic Operators
//=====================================

constexpr uint128_t operator+(uint128_t lhs, int128_t rhs);

constexpr uint128_t operator+(int128_t lhs, uint128_t rhs);

constexpr uint128_t operator-(uint128_t lhs, int128_t rhs);

constexpr uint128_t operator-(int128_t lhs, uint128_t rhs);

constexpr uint128_t operator*(uint128_t lhs, int128_t rhs);

constexpr uint128_t operator*(int128_t lhs, uint128_t rhs);

constexpr uint128_t operator/(uint128_t lhs, int128_t rhs);

constexpr uint128_t operator/(int128_t lhs, uint128_t rhs);

constexpr uint128_t operator%(uint128_t lhs, int128_t rhs);

constexpr uint128_t operator%(int128_t lhs, uint128_t rhs);

} // namespace int128
} // namespace boost

Literals

The following literals and macros are provided for convenient construction of the types provided in the library:

#include <boost/int128/literals.hpp>

namespace boost {
namespace int128 {
namespace literals {

constexpr uint128_t operator ""_u128(const char* str) noexcept;

constexpr uint128_t operator ""_U128(const char* str) noexcept;

constexpr uint128_t operator ""_u128(const char* str, std::size_t len) noexcept;

constexpr uint128_t operator ""_U128(const char* str, std::size_t len) noexcept;

constexpr uint128_t operator ""_u128(unsigned long long v) noexcept;

constexpr uint128_t operator ""_U128(unsigned long long v) noexcept;

constexpr int128_t operator ""_i128(const char* str) noexcept;

constexpr int128_t operator ""_I128(const char* str) noexcept;

constexpr int128_t operator ""_i128(unsigned long long v) noexcept;

constexpr int128_t operator ""_I128(unsigned long long v) noexcept;

constexpr int128_t operator ""_i128(const char* str, std::size_t len) noexcept;

constexpr int128_t operator ""_I128(const char* str, std::size_t len) noexcept;

} // namespace literals
} // namespace int128
} // namespace boost

#define BOOST_INT128_UINT128_C(x) ...
#define BOOST_INT128_INT128_C(x) ...

The macros at the end allow you to write out a 128-bit number like you would with say UINT64_C without having to add quotes:

#include <boost/int128.hpp>

int main()
{
    const boost::int128::uint128_t max_val {std::numeric_limits<boost::int128::uint128_t>::max()};

    // The following type for auto will be boost::int128::uint128_t
    const auto macro_val{BOOST_INT128_UINT128_C(340282366920938463463374607431768211455)};

    return !(max_val == macro_val);
}

<bit>

The following are functions analagous to those found in C++20’s <bit> header, but for boost::int128::uint128_t. None of these functions applied to signed integral types, and thus none have overloads for boost::int128::int128_t. All of these functions are available using C ++14 like the rest of the library.

has_single_bit

Checks if x is an integral power of two. Returns true if x is a power of two; otherwise false

namespace boost {
namespace int128 {

constexpr bool has_single_bit(uint128_t x) noexcept;

} // namespace int128
} // namespace boost

countl_zero

Returns the number of consecutive 0 bits in the value x, starting from the most significant.

namespace boost {
namespace int128 {

constexpr int countl_zero(uint128_t x) noexcept;

} // namespace int128
} // namespace boost

countl_one

Returns the number of consecutive 1 bits in the value x, starting from the most significant.

namespace boost {
namespace int128 {

constexpr int countl_one(uint128_t x) noexcept;

} // namespace int128
} // namespace boost

bit_width

If x is not zero, returns the number of bits needed to store the value x. If x is zero, returns 0

namespace boost {
namespace int128 {

constexpr int bit_width(uint128_t x) noexcept;

} // namespace int128
} // namespace boost

bit_ceil

Returns the smallest integral power of two that is not smaller than x.

namespace boost {
namespace int128 {

constexpr uint128_t bit_ceil(uint128_t x) noexcept;

} // namespace int128
} // namespace boost

bit_floor

Returns the smallest integral power of two that is not greater than x. If x is 0 then returns 0.

namespace boost {
namespace int128 {

constexpr uint128_t bit_floor(uint128_t x) noexcept;

} // namespace int128
} // namespace boost

countr_zero

Returns the number of consecutive 0 bits in the value x, starting from the least significant.

namespace boost {
namespace int128 {

constexpr int countr_zero(uint128_t x) noexcept;

} // namespace int128
} // namespace boost

countr_one

Returns the number of consecutive 1 bits in the value x, starting from the least significant.

namespace boost {
namespace int128 {

constexpr int countr_one(uint128_t x) noexcept;

} // namespace int128
} // namespace boost

rotl

Computes the result of bitwise left-rotating the value of x by s positions. This operation is also known as a left circular shift.

namespace boost {
namespace int128 {

constexpr uint128_t rotl(uint128_t x, int s) noexcept;

} // namespace int128
} // namespace boost

rotr

Computes the result of bitwise right-rotating the value of x by s positions. This operation is also known as a right circular shift.

namespace boost {
namespace int128 {

constexpr uint128_t rotr(uint128_t x, int s) noexcept;

} // namespace int128
} // namespace boost

popcount

Returns the number of 1 bits in x.

namespace boost {
namespace int128 {

constexpr int popcount(uint128_t x) noexcept;

} // namespace int128
} // namespace boost

byteswap

Reverses the bytes in the given integer value x.

namespace boost {
namespace int128 {

constexpr int byteswap(uint128_t x) noexcept;

} // namespace int128
} // namespace boost

<iostream>

The following stream operators are available, and work similar to built-in integer types:

#include <boost/int128/iostream.hpp>

namespace boost {
namespace int128 {

template <typename charT, typename traits>
std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const int128_t& v)

template <typename charT, typename traits>
std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, int128_t& v)

template <typename charT, typename traits>
std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const uint128_t& v)

template <typename charT, typename traits>
std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, uint128_t& v)

} // namespace int128
} // namespace boost

Flags

The following flags are supported for both streaming directions:

  • std::ios_base::oct - Octal Numbers

  • std::ios_base::dec - Decimal Numbers

  • std::ios_base::hex - Hexadecimal Numbers

  • std::ios_base::upper - Upper Case Formatting (e.g. 0XFFFF)

  • std::ios_base::lower - Lower Case Formatting (e.g. 0xffff)

<numeric>

Saturating Arithmetic

Saturating arithmetic avoids the possibility of overflow or underflow, by clamping the value to a defined range should either of these situations occur. This means that on overflow the types will return std::numeric_limits::max(), and on underflow they will return std::numeric_limits::min(). The following functions are provided for saturating arithmetic, and they do not require C++26.

#include <boost/int128/numeric.hpp>

namespace boost {
namespace int128 {

constexpr uint128_t add_sat(uint128_t lhs, uint128_t rhs) noexcept;

constexpr int128_t add_sat(int128_t lhs, int128_t rhs) noexcept;

constexpr uint128_t sub_sat(uint128_t lhs, uint128_t rhs) noexcept;

constexpr int128_t sub_sat(int128_t lhs, int128_t rhs) noexcept;

constexpr uint128_t mul_sat(uint128_t lhs, uint128_t rhs) noexcept;

constexpr int128_t mul_sat(int128_t lhs, int128_t rhs) noexcept;

constexpr uint128_t div_sat(uint128_t lhs, uint128_t rhs) noexcept;

constexpr int128_t div_sat(int128_t lhs, int128_t rhs) noexcept;

} // namespace int128
} // namespace boost

Saturating Cast

This function allows a LibraryIntegerType (i.e. uint128_t or int128_t) to be safely casted to another integer type to include built-in and hardware integer types (TargetIntegerType). Should the TargetIntegerType not be able to represent the value of the LibraryIntegerType it will be set to either std::numeric_limits::max() or std::numeric_limits::min() depending on if the situation is overflow or underflow.

#include <boost/int128/numeric.hpp>

namespace boost {
namespace int128 {

constexpr <typename LibraryIntegerType, typename TargetIntegerType>
constexpr TargetIntegerType saturate_cast(LibraryIntegerType x) noexcept;

} // namespace int128
} // namespace boost

References

The following books, papers and blog posts serve as the basis for the algorithms used in the library:

  • Donald E. Knuth, The Art of Computer Programming Volume 2 Seminumerical Algorithms, 3rd edition, 1998

This documentation is copyright 2025 Matt Borland, and is distributed under the Boost Software License, Version 1.0.