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
Structures and Classes
Functions
Listed by analogous STL header.
<bit>
<cmath>
-
abs
- Absolute Value
<iostream>
<numeric>
Enums
-
None
Constants
-
None
Concepts
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
Copyright and License
This documentation is copyright 2025 Matt Borland, and is distributed under the Boost Software License, Version 1.0.