Added full rounded integral division

This commit is contained in:
John Wellbelove 2025-08-12 15:13:03 +01:00
parent ddfd3fa443
commit 86f76933c1
4 changed files with 225 additions and 114 deletions

View File

@ -9,7 +9,7 @@ https://www.etlcpp.com
Copyright(c) 2025 John Wellbelove
Permission is hereby granted, free of charge, to any person obtaining num copy
Permission is hereby granted, free of charge, to any person obtaining numerator copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
@ -40,8 +40,8 @@ namespace etl
namespace private_rounded_integral_division
{
//*****************************************************************************
///\brief Checks if two values have the same sign.
/// For signed integral types.
// Checks if two values have the same sign.
// For signed integral types.
//*****************************************************************************
template <typename T>
ETL_CONSTEXPR
@ -52,13 +52,13 @@ namespace etl
}
//*****************************************************************************
///\brief Checks if two values have the same sign.
/// For unsigned integral types.
// Checks if two values have the same sign.
// For unsigned integral types.
//*****************************************************************************
template <typename T>
ETL_CONSTEXPR
typename etl::enable_if<etl::is_integral<T>::value && etl::is_unsigned<T>::value, bool>::type
are_same_sign(T a, T b) ETL_NOEXCEPT
are_same_sign(T /*a*/, T /*b*/) ETL_NOEXCEPT
{
return true;
}
@ -68,15 +68,18 @@ namespace etl
///\brief Integral division with rounding to ceiling.
/// For signed integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to ceiling.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value && etl::is_signed<T>::value, T>::type
divide_round_to_ceiling(T num, T den) ETL_NOEXCEPT
divide_round_to_ceiling(T numerator, T denominator) ETL_NOEXCEPT
{
const T remainder = num % den;
const T remainder = numerator % denominator;
T quotient = num / den;
T quotient = numerator / denominator;
// If remainder is zero, already exact
if (remainder == 0)
@ -85,13 +88,17 @@ namespace etl
}
// If signs are the same, increment quotient
return private_rounded_integral_division::are_same_sign(num, den) ? quotient + 1 : quotient;
return private_rounded_integral_division::are_same_sign(numerator, denominator) ? quotient + 1 : quotient;
}
//***************************************************************************
///\brief Integral division with rounding to ceiling.
/// For signed integral types.
/// For different argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to ceiling.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
@ -100,28 +107,31 @@ namespace etl
etl::is_signed<T1>::value &&
etl::is_signed<T2>::value,
typename etl::common_type<T1, T2>::type>::type
divide_round_to_ceiling(T1 num, T2 den) ETL_NOEXCEPT
divide_round_to_ceiling(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
return divide_round_to_ceiling(static_cast<type>(num), static_cast<type>(den));
return divide_round_to_ceiling(static_cast<type>(numerator), static_cast<type>(denominator));
}
//***************************************************************************
///\brief Integral division with rounding to ceiling.
/// For unsigned integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to ceiling.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_unsigned<T>::value,
T>::type
divide_round_to_ceiling(T num, T den) ETL_NOEXCEPT
divide_round_to_ceiling(T numerator, T denominator) ETL_NOEXCEPT
{
const T remainder = num % den;
const T remainder = numerator % denominator;
T quotient = num / den;
T quotient = numerator / denominator;
// If remainder is zero, already exact, otherwise, increment quotient
return remainder == 0U ? quotient : quotient + 1U;
@ -131,6 +141,10 @@ namespace etl
///\brief Integral division with rounding to ceiling.
/// For unsigned integral types.
/// For different argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to ceiling.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
@ -139,28 +153,31 @@ namespace etl
etl::is_unsigned<T1>::value &&
etl::is_unsigned<T2>::value,
typename etl::common_type<T1, T2>::type>::type
divide_round_to_ceiling(T1 num, T2 den) ETL_NOEXCEPT
divide_round_to_ceiling(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
return divide_round_to_ceiling(static_cast<type>(num), static_cast<type>(den));
return divide_round_to_ceiling(static_cast<type>(numerator), static_cast<type>(denominator));
}
//***************************************************************************
///\brief Integral division with rounding to floor.
/// For signed integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to floor.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_signed<T>::value,
T>::type
divide_round_to_floor(T num, T den) ETL_NOEXCEPT
divide_round_to_floor(T numerator, T denominator) ETL_NOEXCEPT
{
const T remainder = num % den;
const T remainder = numerator % denominator;
T quotient = num / den;
T quotient = numerator / denominator;
// If remainder is zero, already exact
if (remainder == 0)
@ -169,13 +186,17 @@ namespace etl
}
// If signs are different, decrement quotient
return private_rounded_integral_division::are_same_sign(num, den) ? quotient : quotient - 1;
return private_rounded_integral_division::are_same_sign(numerator, denominator) ? quotient : quotient - 1;
}
//***************************************************************************
///\brief Integral division with rounding to floor.
/// For signed integral types.
/// For different argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to floor.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
@ -184,33 +205,40 @@ namespace etl
etl::is_signed<T1>::value &&
etl::is_signed<T2>::value,
typename etl::common_type<T1, T2>::type>::type
divide_round_to_floor(T1 num, T2 den) ETL_NOEXCEPT
divide_round_to_floor(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
return divide_round_to_floor(static_cast<type>(num), static_cast<type>(den));
return divide_round_to_floor(static_cast<type>(numerator), static_cast<type>(denominator));
}
//***************************************************************************
///\brief Integral division with rounding to floor.
/// For unsigned integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to floor.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_unsigned<T>::value,
T>::type
divide_round_to_floor(T num, T den) ETL_NOEXCEPT
divide_round_to_floor(T numerator, T denominator) ETL_NOEXCEPT
{
return num / den;
return numerator / denominator;
}
//***************************************************************************
///\brief Integral division with rounding to floor.
/// For unsigned integral types.
/// For different argument types.
//***************************************************************************
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to floor.
/// Return type is the etl::common_type<T1, T2>::type.
/// //***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
@ -218,33 +246,36 @@ namespace etl
etl::is_unsigned<T1>::value &&
etl::is_unsigned<T2>::value,
typename etl::common_type<T1, T2>::type>::type
divide_round_to_floor(T1 num, T2 den) ETL_NOEXCEPT
divide_round_to_floor(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
const type common_num = num;
const type common_den = den;
const type common_numerator = numerator;
const type common_denominator = denominator;
return common_num / common_den;
return common_numerator / common_denominator;
}
//***************************************************************************
///\brief Integral division with rounding towards infinity.
/// For signed integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to infinity.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_signed<T>::value,
T>::type
divide_round_to_infinity(T num, T den) ETL_NOEXCEPT
divide_round_to_infinity(T numerator, T denominator) ETL_NOEXCEPT
{
const T remainder = num % den;
const T remainder = numerator % denominator;
T quotient = num / den;
T quotient = numerator / denominator;
if (private_rounded_integral_division::are_same_sign(num, den))
if (private_rounded_integral_division::are_same_sign(numerator, denominator))
{
// Same sign, round towards +infinity
quotient = remainder ? quotient + 1 : quotient;
@ -262,6 +293,10 @@ namespace etl
///\brief Integral division with rounding towards infinity.
/// For signed integral types.
/// For different argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to infinity.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
@ -270,28 +305,31 @@ namespace etl
etl::is_signed<T1>::value &&
etl::is_signed<T2>::value,
typename etl::common_type<T1, T2>::type>::type
divide_round_to_infinity(T1 num, T2 den) ETL_NOEXCEPT
divide_round_to_infinity(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
return divide_round_to_infinity(static_cast<type>(num), static_cast<type>(den));
return divide_round_to_infinity(static_cast<type>(numerator), static_cast<type>(denominator));
}
//***************************************************************************
///\brief Integral division with rounding towards infinity.
/// For unsigned integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to infinity.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_unsigned<T>::value,
T>::type
divide_round_to_infinity(T num, T den) ETL_NOEXCEPT
divide_round_to_infinity(T numerator, T denominator) ETL_NOEXCEPT
{
const T remainder = num % den;
const T remainder = numerator % denominator;
T quotient = num / den;
T quotient = numerator / denominator;
return remainder ? quotient + 1U : quotient;
}
@ -300,6 +338,10 @@ namespace etl
///\brief Integral division with rounding towards infinity.
/// For unsigned integral types.
/// For different argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to infinity.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
@ -308,77 +350,88 @@ namespace etl
etl::is_unsigned<T1>::value &&
etl::is_unsigned<T2>::value,
typename etl::common_type<T1, T2>::type>::type
divide_round_to_infinity(T1 num, T2 den) ETL_NOEXCEPT
divide_round_to_infinity(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
return divide_round_to_infinity(static_cast<type>(num), static_cast<type>(den));
return divide_round_to_infinity(static_cast<type>(numerator), static_cast<type>(denominator));
}
//***************************************************************************
///\brief Integral division with rounding towards zero.
/// For integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to zero.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_unsigned<T>::value,
T>::type
divide_round_to_zero(T num, T den) ETL_NOEXCEPT
divide_round_to_zero(T numerator, T denominator) ETL_NOEXCEPT
{
return num / den;
return numerator / denominator;
}
//***************************************************************************
///\brief Integral division with rounding towards zero.
/// For integral types.
/// For different argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to zero.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
etl::is_integral<T2>::value,
typename etl::common_type<T1, T2>::type>::type
divide_round_to_zero(T1 num, T2 den) ETL_NOEXCEPT
divide_round_to_zero(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
// Cast to common type to avoid overflow.
const type common_num = num;
const type common_den = den;
const type common_numerator = numerator;
const type common_denominator = denominator;
return common_num / common_den;
return common_numerator / common_denominator;
}
//***************************************************************************
///\brief Integral division with rounding to half up.
/// For signed integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half up.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_signed<T>::value,
T>::type
divide_round_half_up(T num, T den) ETL_NOEXCEPT
divide_round_half_up(T numerator, T denominator) ETL_NOEXCEPT
{
// Normal division
T quotient = num / den;
T remainder = num % den;
T quotient = numerator / denominator;
const T remainder = numerator % denominator;
// Work with magnitudes in unsigned form (avoids abs() overflow)
typedef typename std::make_unsigned<T>::type utype;
utype abs_rem = remainder < 0 ? utype(0) - utype(remainder) : utype(remainder);
utype abs_den = den < 0 ? utype(0) - utype(den) : utype(den);
utype abs_remainder = remainder < 0 ? utype(0) - utype(remainder) : utype(remainder);
utype abs_denominator = denominator < 0 ? utype(0) - utype(denominator) : utype(denominator);
// Threshold for rounding up (half the denominator, rounded up)
utype half_den = (abs_den + 1) / 2;
// Threshold for rounding up (half the denominatorominator, rounded up)
utype half_denominator = (abs_denominator + 1) / 2;
if (abs_rem >= half_den)
if (abs_remainder >= half_denominator)
{
// Round away from zero
if (private_rounded_integral_division::are_same_sign(num, den))
if (private_rounded_integral_division::are_same_sign(numerator, denominator))
{
++quotient; // same sign ? increment
}
@ -395,6 +448,10 @@ namespace etl
///\brief Integral division with rounding to half up.
/// For signed integral types.
/// For different argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half up.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
@ -403,31 +460,34 @@ namespace etl
etl::is_signed<T1>::value &&
etl::is_signed<T2>::value,
typename etl::common_type<T1, T2>::type>::type
divide_round_half_up(T1 num, T2 den) ETL_NOEXCEPT
divide_round_half_up(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
return divide_round_half_up(static_cast<type>(num), static_cast<type>(den));
return divide_round_half_up(static_cast<type>(numerator), static_cast<type>(denominator));
}
//***************************************************************************
///\brief Integral division with rounding to half up.
/// For unsigned integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half up.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_unsigned<T>::value,
T>::type
divide_round_half_up(T num, T den) ETL_NOEXCEPT
divide_round_half_up(T numerator, T denominator) ETL_NOEXCEPT
{
const T remainder = num % den;
const T remainder = numerator % denominator;
T quotient = num / den;
T quotient = numerator / denominator;
// If remainder is at least half the divisor, round up
if (remainder >= (den / 2U) + (den % 2U))
if (remainder >= (denominator / 2U) + (denominator % 2U))
{
++quotient;
}
@ -439,6 +499,10 @@ namespace etl
///\brief Integral division with rounding to half up.
/// For unsigned integral types.
/// For different argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half up.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
@ -446,41 +510,48 @@ namespace etl
etl::is_integral<T2>::value &&
etl::is_unsigned<T1>::value &&
etl::is_unsigned<T2>::value, typename etl::common_type<T1, T2>::type>::type
divide_round_half_up(T1 num, T2 den) ETL_NOEXCEPT
divide_round_half_up(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
return divide_round_half_up(static_cast<type>(num), static_cast<type>(den));
return divide_round_half_up(static_cast<type>(numerator), static_cast<type>(denominator));
}
//***************************************************************************
///\brief Integral division with rounding to half down.
/// For signed integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half down.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_signed<T>::value,
T>::type
divide_round_half_down(T num, T den) ETL_NOEXCEPT
divide_round_half_down(T numerator, T denominator) ETL_NOEXCEPT
{
const T quotient = num / den;
const T remainder = num % den;
const T abs_den = etl::absolute(den);
const T abs_remainder = etl::absolute(remainder);
const T quotient = numerator / denominator;
const T remainder = numerator % denominator;
const T abs_denominator = etl::absolute(denominator);
const T abs_remainderainder = etl::absolute(remainder);
// Direction: +1 if result should be more positive, -1 if more negative
const T direction = ((num >= 0) == (den >= 0)) ? 1 : -1;
const T direction = ((numerator >= 0) == (denominator >= 0)) ? 1 : -1;
// Only round away from zero if remainder is strictly greater than half the divisor
return abs_remainder > (abs_den / 2) ? quotient + direction : quotient;
return abs_remainderainder > (abs_denominator / 2) ? quotient + direction : quotient;
}
//***************************************************************************
///\brief Integral division with rounding to half down.
/// For signed integral types.
/// For different argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half down.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
@ -489,31 +560,34 @@ namespace etl
etl::is_signed<T1>::value &&
etl::is_signed<T2>::value,
typename etl::common_type<T1, T2>::type>::type
divide_round_half_down(T1 num, T2 den) ETL_NOEXCEPT
divide_round_half_down(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
return divide_round_half_down(static_cast<type>(num), static_cast<type>(den));
return divide_round_half_down(static_cast<type>(numerator), static_cast<type>(denominator));
}
//***************************************************************************
///\brief Integral division with rounding to half down.
/// For unsigned integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half down.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_unsigned<T>::value,
T>::type
divide_round_half_down(T num, T den) ETL_NOEXCEPT
divide_round_half_down(T numerator, T denominator) ETL_NOEXCEPT
{
const T remainder = num % den;
const T remainder = numerator % denominator;
T quotient = num / den;
T quotient = numerator / denominator;
// If remainder is at least half the divisor, round down
if (remainder > (den / 2U))
if (remainder > (denominator / 2U))
{
++quotient;
}
@ -525,6 +599,10 @@ namespace etl
///\brief Integral division with rounding to half down.
/// For unsigned integral types.
/// For different argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half down.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
@ -532,36 +610,39 @@ namespace etl
etl::is_integral<T2>::value &&
etl::is_unsigned<T1>::value &&
etl::is_unsigned<T2>::value, typename etl::common_type<T1, T2>::type>::type
divide_round_half_down(T1 num, T2 den) ETL_NOEXCEPT
divide_round_half_down(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
return divide_round_half_down(static_cast<type>(num), static_cast<type>(den));
return divide_round_half_down(static_cast<type>(numerator), static_cast<type>(denominator));
}
//***************************************************************************
///\brief Integral division with rounding to half even.
/// For signed integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half even.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_signed<T>::value,
T>::type
divide_round_half_even(T num, T den) ETL_NOEXCEPT
divide_round_half_even(T numerator, T denominator) ETL_NOEXCEPT
{
const T quotient = num / den;
const T remainder = num % den;
const T abs_den = etl::absolute(den);
const T abs_remainder = etl::absolute(remainder);
const T direction = ((num >= 0) == (den >= 0)) ? 1 : -1;
const T quotient = numerator / denominator;
const T remainder = numerator % denominator;
const T abs_denominator = etl::absolute(denominator);
const T abs_remainderainder = etl::absolute(remainder);
const T direction = ((numerator >= 0) == (denominator >= 0)) ? 1 : -1;
if ((abs_remainder * 2) < abs_den)
if ((abs_remainderainder * 2) < abs_denominator)
{
return quotient;
}
else if ((abs_remainder * 2) > abs_den)
else if ((abs_remainderainder * 2) > abs_denominator)
{
return quotient + direction;
}
@ -576,6 +657,10 @@ namespace etl
///\brief Integral division with rounding to half even.
/// For signed integral types.
/// For different argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half even.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
@ -584,34 +669,37 @@ namespace etl
etl::is_signed<T1>::value &&
etl::is_signed<T2>::value,
typename etl::common_type<T1, T2>::type>::type
divide_round_half_even(T1 num, T2 den) ETL_NOEXCEPT
divide_round_half_even(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
return divide_round_half_even(static_cast<type>(num), static_cast<type>(den));
return divide_round_half_even(static_cast<type>(numerator), static_cast<type>(denominator));
}
//***************************************************************************
///\brief Integral division with rounding to half even.
/// For unsigned integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half even.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_unsigned<T>::value,
T>::type
divide_round_half_even(T num, T den) ETL_NOEXCEPT
divide_round_half_even(T numerator, T denominator) ETL_NOEXCEPT
{
const T quotient = num / den;
const T remainder = num % den;
const T quotient = numerator / denominator;
const T remainder = numerator % denominator;
if ((remainder * 2U) < den)
if ((remainder * 2U) < denominator)
{
// Less than halfway, round down
return quotient;
}
else if ((remainder * 2U) > den)
else if ((remainder * 2U) > denominator)
{
// More than halfway, round up
return quotient + 1U;
@ -627,6 +715,10 @@ namespace etl
///\brief Integral division with rounding to half even.
/// For unsigned integral types.
/// For different argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half even.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
@ -635,36 +727,39 @@ namespace etl
etl::is_unsigned<T1>::value &&
etl::is_unsigned<T2>::value,
typename etl::common_type<T1, T2>::type>::type
divide_round_half_even(T1 num, T2 den) ETL_NOEXCEPT
divide_round_half_even(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
return divide_round_half_even(static_cast<type>(num), static_cast<type>(den));
return divide_round_half_even(static_cast<type>(numerator), static_cast<type>(denominator));
}
//***************************************************************************
///\brief Integral division with rounding to half odd.
/// For signed integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half odd.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_signed<T>::value,
T>::type
divide_round_half_odd(T num, T den) ETL_NOEXCEPT
divide_round_half_odd(T numerator, T denominator) ETL_NOEXCEPT
{
const T quotient = num / den;
const T remainder = num % den;
const T abs_den = etl::absolute(den);
const T abs_remainder = etl::absolute(remainder);
const T direction = ((num >= 0) == (den >= 0)) ? 1 : -1;
const T quotient = numerator / denominator;
const T remainder = numerator % denominator;
const T abs_denominator = etl::absolute(denominator);
const T abs_remainderainder = etl::absolute(remainder);
const T direction = ((numerator >= 0) == (denominator >= 0)) ? 1 : -1;
if ((abs_remainder * 2) < abs_den)
if ((abs_remainderainder * 2) < abs_denominator)
{
return quotient;
}
else if ((abs_remainder * 2) > abs_den)
else if ((abs_remainderainder * 2) > abs_denominator)
{
return quotient + direction;
}
@ -679,6 +774,10 @@ namespace etl
///\brief Integral division with rounding to half odd.
/// For signed integral types.
/// For different parameter types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half odd.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
@ -687,34 +786,37 @@ namespace etl
etl::is_signed<T1>::value &&
etl::is_signed<T2>::value,
typename etl::common_type<T1, T2>::type>::type
divide_round_half_odd(T1 num, T2 den) ETL_NOEXCEPT
divide_round_half_odd(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
return divide_round_half_odd(static_cast<type>(num), static_cast<type>(den));
return divide_round_half_odd(static_cast<type>(numerator), static_cast<type>(denominator));
}
//***************************************************************************
///\brief Integral division with rounding to half odd.
/// For unsigned integral types.
/// For identical argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half odd.
//***************************************************************************
template <typename T>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T>::value &&
etl::is_unsigned<T>::value,
T>::type
divide_round_half_odd(T num, T den) ETL_NOEXCEPT
divide_round_half_odd(T numerator, T denominator) ETL_NOEXCEPT
{
const T quotient = num / den;
const T remainder = num % den;
const T direction = ((num >= 0U) == (den >= 0U)) ? 1 : -1;
const T quotient = numerator / denominator;
const T remainder = numerator % denominator;
const T direction = ((numerator >= 0U) == (denominator >= 0U)) ? 1 : -1;
if ((remainder * 2U) < den)
if ((remainder * 2U) < denominator)
{
return quotient;
}
else if ((remainder * 2U) > den)
else if ((remainder * 2U) > denominator)
{
return quotient + direction;
}
@ -729,6 +831,10 @@ namespace etl
///\brief Integral division with rounding to half odd.
/// For unsigned integral types.
/// For different argument types.
///\param numerator The numerator.
///\param denominator The denominator.
///\return The result of the division rounded to half odd.
/// Return type is the etl::common_type<T1, T2>::type.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
@ -737,11 +843,11 @@ namespace etl
etl::is_unsigned<T1>::value &&
etl::is_unsigned<T2>::value,
typename etl::common_type<T1, T2>::type>::type
divide_round_half_odd(T1 num, T2 den) ETL_NOEXCEPT
divide_round_half_odd(T1 numerator, T2 denominator) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
return divide_round_half_odd(static_cast<type>(num), static_cast<type>(den));
return divide_round_half_odd(static_cast<type>(numerator), static_cast<type>(denominator));
}
}

View File

@ -12,6 +12,7 @@ Made invocation of delegate consrexpr for C++14
#1132 Request: Make type_def Methods Noexcept
#1054 Using #pragma once
#1159 etl::fsm helper to check states id sequence at compile time
#1160 Feature request: rounded division (similar to scaled rounding)
Fixes:
Fix gamma tests (removed integral tests)

View File

@ -267,6 +267,7 @@ add_executable(etl_tests
test_rescale.cpp
test_result.cpp
test_rms.cpp
test_rounded_integral_division.cpp
test_scaled_rounding.cpp
test_set.cpp
test_shared_message.cpp

View File

@ -3698,6 +3698,9 @@
<ClCompile Include="..\test_delegate_observable.cpp">
<Filter>Tests\Callbacks &amp; Delegates</Filter>
</ClCompile>
<ClCompile Include="..\test_rounded_integral_division.cpp">
<Filter>Tests\Maths</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\library.properties">