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>
[[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>
[[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.
Return Value
A remove_trailing_zeros_return where:
-
trimmed_numberisnwith all trailing decimal zeros removed. -
number_of_removed_zerosis the count of removed zeros.
Supported Types and Ranges
| Type | Max Trailing Zeros | Algorithm Steps |
|---|---|---|
|
2 |
2 |
|
4 |
3 |
|
9 |
4 |
|
19 |
5 |
|
38 |
6 |
Example
using namespace boost::safe_numbers;
auto r1 = remove_trailing_zeros(u32{12300});
// r1.trimmed_number == 123, r1.number_of_removed_zeros == 2
auto r2 = remove_trailing_zeros(u64{1000000});
// r2.trimmed_number == 1, r2.number_of_removed_zeros == 6
auto r3 = remove_trailing_zeros(u8{static_cast<std::uint8_t>(7)});
// r3.trimmed_number == 7, r3.number_of_removed_zeros == 0
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>
[[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>
[[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>
[[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>
[[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.
Throws
-
std::domain_errorifn == 0. -
std::domain_errorifbase < 2(base 0 would cause division by zero; base 1 would cause an infinite loop).
Example
using namespace boost::safe_numbers;
auto r1 = ilog(u32{1000}, u32{10}); // r1 == 3 (floor of log10(1000))
auto r2 = ilog(u32{1024}, u32{2}); // r2 == 10 (floor of log2(1024))
auto r3 = ilog(u32{80}, u32{3}); // r3 == 3 (floor of log3(80))
auto r4 = ilog(u32{3125}, u32{5}); // r4 == 5 (5^5 = 3125)
auto r5 = ilog(u32{1}, u32{7}); // r5 == 0 (any base, log(1) = 0)
ipow
Integer exponentiation using the exponentiation-by-squaring algorithm.
template <non_bounded_unsigned_library_type T>
[[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>
[[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>
[[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>
[[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>.
Return Value
The smallest integer greater than or equal to the exact quotient a / b, as the same safe integer type T.
Example
using namespace boost::safe_numbers;
auto r1 = div_ceil(u32{10}, u32{3}); // r1 == u32{4} (ceil(3.33) = 4)
auto r2 = div_ceil(u32{9}, u32{3}); // r2 == u32{3} (exact division)
auto r3 = div_ceil(u32{0}, u32{5}); // r3 == u32{0}
auto r4 = div_ceil(u32{1}, u32{2}); // r4 == u32{1} (ceil(0.5) = 1)
auto r5 = div_ceil(u32{100}, u32{100}); // r5 == u32{1}
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>
[[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>.
Return Value
The smallest multiple of b that is greater than or equal to a, as the same safe integer type T.
When a is already a multiple of b, returns a.
When a == 0, returns 0.
Example
using namespace boost::safe_numbers;
auto r1 = next_multiple_of(u32{10}, u32{3}); // r1 == u32{12} (next multiple of 3 >= 10)
auto r2 = next_multiple_of(u32{9}, u32{3}); // r2 == u32{9} (already a multiple)
auto r3 = next_multiple_of(u32{0}, u32{5}); // r3 == u32{0}
auto r4 = next_multiple_of(u32{1}, u32{4096}); // r4 == u32{4096} (align to page size)
auto r5 = next_multiple_of(u32{4097}, u32{4096}); // r5 == u32{8192}