Examples
All the following examples can be found in the examples/ folder of the library.
Basic Construction
Example 1. This example demonstrates the various ways to construct uint128_t and int128_t values
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/int128/int128.hpp>
#include <boost/int128/literals.hpp>
#include <boost/int128/iostream.hpp>
#include <iostream>
#include <limits>
#include <sstream>
int main()
{
using boost::int128::uint128_t;
using boost::int128::int128_t;
std::cout << "=== uint128_t Construction ===" << std::endl;
// 1) From a builtin integer type
constexpr uint128_t from_builtin {42U};
std::cout << "From builtin (42U): " << from_builtin << std::endl;
// 2) From high and low 64-bit values (high, low)
constexpr uint128_t from_parts {UINT64_C(0x1), UINT64_C(0x0)}; // 2^64
std::cout << "From parts (1, 0) = 2^64: " << from_parts << std::endl;
constexpr uint128_t max_value {UINT64_C(0xFFFFFFFFFFFFFFFF), UINT64_C(0xFFFFFFFFFFFFFFFF)};
std::cout << "From parts (max, max): " << max_value << std::endl;
std::cout << " Equals numeric_limits max? " << std::boolalpha
<< (max_value == std::numeric_limits<uint128_t>::max()) << std::endl;
// 3) From user-defined literals (values > 2^64 without splitting)
using namespace boost::int128::literals;
const auto from_literal {"36893488147419103232"_U128}; // 2 * 2^64
std::cout << "From literal \"36893488147419103232\"_U128: " << from_literal << std::endl;
// 4) From macro (like UINT64_C but for 128-bit)
const auto from_macro {BOOST_INT128_UINT128_C(340282366920938463463374607431768211455)};
std::cout << "From BOOST_INT128_UINT128_C(max): " << from_macro << std::endl;
// 5) From input stream
std::stringstream ss;
ss.str("12345678901234567890123456789");
uint128_t from_stream;
ss >> from_stream;
std::cout << "From stringstream: " << from_stream << std::endl;
std::cout << "\n=== int128_t Construction ===" << std::endl;
// Signed from builtin
constexpr int128_t signed_builtin {-42};
std::cout << "From builtin (-42): " << signed_builtin << std::endl;
// Signed from parts (high is signed, low is unsigned)
constexpr int128_t min_value {INT64_MIN, 0};
std::cout << "From parts (INT64_MIN, 0): " << min_value << std::endl;
std::cout << " Equals numeric_limits min? "
<< (min_value == std::numeric_limits<int128_t>::min()) << std::endl;
// Signed literals (lowercase and uppercase both work)
const auto negative_literal {"-99999999999999999999"_i128};
std::cout << "From literal \"-99999999999999999999\"_i128: " << negative_literal << std::endl;
const auto positive_literal {"99999999999999999999"_I128};
std::cout << "From literal \"99999999999999999999\"_I128: " << positive_literal << std::endl;
// Signed macro
const auto from_signed_macro {BOOST_INT128_INT128_C(-170141183460469231731687303715884105728)};
std::cout << "From BOOST_INT128_INT128_C(min): " << from_signed_macro << std::endl;
std::cout << "\n=== Default and Copy Construction ===" << std::endl;
// Default construction (zero-initialized)
uint128_t default_constructed {};
std::cout << "Default constructed: " << default_constructed << std::endl;
// Copy construction
uint128_t copied {from_literal};
std::cout << "Copy constructed: " << copied << std::endl;
return 0;
}
Expected Output
=== uint128_t Construction === From builtin (42U): 42 From parts (1, 0) = 2^64: 18446744073709551616 From parts (max, max): 340282366920938463463374607431768211455 Equals numeric_limits max? true From literal "36893488147419103232"_U128: 36893488147419103232 From BOOST_INT128_UINT128_C(max): 340282366920938463463374607431768211455 From stringstream: 12345678901234567890123456789 === int128_t Construction === From builtin (-42): -42 From parts (INT64_MIN, 0): -170141183460469231731687303715884105728 Equals numeric_limits min? true From literal "-99999999999999999999"_i128: -99999999999999999999 From literal "99999999999999999999"_I128: 99999999999999999999 From BOOST_INT128_INT128_C(min): -170141183460469231731687303715884105728 === Default and Copy Construction === Default constructed: 0 Copy constructed: 36893488147419103232
Basic Arithmetic
Example 2. This example demonstrates arithmetic operations with 128-bit integers
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/int128/int128.hpp>
#include <boost/int128/iostream.hpp>
#include <iostream>
int main()
{
// The types of this library support all arithmetic operations one would expect.
// They can be between values of the same type, or the same signedness by default.
// See `mixed_type_arithmetic.cpp` for operations with different signedness.
using boost::int128::int128_t;
using boost::int128::uint128_t;
// Basic arithmetic with signed 128-bit integers
int128_t x {1000000000000LL}; // 1 trillion
int128_t y {999999999999LL}; // Just under 1 trillion
std::cout << "=== Signed 128-bit Arithmetic ===" << std::endl;
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl;
// Addition and subtraction
std::cout << "\nAddition and Subtraction:" << std::endl;
std::cout << "x + y = " << (x + y) << std::endl;
std::cout << "x - y = " << (x - y) << std::endl;
// Multiplication - results that exceed 64-bit range
std::cout << "\nMultiplication (exceeds 64-bit range):" << std::endl;
std::cout << "x * y = " << (x * y) << std::endl;
// Division and modulo
std::cout << "\nDivision and Modulo:" << std::endl;
std::cout << "x / 7 = " << (x / 7) << std::endl;
std::cout << "x % 7 = " << (x % 7) << std::endl;
// Comparisons
std::cout << "\nComparisons:" << std::endl;
std::cout << "x > y: " << std::boolalpha << (x > y) << std::endl;
std::cout << "x == y: " << (x == y) << std::endl;
std::cout << "x != y: " << (x != y) << std::endl;
// Negative values and absolute value
int128_t negative {-42};
std::cout << "\nNegative values:" << std::endl;
std::cout << "negative = " << negative << std::endl;
std::cout << "abs(negative) = " << boost::int128::abs(negative) << std::endl;
// Compound assignment operators
std::cout << "\nCompound assignment operators:" << std::endl;
int128_t z {100};
std::cout << "z = " << z << std::endl;
z += 50;
std::cout << "z += 50: " << z << std::endl;
z -= 25;
std::cout << "z -= 25: " << z << std::endl;
z *= 2;
std::cout << "z *= 2: " << z << std::endl;
z /= 5;
std::cout << "z /= 5: " << z << std::endl;
z %= 7;
std::cout << "z %= 7: " << z << std::endl;
// Unsigned 128-bit arithmetic - useful for very large positive values
std::cout << "\n=== Unsigned 128-bit Arithmetic ===" << std::endl;
uint128_t large {UINT64_C(0x1), UINT64_C(0x0)}; // 2^64
std::cout << "large (2^64) = " << large << std::endl;
std::cout << "large * 2 = " << (large * 2U) << std::endl;
std::cout << "large + large = " << (large + large) << std::endl;
// Increment and decrement
std::cout << "\nIncrement and Decrement:" << std::endl;
int128_t counter {10};
std::cout << "counter = " << counter << std::endl;
std::cout << "++counter = " << ++counter << std::endl;
std::cout << "counter++ = " << counter++ << std::endl;
std::cout << "counter = " << counter << std::endl;
std::cout << "--counter = " << --counter << std::endl;
return 0;
}
Expected Output
=== Signed 128-bit Arithmetic === x = 1000000000000 y = 999999999999 Addition and Subtraction: x + y = 1999999999999 x - y = 1 Multiplication (exceeds 64-bit range): x * y = 999999999999000000000000 Division and Modulo: x / 7 = 142857142857 x % 7 = 1 Comparisons: x > y: true x == y: false x != y: true Negative values: negative = -42 abs(negative) = 42 Compound assignment operators: z = 100 z += 50: 150 z -= 25: 125 z *= 2: 250 z /= 5: 50 z %= 7: 1 === Unsigned 128-bit Arithmetic === large (2^64) = 18446744073709551616 large * 2 = 36893488147419103232 large + large = 36893488147419103232 Increment and Decrement: counter = 10 ++counter = 11 counter++ = 11 counter = 12 --counter = 11
IO Streaming
Example 3. This example demonstrates iostream support and string conversions
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/int128/int128.hpp>
#include <boost/int128/iostream.hpp>
#include <iostream>
#include <sstream>
int main()
{
using boost::int128::int128_t;
using boost::int128::uint128_t;
std::cout << "=== Basic Streaming ===" << std::endl;
// Both types allow streaming as one would expect from a regular builtin-type
constexpr int128_t signed_value {-42};
std::cout << "Signed value: " << signed_value << std::endl;
// We can also use <iomanip> to change the output format
constexpr uint128_t unsigned_value {0x1, UINT64_MAX};
std::cout << "Unsigned value (dec): " << unsigned_value << '\n'
<< "Unsigned value (hex): " << std::hex << unsigned_value << '\n'
<< "Unsigned value (oct): " << std::oct << unsigned_value << std::endl;
// Hex also can be manipulated to be uppercase
std::cout << "Upper unsigned value: " << std::hex << std::uppercase << unsigned_value << std::endl;
// And returned to default formatting
std::cout << "Lower unsigned value: " << std::dec << std::nouppercase << unsigned_value << std::endl;
// Large values that exceed 64-bit range
std::cout << "\n=== Large Values (Beyond 64-bit) ===" << std::endl;
// 2^64 = 18446744073709551616 (first value that doesn't fit in uint64_t)
constexpr uint128_t two_to_64 {1, 0};
std::cout << "2^64 = " << two_to_64 << std::endl;
// 2^100 = a very large number
constexpr uint128_t two_to_100 {uint128_t{1} << 100};
std::cout << "2^100 = " << two_to_100 << std::endl;
// Maximum uint128_t value
constexpr auto uint_max {std::numeric_limits<uint128_t>::max()};
std::cout << "uint128_t max = " << uint_max << std::endl;
// Minimum and maximum int128_t values
constexpr auto int_min {std::numeric_limits<int128_t>::min()};
constexpr auto int_max {std::numeric_limits<int128_t>::max()};
std::cout << "int128_t min = " << int_min << std::endl;
std::cout << "int128_t max = " << int_max << std::endl;
// String conversion using stringstream
std::cout << "\n=== String Conversion with std::stringstream ===" << std::endl;
// Convert uint128_t to string
std::ostringstream oss;
oss << two_to_100;
auto str {oss.str()};
std::cout << "uint128_t to string: \"" << str << "\"" << std::endl;
// Convert string to uint128_t
std::istringstream iss {"123456789012345678901234567890"};
uint128_t parsed_value {};
iss >> parsed_value;
std::cout << "String to uint128_t: " << parsed_value << std::endl;
// Round-trip: value -> string -> value
std::cout << "\n=== Round-trip Conversion ===" << std::endl;
constexpr uint128_t original {0xDEADBEEF, 0xCAFEBABE12345678};
std::ostringstream oss2;
oss2 << original;
auto original_str {oss2.str()};
std::istringstream iss2 {original_str};
uint128_t round_tripped {};
iss2 >> round_tripped;
std::cout << "Original: " << original << std::endl;
std::cout << "As string: \"" << original_str << "\"" << std::endl;
std::cout << "Round-tripped: " << round_tripped << std::endl;
std::cout << "Match: " << std::boolalpha << (original == round_tripped) << std::endl;
return 0;
}
Expected Output
=== Basic Streaming === Signed value: -42 Unsigned value (dec): 36893488147419103231 Unsigned value (hex): 0x1ffffffffffffffff Unsigned value (oct): 03777777777777777777777 Upper unsigned value: 0X1FFFFFFFFFFFFFFFF Lower unsigned value: 36893488147419103231 === Large Values (Beyond 64-bit) === 2^64 = 18446744073709551616 2^100 = 1267650600228229401496703205376 uint128_t max = 340282366920938463463374607431768211455 int128_t min = -170141183460469231731687303715884105728 int128_t max = 170141183460469231731687303715884105727 === String Conversion with std::stringstream === uint128_t to string: "1267650600228229401496703205376" String to uint128_t: 123456789012345678901234567890 === Round-trip Conversion === Original: 68915718020162848918556923512 As string: "68915718020162848918556923512" Round-tripped: 68915718020162848918556923512 Match: true
Bitwise Functions (<bit>)
Example 4. This example demonstrates bitwise operations from the <bit> header
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// Individual headers
#include <boost/int128/int128.hpp>
#include <boost/int128/bit.hpp>
// Or you can do a single header
// #include <boost/int128.hpp>
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunused-variable"
#endif
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable:4146) // MSVC 14.1 only unary minus applied to unsigned type
#endif
#if defined(__GNUC__) && __GNUC__ <= 7 && !defined(__clang__)
int main()
{
// The following does not work in a constexpr way for old GCCs
// Clang is fine
return 0;
}
#else
int main()
{
// The functions from bit are only available for uint128_t
constexpr boost::int128::uint128_t x {1U};
// All the functions are constexpr
// Does the value have only a single bit set?
static_assert(boost::int128::has_single_bit(x), "Should have one bit");
// How many zeros from the left
static_assert(boost::int128::countl_zero(x) == 127U, "Should be 127");
// The bit width of the value
// 1 + 1 is 10 in binary which is 2 bits wide
static_assert(boost::int128::bit_width(x + x) == 2U, "2 bits wide");
// The smallest power of two not greater than the input value
static_assert(boost::int128::bit_floor(3U * x) == 2U, "2 < 3");
// The smallest power of two not Smaller than the input value
static_assert(boost::int128::bit_ceil(5U * x) == 8U, "8 > 5");
// How many zeros from the right?
static_assert(boost::int128::countr_zero(2U * x) == 1, "1 zero to the right of 10");
// How many 1-bits in the value
static_assert(boost::int128::popcount(7U * x) == 3, "111");
// Swap the bytes
// Create a value with distinct byte pattern
constexpr boost::int128::uint128_t original{
0x0123456789ABCDEFULL,
0xFEDCBA9876543210ULL
};
// Expected result after byteswap
constexpr boost::int128::uint128_t expected{
0x1032547698BADCFEULL,
0xEFCDAB8967452301ULL
};
static_assert(boost::int128::byteswap(original) == expected, "Mismatched byteswap");
static_assert(boost::int128::byteswap(expected) == original, "Mismatched byteswap");
return 0;
}
#endif
Saturating Arithmetic (<numeric>)
Example 5. This example demonstrates saturating arithmetic operations that clamp to min/max instead of overflowing
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// Individual headers
#include <boost/int128/int128.hpp>
#include <boost/int128/numeric.hpp>
#include <boost/int128/iostream.hpp>
// Or you can do a single header
// #include <boost/int128.hpp>
#include <limits>
#include <type_traits>
#include <iostream>
int main()
{
using boost::int128::uint128_t;
using boost::int128::int128_t;
// std::numeric_limits is overloaded for both types
constexpr auto uint_max {std::numeric_limits<uint128_t>::max()};
static_assert(std::is_same<decltype(uint_max), const uint128_t>::value, "Types should match");
constexpr auto int_max {std::numeric_limits<int128_t>::max()};
constexpr auto int_min {std::numeric_limits<int128_t>::min()};
std::cout << "=== Saturating Arithmetic ===" << std::endl;
std::cout << "uint128_t max = " << uint_max << std::endl;
std::cout << "int128_t max = " << int_max << std::endl;
std::cout << "int128_t min = " << int_min << std::endl;
// Saturating arithmetic returns max on overflow, or min on underflow rather than rolling over
std::cout << "\n=== Saturating Addition and Subtraction ===" << std::endl;
std::cout << "add_sat(uint_max, uint_max) = " << boost::int128::add_sat(uint_max, uint_max)
<< " (saturates to uint_max)" << std::endl;
std::cout << "sub_sat(0, uint_max) = " << boost::int128::sub_sat(uint128_t{0}, uint_max)
<< " (saturates to 0, not underflow)" << std::endl;
// This is especially useful for signed types since rollover is undefined
std::cout << "\n=== Saturating Multiplication ===" << std::endl;
std::cout << "mul_sat(int_max, 2) = " << boost::int128::mul_sat(int_max, 2)
<< " (saturates to int_max)" << std::endl;
std::cout << "mul_sat(-(int_max - 2), 5) = " << boost::int128::mul_sat(-(int_max - 2), 5)
<< " (saturates to int_min)" << std::endl;
// The only case in the library where div_sat overflows is x = int_min and y = -1
std::cout << "\n=== Saturating Division ===" << std::endl;
std::cout << "div_sat(int_min, -1) = " << boost::int128::div_sat(int_min, -1)
<< " (saturates to int_max; normally this overflows)" << std::endl;
// saturate_cast allows types to be safely converted without rollover behavior
std::cout << "\n=== Saturating Casts ===" << std::endl;
std::cout << "saturate_cast<int128_t>(uint_max) = " << boost::int128::saturate_cast<int128_t>(uint_max)
<< " (saturates to int_max)" << std::endl;
// You can also cast to builtin types
std::cout << "saturate_cast<int64_t>(int_max) = " << boost::int128::saturate_cast<std::int64_t>(int_max)
<< " (saturates to INT64_MAX)" << std::endl;
// Even of different signedness as this is treated like a static cast
std::cout << "saturate_cast<int32_t>(uint_max) = " << boost::int128::saturate_cast<std::int32_t>(uint_max)
<< " (saturates to INT32_MAX)" << std::endl;
return 0;
}
Expected Output
=== Saturating Arithmetic === uint128_t max = 340282366920938463463374607431768211455 int128_t max = 170141183460469231731687303715884105727 int128_t min = -170141183460469231731687303715884105728 === Saturating Addition and Subtraction === add_sat(uint_max, uint_max) = 340282366920938463463374607431768211455 (saturates to uint_max) sub_sat(0, uint_max) = 0 (saturates to 0, not underflow) === Saturating Multiplication === mul_sat(int_max, 2) = 170141183460469231731687303715884105727 (saturates to int_max) mul_sat(-(int_max - 2), 5) = -170141183460469231731687303715884105728 (saturates to int_min) === Saturating Division === div_sat(int_min, -1) = 170141183460469231731687303715884105727 (saturates to int_max; normally this overflows) === Saturating Casts === saturate_cast<int128_t>(uint_max) = 170141183460469231731687303715884105727 (saturates to int_max) saturate_cast<int64_t>(int_max) = 9223372036854775807 (saturates to INT64_MAX) saturate_cast<int32_t>(uint_max) = 2147483647 (saturates to INT32_MAX)
Mixed Signedness Arithmetic
Example 6. This example demonstrates arithmetic between 128-bit and built-in integer types
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#define BOOST_INT128_ALLOW_SIGN_CONVERSION
#include <boost/int128.hpp>
#include <iostream>
int main()
{
// By default, mixed type arithmetic is NOT ALLOWED
// In order for this file to compile #define BOOST_INT128_ALLOW_SIGN_CONVERSION
// BEFORE the inclusion of any file of this library (uncomment the top line)
//
// Unlike builtin types, we cannot enforce sign correctness via a compiler flag,
// so we made it the default.
std::cout << "=== Mixed Type Arithmetic with uint128_t ===" << std::endl;
constexpr boost::int128::uint128_t unsigned_value {3};
std::cout << "unsigned_value = " << unsigned_value << std::endl;
constexpr auto greater_unsigned_value {unsigned_value + 5};
std::cout << "unsigned_value + 1 = " << (unsigned_value + 1) << std::endl;
std::cout << "unsigned_value - 1 = " << (unsigned_value - 1) << std::endl;
std::cout << "unsigned_value * 2 = " << (unsigned_value * 2) << std::endl;
std::cout << "unsigned_value / 3 = " << (unsigned_value / 3) << std::endl;
std::cout << "unsigned_value % 3 = " << (unsigned_value % 3) << std::endl;
std::cout << "unsigned_value + 5 = " << (unsigned_value + 5)
<< " (same as greater_unsigned_value: " << greater_unsigned_value << ")" << std::endl;
std::cout << "\n=== Mixed Type Arithmetic with int128_t ===" << std::endl;
constexpr boost::int128::int128_t signed_value {-3};
std::cout << "signed_value = " << signed_value << std::endl;
std::cout << "signed_value + 1U = " << (signed_value + 1U) << std::endl;
std::cout << "signed_value - 4U = " << (signed_value - 4U) << std::endl;
std::cout << "signed_value * 2 = " << (signed_value * 2) << std::endl;
std::cout << "signed_value / 4U = " << (signed_value / 4U) << std::endl;
return 0;
}
Expected Output
=== Mixed Type Arithmetic with uint128_t === unsigned_value = 3 unsigned_value + 1 = 4 unsigned_value - 1 = 2 unsigned_value * 2 = 6 unsigned_value / 3 = 1 unsigned_value % 3 = 0 unsigned_value + 5 = 8 (same as greater_unsigned_value: 8) === Mixed Type Arithmetic with int128_t === signed_value = -3 signed_value + 1U = -2 signed_value - 4U = -7 signed_value * 2 = -6 signed_value / 4U = 0
Boost.Math and Boost.Random Integration
Example 7. This example demonstrates integration with Boost.Math and Boost.Random libraries
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// Allowing sign conversion is a required pre-requisite for Boost.Random
#define BOOST_INT128_ALLOW_SIGN_CONVERSION
#include <boost/int128.hpp>
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
#pragma clang diagnostic ignored "-Wold-style-cast"
#pragma clang diagnostic ignored "-Wundef"
#pragma clang diagnostic ignored "-Wstring-conversion"
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
#include <boost/math/statistics/univariate_statistics.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <iostream>
#include <limits>
#include <array>
#include <random>
// For some bizare reason that I can't figure out Clang-Cl x86 in Github Actions crashes only with C++14
// I can't replicate this crash locally
#if defined(_WIN32) && defined(__clang__) && defined(__cplusplus) && __cplusplus == 201402L
int main()
{
return 0;
}
#else
int main()
{
// Setup our rng and distribution
std::mt19937_64 rng {42};
boost::random::uniform_int_distribution<boost::int128::uint128_t> dist {0, (std::numeric_limits<boost::int128::uint128_t>::max)()};
// Create a dataset for ourselves of random uint128_ts using our dist and rng from above
std::array<boost::int128::uint128_t, 10000> data_set;
for (auto& value : data_set)
{
value = dist(rng);
}
// Perform some rudimentary statistical analysis on our dataset
std::cout << " Mean: " << boost::math::statistics::mean(data_set) << std::endl;
std::cout << "Variance: " << boost::math::statistics::variance(data_set) << std::endl;
std::cout << " Median: " << boost::math::statistics::median(data_set) << std::endl;
return 0;
}
#endif
Boost.Charconv Integration
Example 8. This example demonstrates fast string-to-number and number-to-string conversions using Boost.Charconv
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/int128/int128.hpp>
#include <boost/int128/iostream.hpp>
#include <boost/int128/charconv.hpp>
#include <boost/charconv.hpp>
#include <iostream>
#include <limits>
#include <cstring>
int main()
{
using boost::int128::uint128_t;
using boost::int128::int128_t;
char buffer[64];
// === to_chars: Convert integers to character strings ===
std::cout << "=== to_chars ===" << std::endl;
// Unsigned 128-bit to decimal string
constexpr uint128_t max_u128 {std::numeric_limits<uint128_t>::max()};
auto result {boost::charconv::to_chars(buffer, buffer + sizeof(buffer), max_u128)};
*result.ptr = '\0';
std::cout << "uint128_t max (decimal): " << buffer << std::endl;
// Signed 128-bit to decimal string
constexpr int128_t min_i128 {std::numeric_limits<int128_t>::min()};
result = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), min_i128);
*result.ptr = '\0';
std::cout << "int128_t min (decimal): " << buffer << std::endl;
// Hexadecimal output (base 16)
uint128_t hex_value {UINT64_C(0xDEADBEEF), UINT64_C(0xCAFEBABE12345678)};
result = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), hex_value, 16);
*result.ptr = '\0';
std::cout << "uint128_t (hex): 0x" << buffer << std::endl;
// Octal output (base 8)
result = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), int128_t{511}, 8);
*result.ptr = '\0';
std::cout << "int128_t 511 (octal): 0" << buffer << std::endl;
// === from_chars: Parse character strings to integers ===
std::cout << "\n=== from_chars ===" << std::endl;
// Parse decimal string to uint128_t
const char* decimal_str {"340282366920938463463374607431768211455"};
uint128_t parsed_unsigned;
boost::charconv::from_chars(decimal_str, decimal_str + std::strlen(decimal_str), parsed_unsigned);
std::cout << "Parsed \"" << decimal_str << "\"" << std::endl;
std::cout << " Result: " << parsed_unsigned << std::endl;
std::cout << " Equals max? " << std::boolalpha << (parsed_unsigned == max_u128) << std::endl;
// Parse negative decimal string to int128_t
const char* negative_str {"-170141183460469231731687303715884105728"};
int128_t parsed_signed;
boost::charconv::from_chars(negative_str, negative_str + std::strlen(negative_str), parsed_signed);
std::cout << "Parsed \"" << negative_str << "\"" << std::endl;
std::cout << " Result: " << parsed_signed << std::endl;
std::cout << " Equals min? " << (parsed_signed == min_i128) << std::endl;
// Parse hexadecimal string (base 16)
const char* hex_str {"DEADBEEFCAFEBABE12345678"};
uint128_t parsed_hex;
boost::charconv::from_chars(hex_str, hex_str + std::strlen(hex_str), parsed_hex, 16);
std::cout << "Parsed hex \"" << hex_str << "\"" << std::endl;
std::cout << " Result: " << parsed_hex << std::endl;
return 0;
}
Expected Output
=== to_chars === uint128_t max (decimal): 340282366920938463463374607431768211455 int128_t min (decimal): -170141183460469231731687303715884105728 uint128_t (hex): 0xdeadbeefcafebabe12345678 int128_t 511 (octal): 0777 === from_chars === Parsed "340282366920938463463374607431768211455" Result: 340282366920938463463374607431768211455 Equals max? true Parsed "-170141183460469231731687303715884105728" Result: -170141183460469231731687303715884105728 Equals min? true Parsed hex "DEADBEEFCAFEBABE12345678" Result: 68915718020162848918556923512
{fmt} Library Integration
Example 9. This example demonstrates formatting with the {fmt} library including alignment specifiers
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// This example demonstrates {fmt} library integration with int128 types.
// Requires {fmt} to be installed: https://github.com/fmtlib/fmt
//
// For C++20 std::format support, use <boost/int128/format.hpp> instead,
// which provides the same formatting capabilities with std::format.
#define FMT_HEADER_ONLY
#include <boost/int128/int128.hpp>
#include <boost/int128/fmt_format.hpp>
#ifdef BOOST_INT128_HAS_FMT_FORMAT
#include <fmt/format.h>
#include <iostream>
int main()
{
using boost::int128::int128_t;
using boost::int128::uint128_t;
std::cout << "=== Basic Formatting ===" << std::endl;
constexpr uint128_t unsigned_value {0xDEADBEEF, 0xCAFEBABE12345678};
constexpr int128_t signed_value {-123456789012345678};
// Default decimal formatting
std::cout << fmt::format("Default (decimal): {}", unsigned_value) << std::endl;
std::cout << fmt::format("Signed value: {}", signed_value) << std::endl;
std::cout << "\n=== Base Specifiers ===" << std::endl;
// Different bases: binary, octal, decimal, hex
constexpr uint128_t value {255};
std::cout << fmt::format("Binary: {:b}", value) << std::endl;
std::cout << fmt::format("Octal: {:o}", value) << std::endl;
std::cout << fmt::format("Decimal: {:d}", value) << std::endl;
std::cout << fmt::format("Hexadecimal: {:x}", value) << std::endl;
std::cout << fmt::format("Hex (upper): {:X}", value) << std::endl;
std::cout << "\n=== Alternate Form (Prefixes) ===" << std::endl;
// Using # for alternate form adds base prefixes
std::cout << fmt::format("Binary with prefix: {:#b}", value) << std::endl;
std::cout << fmt::format("Octal with prefix: {:#o}", value) << std::endl;
std::cout << fmt::format("Hex with prefix: {:#x}", value) << std::endl;
std::cout << fmt::format("Hex upper prefix: {:#X}", value) << std::endl;
std::cout << "\n=== Sign Options ===" << std::endl;
constexpr int128_t positive {42};
constexpr int128_t negative {-42};
// Sign specifiers: + (always show), - (default), space (space for positive)
std::cout << fmt::format("Plus sign: {:+} and {:+}", positive, negative) << std::endl;
std::cout << fmt::format("Minus only: {} and {}", positive, negative) << std::endl;
std::cout << fmt::format("Space sign: {: } and {: }", positive, negative) << std::endl;
std::cout << "\n=== Zero Padding ===" << std::endl;
// Padding with zeros (no alignment specifier)
std::cout << fmt::format("8-digit padding: {:08}", value) << std::endl;
std::cout << fmt::format("16-digit padding: {:016}", value) << std::endl;
std::cout << "\n=== Alignment ===" << std::endl;
// Left, right, and center alignment with default fill (space)
std::cout << fmt::format("Left align: '{:<10}'", positive) << std::endl;
std::cout << fmt::format("Right align: '{:>10}'", positive) << std::endl;
std::cout << fmt::format("Center align: '{:^10}'", positive) << std::endl;
std::cout << "\n=== Alignment with Fill Characters ===" << std::endl;
// Custom fill characters
std::cout << fmt::format("Left with *: '{:*<10}'", positive) << std::endl;
std::cout << fmt::format("Right with 0: '{:0>10}'", positive) << std::endl;
std::cout << fmt::format("Center with -: '{:-^10}'", positive) << std::endl;
std::cout << "\n=== Alignment with Sign ===" << std::endl;
// Alignment combined with sign specifiers
std::cout << fmt::format("Right align +: '{:>+10}'", positive) << std::endl;
std::cout << fmt::format("Left align +: '{:<+10}'", positive) << std::endl;
std::cout << fmt::format("Center align +: '{:^+11}'", positive) << std::endl;
std::cout << fmt::format("Right align -: '{:*>10}'", negative) << std::endl;
std::cout << "\n=== Alignment with Hex and Prefix ===" << std::endl;
// Alignment with base specifiers and prefixes
std::cout << fmt::format("Right align hex: '{:>10x}'", value) << std::endl;
std::cout << fmt::format("Left align hex: '{:<10x}'", value) << std::endl;
std::cout << fmt::format("Center with prefix: '{:*^#12x}'", value) << std::endl;
std::cout << "\n=== Large Values ===" << std::endl;
// Demonstrate with values beyond 64-bit range
constexpr auto uint_max {std::numeric_limits<uint128_t>::max()};
constexpr auto int_min {std::numeric_limits<int128_t>::min()};
std::cout << fmt::format("uint128_t max: {}", uint_max) << std::endl;
std::cout << fmt::format("uint128_t max (hex): {:#x}", uint_max) << std::endl;
std::cout << fmt::format("int128_t min: {}", int_min) << std::endl;
std::cout << "\n=== Combined Format Specifiers ===" << std::endl;
// Combining multiple specifiers
std::cout << fmt::format("Hex with prefix, uppercase, padded: {:#016X}", unsigned_value) << std::endl;
std::cout << fmt::format("Signed with plus, padded: {:+020}", signed_value) << std::endl;
return 0;
}
#else
#include <iostream>
int main()
{
std::cout << "This example requires {fmt} library to be installed." << std::endl;
std::cout << "Install from: https://github.com/fmtlib/fmt" << std::endl;
return 0;
}
#endif
Expected Output
=== Basic Formatting === Default (decimal): 68915718020162848918556923512 Signed value: -123456789012345678 === Base Specifiers === Binary: 11111111 Octal: 377 Decimal: 255 Hexadecimal: ff Hex (upper): FF === Alternate Form (Prefixes) === Binary with prefix: 0b11111111 Octal with prefix: 0377 Hex with prefix: 0xff Hex upper prefix: 0XFF === Sign Options === Plus sign: +42 and -42 Minus only: 42 and -42 Space sign: 42 and -42 === Zero Padding === 8-digit padding: 00000255 16-digit padding: 0000000000000255 === Alignment === Left align: '42 ' Right align: ' 42' Center align: ' 42 ' === Alignment with Fill Characters === Left with *: '42********' Right with 0: '0000000042' Center with -: '----42----' === Alignment with Sign === Right align +: ' +42' Left align +: '+42 ' Center align +: ' +42 ' Right align -: '*******-42' === Alignment with Hex and Prefix === Right align hex: ' ff' Left align hex: 'ff ' Center with prefix: '****0xff****' === Large Values === uint128_t max: 340282366920938463463374607431768211455 uint128_t max (hex): 0xffffffffffffffffffffffffffffffff int128_t min: -170141183460469231731687303715884105728 === Combined Format Specifiers === Hex with prefix, uppercase, padded: 0XDEADBEEFCAFEBABE12345678 Signed with plus, padded: -00123456789012345678
Division with Remainder (<cstdlib>)
Example 10. This example demonstrates the div() function that returns both quotient and remainder
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/int128/int128.hpp>
#include <boost/int128/cstdlib.hpp>
#include <boost/int128/iostream.hpp>
#include <iostream>
int main()
{
using boost::int128::uint128_t;
using boost::int128::int128_t;
std::cout << "=== div() Function ===" << std::endl;
std::cout << "Returns both quotient and remainder in a single operation" << std::endl;
// Unsigned division
std::cout << "\n--- Unsigned Division ---" << std::endl;
constexpr uint128_t dividend {1000000000000000000ULL};
constexpr uint128_t divisor {7};
auto uresult {boost::int128::div(dividend, divisor)};
std::cout << dividend << " / " << divisor << " = " << uresult.quot
<< " remainder " << uresult.rem << std::endl;
// Verify: quot * divisor + rem == dividend
std::cout << "Verification: " << uresult.quot << " * " << divisor
<< " + " << uresult.rem << " = " << (uresult.quot * divisor + uresult.rem) << std::endl;
// Large value division
std::cout << "\n--- Large Value Division ---" << std::endl;
constexpr uint128_t large_dividend {uint128_t{1} << 100}; // 2^100
constexpr uint128_t large_divisor {uint128_t{1} << 50}; // 2^50
auto large_result {boost::int128::div(large_dividend, large_divisor)};
std::cout << "2^100 / 2^50 = " << large_result.quot
<< " remainder " << large_result.rem << std::endl;
// Signed division
std::cout << "\n--- Signed Division ---" << std::endl;
constexpr int128_t signed_dividend {-100};
constexpr int128_t signed_divisor {7};
auto sresult {boost::int128::div(signed_dividend, signed_divisor)};
std::cout << signed_dividend << " / " << signed_divisor << " = " << sresult.quot
<< " remainder " << sresult.rem << std::endl;
// Different sign combinations
std::cout << "\n--- Sign Combinations ---" << std::endl;
constexpr int128_t pos {17};
constexpr int128_t neg {-17};
constexpr int128_t div_pos {5};
constexpr int128_t div_neg {-5};
auto pp {boost::int128::div(pos, div_pos)};
auto pn {boost::int128::div(pos, div_neg)};
auto np {boost::int128::div(neg, div_pos)};
auto nn {boost::int128::div(neg, div_neg)};
std::cout << " 17 / 5 = " << pp.quot << " remainder " << pp.rem << std::endl;
std::cout << " 17 / -5 = " << pn.quot << " remainder " << pn.rem << std::endl;
std::cout << "-17 / 5 = " << np.quot << " remainder " << np.rem << std::endl;
std::cout << "-17 / -5 = " << nn.quot << " remainder " << nn.rem << std::endl;
// Edge case: dividend smaller than divisor
std::cout << "\n--- Edge Cases ---" << std::endl;
auto small_div {boost::int128::div(uint128_t{3}, uint128_t{10})};
std::cout << "3 / 10 = " << small_div.quot << " remainder " << small_div.rem << std::endl;
return 0;
}
Expected Output
=== div() Function === Returns both quotient and remainder in a single operation --- Unsigned Division --- 1000000000000000000 / 7 = 142857142857142857 remainder 1 Verification: 142857142857142857 * 7 + 1 = 1000000000000000000 --- Large Value Division --- 2^100 / 2^50 = 1125899906842624 remainder 0 --- Signed Division --- -100 / 7 = -14 remainder -2 --- Sign Combinations --- 17 / 5 = 3 remainder 2 17 / -5 = -3 remainder 2 -17 / 5 = -3 remainder -2 -17 / -5 = 3 remainder -2 --- Edge Cases --- 3 / 10 = 0 remainder 3
Numeric Algorithms (<numeric>)
Example 11. This example demonstrates gcd, lcm, and midpoint algorithms
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/int128/int128.hpp>
#include <boost/int128/numeric.hpp>
#include <boost/int128/iostream.hpp>
#include <iostream>
int main()
{
using boost::int128::uint128_t;
using boost::int128::int128_t;
std::cout << "=== Greatest Common Divisor (gcd) ===" << std::endl;
// Basic gcd
constexpr uint128_t a {48};
constexpr uint128_t b {18};
std::cout << "gcd(" << a << ", " << b << ") = " << boost::int128::gcd(a, b) << std::endl;
// gcd with larger values
constexpr uint128_t large_a {123456789012345678ULL};
constexpr uint128_t large_b {987654321098765432ULL};
std::cout << "gcd(" << large_a << ", " << large_b << ") = "
<< boost::int128::gcd(large_a, large_b) << std::endl;
// gcd with 128-bit values
constexpr uint128_t huge_a {uint128_t{1} << 100};
constexpr uint128_t huge_b {uint128_t{1} << 80};
std::cout << "gcd(2^100, 2^80) = " << boost::int128::gcd(huge_a, huge_b) << " (= 2^80)" << std::endl;
// Signed gcd (always returns positive)
constexpr int128_t neg_a {-48};
constexpr int128_t neg_b {18};
std::cout << "gcd(" << neg_a << ", " << neg_b << ") = "
<< boost::int128::gcd(neg_a, neg_b) << " (always positive)" << std::endl;
std::cout << "\n=== Least Common Multiple (lcm) ===" << std::endl;
// Basic lcm
constexpr uint128_t x {12};
constexpr uint128_t y {18};
std::cout << "lcm(" << x << ", " << y << ") = " << boost::int128::lcm(x, y) << std::endl;
// lcm with coprime numbers
constexpr uint128_t p {7};
constexpr uint128_t q {11};
std::cout << "lcm(" << p << ", " << q << ") = " << boost::int128::lcm(p, q)
<< " (coprime: lcm = p * q)" << std::endl;
// Relationship: gcd(a,b) * lcm(a,b) = a * b
std::cout << "\nVerifying gcd * lcm = a * b:" << std::endl;
auto g {boost::int128::gcd(x, y)};
auto l {boost::int128::lcm(x, y)};
std::cout << "gcd(" << x << ", " << y << ") * lcm(" << x << ", " << y << ") = "
<< (g * l) << std::endl;
std::cout << x << " * " << y << " = " << (x * y) << std::endl;
std::cout << "\n=== Midpoint ===" << std::endl;
// Unsigned midpoint
constexpr uint128_t low {10};
constexpr uint128_t high {20};
std::cout << "midpoint(" << low << ", " << high << ") = "
<< boost::int128::midpoint(low, high) << std::endl;
// Midpoint with odd sum (rounds toward first argument)
constexpr uint128_t odd_low {10};
constexpr uint128_t odd_high {21};
std::cout << "midpoint(" << odd_low << ", " << odd_high << ") = "
<< boost::int128::midpoint(odd_low, odd_high) << " (rounds toward first arg)" << std::endl;
std::cout << "midpoint(" << odd_high << ", " << odd_low << ") = "
<< boost::int128::midpoint(odd_high, odd_low) << " (rounds toward first arg)" << std::endl;
// Midpoint avoids overflow (unlike (a+b)/2)
std::cout << "\n--- Overflow-safe midpoint ---" << std::endl;
constexpr auto uint_max {std::numeric_limits<uint128_t>::max()};
constexpr auto uint_max_minus_10 {uint_max - 10U};
std::cout << "midpoint(uint128_max, uint128_max - 10) = "
<< boost::int128::midpoint(uint_max, uint_max_minus_10) << std::endl;
std::cout << "(This would overflow if computed as (a + b) / 2)" << std::endl;
// Signed midpoint
std::cout << "\n--- Signed midpoint ---" << std::endl;
constexpr int128_t neg {-100};
constexpr int128_t pos {100};
std::cout << "midpoint(" << neg << ", " << pos << ") = "
<< boost::int128::midpoint(neg, pos) << std::endl;
constexpr int128_t neg2 {-100};
constexpr int128_t neg3 {-50};
std::cout << "midpoint(" << neg2 << ", " << neg3 << ") = "
<< boost::int128::midpoint(neg2, neg3) << std::endl;
return 0;
}
Expected Output
=== Greatest Common Divisor (gcd) === gcd(48, 18) = 6 gcd(123456789012345678, 987654321098765432) = 2 gcd(2^100, 2^80) = 1208925819614629174706176 (= 2^80) gcd(-48, 18) = 6 (always positive) === Least Common Multiple (lcm) === lcm(12, 18) = 36 lcm(7, 11) = 77 (coprime: lcm = p * q) Verifying gcd * lcm = a * b: gcd(12, 18) * lcm(12, 18) = 216 12 * 18 = 216 === Midpoint === midpoint(10, 20) = 15 midpoint(10, 21) = 15 (rounds toward first arg) midpoint(21, 10) = 16 (rounds toward first arg) --- Overflow-safe midpoint --- midpoint(uint128_max, uint128_max - 10) = 340282366920938463463374607431768211450 (This would overflow if computed as (a + b) / 2) --- Signed midpoint --- midpoint(-100, 100) = 0 midpoint(-100, -50) = -75