Integer Utilities
Description
The library provides utility functions for safe integer types.
These operate on the non-bounded unsigned types (u8, u16, u32, u64, u128).
#include <boost/safe_numbers/integer_utilities.hpp>
isqrt
template <non_bounded_unsigned_library_type T>
BOOST_SAFE_NUMBERS_HOST_DEVICE [[nodiscard]] constexpr auto isqrt(const T val) -> T;
Returns the integer square root of val, i.e., the largest integer r such that r * r <= val.
Uses Newton’s method on the underlying hardware type. The computation cannot overflow and converges rapidly.
remove_trailing_zeros
Removes trailing decimal zeros from an unsigned integer value using a branchless algorithm based on modular multiplicative inverses (Granlund-Montgomery division).
Return Type
template <typename UInt>
struct remove_trailing_zeros_return
{
UInt trimmed_number;
std::size_t number_of_removed_zeros;
};
template <non_bounded_unsigned_library_type T>
BOOST_SAFE_NUMBERS_HOST_DEVICE [[nodiscard]] constexpr auto remove_trailing_zeros(const T n);
Removes all trailing decimal zeros from n.
Returns a remove_trailing_zeros_return containing the trimmed value and the count of removed zeros, such that trimmed_number * 10^number_of_removed_zeros == n.
is_power_10
Tests whether an unsigned integer value is an exact power of 10 (i.e., one of 1, 10, 100, 1000, …).
template <non_bounded_unsigned_library_type T>
BOOST_SAFE_NUMBERS_HOST_DEVICE [[nodiscard]] constexpr auto is_power_10(const T n) -> bool;
ilog2
Returns the integer base-2 logarithm (floor of log2) of a value.
template <non_bounded_unsigned_library_type T>
BOOST_SAFE_NUMBERS_HOST_DEVICE [[nodiscard]] constexpr auto ilog2(const T n) -> int;
Computes floor(log2(n)) using bit_width(n) - 1.
ilog10
Returns the integer base-10 logarithm (floor of log10) of a value.
Uses an O(1) algorithm based on the most significant bit position to approximate log10, refined with a single power-of-10 table lookup.
template <non_bounded_unsigned_library_type T>
BOOST_SAFE_NUMBERS_HOST_DEVICE [[nodiscard]] constexpr auto ilog10(const T n) -> int;
Computes floor(log10(n)) using num_digits(n) - 1, where num_digits approximates the digit count via log10(x) ~= log2(x) / log2(10) and refines with at most two comparisons against a power-of-10 lookup table.
ilog
Returns the integer logarithm in an arbitrary base (floor of logbase) of a value.
template <non_bounded_unsigned_library_type T>
BOOST_SAFE_NUMBERS_HOST_DEVICE [[nodiscard]] constexpr auto ilog(const T n, const T base) -> int;
Computes floor(logbase(n)) by repeated division.
For the common cases of base 2 and base 10, prefer the specialized ilog2 and ilog10 functions which run in O(1).
Parameters
-
n— The value to compute the logarithm of. Must be non-zero. -
base— The base of the logarithm. Must be >= 2.
ipow
Integer exponentiation using the exponentiation-by-squaring algorithm.
template <non_bounded_unsigned_library_type T>
BOOST_SAFE_NUMBERS_HOST_DEVICE [[nodiscard]] constexpr auto ipow(const T a, const T b) noexcept -> T;
Computes a raised to the power b using exponentiation by squaring.
The algorithm runs in O(log(b)) multiplications:
-
If
b == 0, returnsT{1}. -
If
bis odd, returnsa * ipow(a, b - 1). -
If
bis even, returnsipow(a, b / 2)^2.
If the result overflows the type, the behavior follows the overflow policy of the safe integer type (by default, throwing std::overflow_error).
is_power_2
Tests whether an unsigned integer value is an exact power of 2 (i.e., has exactly one bit set).
template <non_bounded_unsigned_library_type T>
BOOST_SAFE_NUMBERS_HOST_DEVICE [[nodiscard]] constexpr auto is_power_2(const T n) noexcept -> bool;
abs_diff
Computes the absolute difference between two integers without risk of underflow.
For unsigned types, naive subtraction a - b when b > a would underflow; abs_diff always returns the non-negative distance between the two values.
template <integral_library_type T>
BOOST_SAFE_NUMBERS_HOST_DEVICE [[nodiscard]] constexpr auto abs_diff(const T a, const T b) noexcept -> T;
Returns |a - b|, computed as a - b if a >= b, or b - a otherwise.
Works with all safe integer types: u8, u16, u32, u64, u128, and bounded_uint<Min, Max>.
div_ceil
Computes the ceiling of integer division, i.e., the smallest integer not less than the exact quotient a / b.
For unsigned types, this is equivalent to (a + b - 1) / b but computed without risk of overflow.
template <integral_library_type T>
BOOST_SAFE_NUMBERS_HOST_DEVICE [[nodiscard]] constexpr auto div_ceil(const T a, const T b) noexcept -> T;
Returns the ceiling of a / b.
When a is evenly divisible by b, returns a / b.
Otherwise, returns a / b + 1.
Works with all safe integer types: u8, u16, u32, u64, u128, and bounded_uint<Min, Max>.
next_multiple_of
Computes the smallest multiple of b that is greater than or equal to a.
This is useful for alignment calculations (e.g., aligning a size to a page boundary or block size).
template <integral_library_type T>
BOOST_SAFE_NUMBERS_HOST_DEVICE [[nodiscard]] constexpr auto next_multiple_of(const T a, const T b) noexcept -> T;
Returns the smallest value m such that m >= a and m % b == 0.
Equivalent to div_ceil(a, b) * b.
Works with all safe integer types: u8, u16, u32, u64, u128, and bounded_uint<Min, Max>.
Examples
// Copyright 2026 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/safe_numbers/integer_utilities.hpp>
#include <boost/safe_numbers/unsigned_integers.hpp>
#include <boost/safe_numbers/iostream.hpp>
#include <iostream>
int main()
{
using namespace boost::safe_numbers;
std::cout << std::boolalpha;
// Integer square root (floor of sqrt)
std::cout << "isqrt(100) = " << isqrt(u32{100}) << '\n';
std::cout << "isqrt(200) = " << isqrt(u32{200}) << '\n';
std::cout << '\n';
// Remove trailing decimal zeros
const auto rtz = remove_trailing_zeros(u32{12300});
std::cout << "remove_trailing_zeros(12300) = " << rtz.trimmed_number
<< " (removed " << rtz.number_of_removed_zeros << " zeros)\n";
std::cout << '\n';
// Power-of-N predicates
std::cout << "is_power_10(1000) = " << is_power_10(u32{1000}) << '\n';
std::cout << "is_power_10(1234) = " << is_power_10(u32{1234}) << '\n';
std::cout << "is_power_2(1024) = " << is_power_2(u32{1024}) << '\n';
std::cout << "is_power_2(1000) = " << is_power_2(u32{1000}) << '\n';
std::cout << '\n';
// Integer logarithms
std::cout << "ilog2(1024) = " << ilog2(u32{1024}) << '\n';
std::cout << "ilog10(1000) = " << ilog10(u32{1000}) << '\n';
std::cout << "ilog(80, 3) = " << ilog(u32{80}, u32{3}) << '\n';
std::cout << '\n';
// Exponentiation and arithmetic helpers
std::cout << "ipow(2, 10) = " << ipow(u32{2}, u32{10}) << '\n';
std::cout << "abs_diff(3, 10) = " << abs_diff(u32{3}, u32{10}) << '\n';
std::cout << "div_ceil(10, 3) = " << div_ceil(u32{10}, u32{3}) << '\n';
std::cout << "next_multiple_of(10, 3) = " << next_multiple_of(u32{10}, u32{3}) << '\n';
return 0;
}
Output:
isqrt(100) = 10 isqrt(200) = 14 remove_trailing_zeros(12300) = 123 (removed 2 zeros) is_power_10(1000) = true is_power_10(1234) = false is_power_2(1024) = true is_power_2(1000) = false ilog2(1024) = 10 ilog10(1000) = 3 ilog(80, 3) = 3 ipow(2, 10) = 1024 abs_diff(3, 10) = 7 div_ceil(10, 3) = 4 next_multiple_of(10, 3) = 12