Numeric

Description

The library provides overloads of standard <numeric> algorithms for safe integer types. These operate on the non-bounded types (u8, u16, u32, u64, u128) and their verified counterparts.

#include <boost/safe_numbers/numeric.hpp>

gcd

Computes the greatest common divisor of two integers using the Euclidean algorithm.

Runtime Overload

template <non_bounded_integral_library_type T>
    requires (!is_verified_type_v<T>)
constexpr auto gcd(const T m, const T n) noexcept -> T;

Returns the greatest common divisor of m and n. Delegates to std::gcd on the underlying hardware type, or to int128::gcd for 128-bit types.

Parameters

  • m — The first value.

  • n — The second value.

Return Value

The greatest common divisor of m and n, as the same safe integer type T. If both m and n are zero, returns zero.

Complexity

O(log(min(m, n))) divisions (Euclidean algorithm).

Example

using namespace boost::safe_numbers;

auto r1 = gcd(u32{12}, u32{8});       // r1 == u32{4}
auto r2 = gcd(u32{54}, u32{24});      // r2 == u32{6}
auto r3 = gcd(u64{1000000}, u64{750000});  // r3 == u64{250000}
auto r4 = gcd(u32{7}, u32{11});       // r4 == u32{1}  (coprime)
auto r5 = gcd(u32{0}, u32{42});       // r5 == u32{42}

Verified Overload

template <non_bounded_integral_library_type T>
consteval auto gcd(const verified_type_basis<T> m, const verified_type_basis<T> n) noexcept -> verified_type_basis<T>;

Compile-time only overload for verified types. Delegates to the same underlying algorithm after extracting the basis value, and wraps the result back into a verified type.

Since gcd is consteval for verified types, the result is guaranteed to be a compile-time constant.

Example

using namespace boost::safe_numbers;

constexpr auto r = gcd(verified_u32{u32{1234567890}}, verified_u32{u32{987654321}});  // r == verified_u32{u32{9}}
static_assert(gcd(verified_u64{u64{1000000000000}}, verified_u64{u64{750000000000}}) == verified_u64{u64{250000000000}});

lcm

Computes the least common multiple of two integers.

Runtime Overload

template <non_bounded_integral_library_type T>
    requires (!is_verified_type_v<T>)
constexpr auto lcm(const T m, const T n) noexcept -> T;

Returns the least common multiple of m and n. Delegates to std::lcm on the underlying hardware type, or to int128::lcm for 128-bit types.

Parameters

  • m — The first value.

  • n — The second value.

Return Value

The least common multiple of m and n, as the same safe integer type T. If either m or n is zero, returns zero.

Complexity

O(log(min(m, n))) divisions (via gcd).

Example

using namespace boost::safe_numbers;

auto r1 = lcm(u32{4}, u32{6});        // r1 == u32{12}
auto r2 = lcm(u32{12}, u32{18});      // r2 == u32{36}
auto r3 = lcm(u64{1000}, u64{750});   // r3 == u64{3000}
auto r4 = lcm(u32{7}, u32{11});       // r4 == u32{77}  (coprime)
auto r5 = lcm(u32{0}, u32{42});       // r5 == u32{0}

Verified Overload

template <non_bounded_integral_library_type T>
consteval auto lcm(const verified_type_basis<T> m, const verified_type_basis<T> n) noexcept -> verified_type_basis<T>;

Compile-time only overload for verified types. Delegates to the same underlying algorithm after extracting the basis value, and wraps the result back into a verified type.

Since lcm is consteval for verified types, the result is guaranteed to be a compile-time constant.

Example

using namespace boost::safe_numbers;

constexpr auto r = lcm(verified_u32{u32{12}}, verified_u32{u32{18}});  // r == verified_u32{u32{36}}
static_assert(lcm(verified_u64{u64{1000}}, verified_u64{u64{750}}) == verified_u64{u64{3000}});

midpoint

Computes the midpoint of two integers without overflow. The result is rounded towards the first argument a.

Runtime Overload

template <non_bounded_integral_library_type T>
    requires (!is_verified_type_v<T>)
constexpr auto midpoint(const T a, const T b) noexcept -> T;

Returns the midpoint of a and b, computed without overflow. Delegates to std::midpoint on the underlying hardware type, or to int128::midpoint for 128-bit types.

Parameters

  • a — The first value. The result rounds towards this value.

  • b — The second value.

Return Value

The integer midpoint of a and b, as the same safe integer type T. When the mathematical midpoint is not an integer, the result is rounded towards a.

Complexity

O(1).

Example

using namespace boost::safe_numbers;

auto r1 = midpoint(u32{0}, u32{10});    // r1 == u32{5}
auto r2 = midpoint(u32{1}, u32{4});     // r2 == u32{2}  (rounds towards a)
auto r3 = midpoint(u32{4}, u32{1});     // r3 == u32{3}  (rounds towards a)
auto r4 = midpoint(u32{0}, u32{0});     // r4 == u32{0}
auto r5 = midpoint(u32{3}, u32{3});     // r5 == u32{3}

Verified Overload

template <non_bounded_integral_library_type T>
consteval auto midpoint(const verified_type_basis<T> a, const verified_type_basis<T> b) noexcept -> verified_type_basis<T>;

Compile-time only overload for verified types. Delegates to the same underlying algorithm after extracting the basis value, and wraps the result back into a verified type.

Since midpoint is consteval for verified types, the result is guaranteed to be a compile-time constant.

Example

using namespace boost::safe_numbers;

constexpr auto r = midpoint(verified_u32{u32{0}}, verified_u32{u32{10}});  // r == verified_u32{u32{5}}
static_assert(midpoint(verified_u64{u64{100}}, verified_u64{u64{200}}) == verified_u64{u64{150}});