Arithmetic & Logic Operations
Header aarith/integer/integer_operations.hpp
-
namespace aarith
Functions
-
template<typename I, typename T>
constexpr auto expanding_add(const I &a, const T &b, const bool initial_carry) Adds two unsigned integers of, possibly, different bit widths.
- Template Parameters
I – Integer type of the first summand
T – Integer type of the second summand
- Parameters
a – First summand
b – Second summand
initial_carry – True if there is an initial carry coming in
- Returns
Sum of a and b with bit width max(I::width,T::width)+1
-
template<typename I>
constexpr auto sub(const I &a, const I &b) -> I Computes the difference of two integers.
- Template Parameters
I – The integer type used in the subtraction
- Parameters
a – Minuend
b – Subtrahend
- Returns
Difference between a and b
-
template<typename I, typename T>
constexpr auto expanding_sub(const I &a, const T &b) Subtracts two integers of, possibly, different bit widths.
Expanding does not, in contrast to
See also
expanding_add, ensure that no underflow will happen. It simply makes sure that the resulting bit width is the larger of both input bit widths.
- Template Parameters
W – Width of the minuend
V – Width of the subtrahend
- Parameters
a – Minuend
b – Subtrahend
- Returns
Difference of correct bit width
-
template<typename I>
I constexpr add(const I &a, const I &b) Adds two integers.
- Template Parameters
I – The integer type used for the addition
- Parameters
a – First summand
b – Second summand
- Returns
Sum of a and b
-
template<std::size_t W, std::size_t V, typename WordType>
constexpr uinteger<W + V, WordType> schoolbook_expanding_mul(const uinteger<W, WordType> &a, const uinteger<V, WordType> &b) Multiplies two unsigned integers expanding the bit width so that the result fits.
This implements the simplest multiplication algorithm (binary “long multiplication”) that adds up the partial products everywhere where the first multiplicand has a 1 bit. The simplicity, of course, comes at the cost of performance.
- Template Parameters
W – The bit width of the first multiplicand
V – The bit width of the second multiplicand
- Parameters
a – First multiplicand
b – Second multiplicand
- Returns
Product of a and b
-
template<typename I, typename = std::enable_if_t<is_integral_v<I> && is_unsigned_v<I>>>
constexpr I schoolbook_mul(const I &a, const I &b) Multiplies two integers.
The result is then cropped to fit the initial bit width
See also
booth_expanding_mul for that.
Note
No Type conversion is performed. If the bit widths do not match, the code will not compile! Use
- Template Parameters
I – The integer type to operate on
- Parameters
a – First multiplicand
b – Second multiplicand
- Returns
Product of a and b
-
template<std::size_t W, std::size_t V, typename WordType>
constexpr uinteger<W + V, WordType> expanding_karazuba(const uinteger<W, WordType> &a, const uinteger<V, WordType> &b) Multiplies two unsigned integers using the Karazuba algorithm expanding the bit width so that the result fits.
This implements the karazuba multiplication algorithm (divide and conquer).
- Template Parameters
W – The bit width of the first multiplicant
V – The bit width of the second multiplicant
- Parameters
a – First multiplicant
b – Second multiplicant
- Returns
Product of a and b
-
template<std::size_t W, std::size_t V, typename WordType>
constexpr std::pair<uinteger<W, WordType>, uinteger<W, WordType>> restoring_division(const uinteger<W, WordType> &numerator, const uinteger<V, WordType> &denominator) Implements the restoring division algorithm.
- Parameters
numerator – The number that is to be divided
denominator – The number that divides the other number
- Template Parameters
W – Width of the numbers used in division.
- Returns
Pair of (quotient, remainder)
-
template<typename I>
constexpr auto remainder(const I &numerator, const I &denominator) -> I Computes the remainder of the division of one integer by another integer.
Note
For signed integers, weird under-/overflows for ::min() may occur
- Template Parameters
I – Integer type to work on
- Parameters
numerator – The number that is to be divided
denominator – The number that divides the other number
- Returns
The remainder of the division operation
-
template<typename I>
constexpr auto div(const I &numerator, const I &denominator) -> I Divides one integer by another integer.
Note
integer<W>::min/integer<W>(-1) will return <integer<W>::min,0>, i.e. some weird overflow happens for signed integers
- Template Parameters
I – Integer type to work on
- Parameters
numerator – The number that is to be divided
denominator – The number that divides the other number
- Returns
The quotient of the division operation
-
template<size_t Width, typename WordType>
constexpr auto abs(const integer<Width, WordType> &n) -> integer<Width, WordType> Computes the absolute value of a given signed integer.
There is a potential loss of precision as abs(integer::min) > integer::max
- Template Parameters
Width – The width of the signed integer
- Parameters
n – The signed inter to be “absolute valued”
- Returns
The absolute value of the signed integer
-
template<size_t Width, typename WordType>
constexpr auto expanding_abs(const integer<Width, WordType> &n) -> uinteger<Width, WordType> Computes the absolute value of a given signed integer.
This method returns an unsigned integer. This means that the absolute value will fit and no overflow will happen.
- Template Parameters
Width – The width of the signed integer
- Parameters
n – The signed inter to be “absolute valued”
- Returns
The absolute value of the signed integer
-
template<class IntA, class IntB>
constexpr auto fun_add_expand(const IntA &a, const IntB &b, const bool initial_carry = false) Adds two signed integers of, possibly, different bit widths.
This is an implementation using a more functional style of programming. It is not particularly fast and only here for educational purposes. You can use method as a means to understand how to work on an integer.
- Template Parameters
IntA – The integer type of the first summand
IntB – The integer type of the second summand
- Parameters
a – First summand
b – Second summand
initial_carry – True if there is an initial carry coming in
- Returns
Sum of correct maximal bit width
-
template<typename I>
constexpr auto fun_add(const I &a, const I &b, const bool initial_carry = false) -> I Adds two integers of, possibly, different bit widths.
See also
fun_add_expand
- Template Parameters
I – Integer type used in the addition
- Parameters
a – First summand
b – Second summand
initial_carry – True if there is an initial carry coming in
- Returns
Sum of a and b
-
template<size_t Width, typename WordType>
auto constexpr operator>>=(integer<Width, WordType> &lhs, const size_t rhs) -> integer<Width, WordType> Arithmetic right-shift operator.
This shift preserves the signedness of the integer.
- Template Parameters
Width – The width of the signed integer
- Parameters
lhs – The integer to be shifted
rhs – The number of bits to be shifted
- Returns
The shifted integer
-
template<size_t Width, typename WordType, typename U, typename = std::enable_if_t<is_unsigned_v<U>>>
auto constexpr operator>>=(integer<Width, WordType> &lhs, const U &rhs) -> integer<Width, WordType>&
-
template<size_t Width, typename WordType>
auto constexpr operator>>(const integer<Width, WordType> &lhs, const size_t rhs) -> integer<Width, WordType> Arithmetic right-shift operator.
This shift preserves the signedness of the integer.
- Template Parameters
Width – The width of the signed integer
- Parameters
lhs – The integer to be shifted
rhs – The number of bits to be shifted
- Returns
The shifted integer
-
template<size_t Width, typename WordType, typename U, typename = std::enable_if_t<is_unsigned_v<U>>>
auto constexpr operator>>(const integer<Width, WordType> &lhs, const U &rhs) -> integer<Width, WordType>
-
template<typename I, typename = std::enable_if_t<is_integral_v<I>>>
I &operator--(I &a)
-
template<typename I, typename = std::enable_if_t<is_integral_v<I>>>
I operator--(I &a, int)
-
template<typename I, typename = std::enable_if_t<is_integral_v<I>>>
I &operator++(I &a)
-
template<typename I, typename = std::enable_if_t<is_integral_v<I>>>
I operator++(I &a, int)
-
template<size_t W, size_t V, typename WordType>
constexpr auto naive_expanding_mul(const integer<W, WordType> &m, const integer<V, WordType> &r) Naively multiplies two signed integers.
- Template Parameters
W – The bit width of the first multiplicand
V – The bit width of the second multiplicand
- Parameters
a – First multiplicand
b – Second multiplicand
- Returns
Product of a and b
-
template<size_t W, typename WordType>
constexpr integer<W, WordType> naive_mul(const integer<W, WordType> &a, const integer<W, WordType> &b) Naively multiplies two integers.
The result is then cropped to fit the initial bit width
See also
booth_expanding_mul for that.
Note
No Type conversion is performed. If the bit widths do not match, the code will not compile! Use
- Template Parameters
I – The integer type to operate on
- Parameters
a – First multiplicand
b – Second multiplicand
- Returns
Product of a and b
-
template<size_t x, size_t y, typename WordType>
constexpr auto booth_expanding_mul(const integer<x, WordType> &m, const integer<y, WordType> &r) -> integer<y + x, WordType> Multiplies two signed integers.
This implements the Booth multiplication algorithm with extension to correctly handle the most negative number. See https://en.wikipedia.org/wiki/Booth%27s_multiplication_algorithm for details.
- Template Parameters
x – The bit width of the first multiplicant
y – The bit width of the second multiplicant
- Parameters
m – Multiplicand
r – Multiplier
- Returns
Product of m and r
-
template<size_t W, typename WordType>
constexpr integer<W, WordType> booth_mul(const integer<W, WordType> &a, const integer<W, WordType> &b) Multiplies two integers.
The result is then cropped to fit the initial bit width
See also
booth_expanding_mul for that.
Note
No Type conversion is performed. If the bit widths do not match, the code will not compile! Use
- Template Parameters
I – The integer type to operate on
- Parameters
a – First multiplicand
b – Second multiplicand
- Returns
Product of a and b
-
template<size_t x, size_t y, typename WordType>
constexpr auto booth_inplace_expanding_mul(const integer<x, WordType> &m, const integer<y, WordType> &r) -> integer<y + x, WordType> Multiplies two signed integers.
This implements the Booth multiplication algorithm with extension to correctly handle the most negative number. See https://en.wikipedia.org/wiki/Booth%27s_multiplication_algorithm for details.
- Template Parameters
x – The bit width of the first multiplicant
y – The bit width of the second multiplicant
- Parameters
m – Multiplicand
r – Multiplier
- Returns
Product of m and r
-
template<size_t W, typename WordType>
constexpr integer<W, WordType> booth_inplace_mul(const integer<W, WordType> &a, const integer<W, WordType> &b) Multiplies two integers.
The result is then cropped to fit the initial bit width
See also
booth_expanding_mul for that.
Note
No Type conversion is performed. If the bit widths do not match, the code will not compile! Use
- Template Parameters
I – The integer type to operate on
- Parameters
a – First multiplicand
b – Second multiplicand
- Returns
Product of a and b
-
template<size_t W, typename WordType>
constexpr auto negate(const integer<W, WordType> &n) -> integer<W, WordType> Negates the value.
- Template Parameters
W – The width of the signed integer
- Parameters
n – The signed integer whose sign is to be changed
- Returns
The negative value of the signed integer
-
template<size_t W, typename WordType>
constexpr int8_t signum(integer<W, WordType> n) Computes the sign of the integer.
For the number zero, the function returns a signum of 0, -1 for negative numbers and +1 for positive numbers.
- Template Parameters
W – The width of the integer
WordType – The word type to store the data in
- Parameters
n – The integer
- Returns
The sign of the integer
-
template<size_t W, typename WordType>
constexpr int8_t signum(uinteger<W, WordType> n) Computes the sign of the unsigned integer.
For the number zero, the function returns a signum of 0 and a 1 for every other number.
- Template Parameters
W – The width of the unsigned integer
- Parameters
n – The integer
- Returns
The sign of the integer
-
template<std::size_t W, std::size_t V, typename WordType>
constexpr std::pair<integer<W, WordType>, integer<W, WordType>> restoring_division(const integer<W, WordType> &numerator, const integer<V, WordType> &denominator) Implements the restoring division algorithm.
Note
integer<W>::min/integer<W>(-1) will return <integer<W>::min,0>, i.e. some weird overflow happens
- Parameters
numerator – The number that is to be divided
denominator – The number that divides the other number
- Template Parameters
W – Width of the numbers used in division.
- Returns
Pair of (quotient, remainder)
-
template<typename I, typename = std::enable_if_t<is_integral_v<I>>>
constexpr I mul(const I &a, const I &b)
-
template<typename I, typename = std::enable_if_t<is_integral_v<I>>>
auto constexpr expanding_mul(const I &a, const I &b)
-
template<typename IntegerType>
IntegerType pow(const IntegerType &base, const size_t exponent) Exponentiation function.
Note
This function does not make any attempts to be fast or to prevent overflows!
Note
If exponent equals std::numeric_limits<size_t>::max(), this method throws an exception, unless base equals zero
- Template Parameters
W – Bit width of the integer
- Parameters
base –
exponent –
- Returns
The base to the power of the exponent
-
template<typename IntegerType>
IntegerType pow(const IntegerType &base, const IntegerType &exponent) Exponentiation function.
Note
This function does not make any attempts to be fast or to prevent overflows!
Note
If exponent equals std::numeric_limits<IntegerType>::max(), this method throws an exception, unless base equals zero
- Template Parameters
IntegerType – The type of integer used in the computation
- Parameters
base –
exponent –
- Returns
The base to the power of the exponent
-
template<std::size_t W, typename WordType>
constexpr uinteger<W, WordType> karazuba(const uinteger<W, WordType> &a, const uinteger<W, WordType> &b) Multiplies two unsigned integers using the Karazuba algorithm.
This implements the karazuba multiplication algorithm (divide and conquer).
- Template Parameters
W – The bit width of the multiplicants
- Parameters
a – First multiplicant
b – Second multiplicant
- Returns
Product of a and b
-
template<typename Integer>
constexpr Integer distance(const Integer &a, const Integer &b) Computes the distance (i.e. the absolute difference) between two integers.
- Template Parameters
Integer – The integer type to operate on
- Parameters
a – First integer
b – Second integer
- Returns
The distance between the two integers
-
template<typename W, typename I, typename = std::enable_if_t<is_word_array_v<W> && is_integral_v<I> && is_unsigned_v<I>>>
constexpr auto operator>>=(W &lhs, const I rhs) -> W Left-shift assignment operator.
- Template Parameters
W – The word_container type to work on
- Parameters
lhs – The word_container to be shifted
rhs – The number of bits to shift
- Returns
The shifted word_container
-
template<typename W, typename I, typename = std::enable_if_t<is_word_array_v<W> && is_integral_v<I> && is_unsigned_v<I>>>
constexpr auto operator>>(const W &lhs, const I rhs) -> W Left-shift assignment operator.
- Template Parameters
W – The word_container type to work on
- Parameters
lhs – The word_container to be shifted
rhs – The number of bits to shift
- Returns
The shifted word_container
-
namespace integer_operators
Convenience namespace to include when code should be written the “normal” way. There is one caveat though: No automatic type conversion will take place!
Functions
-
template<typename I, typename = std::enable_if_t<is_integral<I>::value>>
auto constexpr operator-(const I &num) -> I
-
template<typename I, typename = std::enable_if_t<is_integral<I>::value>>
auto constexpr operator+(const I &lhs, const I &rhs) -> I
-
template<typename I, typename = std::enable_if_t<is_integral<I>::value>>
auto constexpr operator-(const I &lhs, const I &rhs) -> I
-
template<typename I, typename = std::enable_if_t<is_integral_v<I>>>
auto constexpr operator*(const I &lhs, const I &rhs) -> I
-
template<typename I, typename = std::enable_if_t<is_integral<I>::value>>
-
template<typename I, typename T>