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