Added complete set of rounded integral division

This commit is contained in:
John Wellbelove 2025-08-07 18:45:46 +01:00
parent 2de4057021
commit ff1e4296bc
4 changed files with 862 additions and 3 deletions

View File

@ -0,0 +1,495 @@
///\file
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2025 John Wellbelove
Permission is hereby granted, free of charge, to any person obtaining num 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
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef ETL_ROUNDED_INTEGRAL_DIVISION_INCLUDED
#define ETL_ROUNDED_INTEGRAL_DIVISION_INCLUDED
#include "type_traits.h"
#include "absolute.h"
namespace etl
{
//***************************************************************************
///\brief Integral division with rounding to ceiling.
/// For signed integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
etl::is_integral<T2>::value &&
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
{
typedef typename etl::common_type<T1, T2>::type type;
const type common_num = num;
const type common_den = den;
const type remainder = common_num % common_den;
type quotient = common_num / common_den;
// If remainder is zero, already exact
if (remainder == 0)
{
return quotient;
}
// If signs are the same, increment quotient
return ((common_num ^ common_den) >= 0) ? quotient + 1 : quotient;
}
//***************************************************************************
///\brief Integral division with rounding to ceiling.
/// For unsigned integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
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_to_ceiling(T1 num, T2 den) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
const type common_num = num;
const type common_den = den;
const type remainder = common_num % common_den;
type quotient = common_num / common_den;
// If remainder is zero, already exact, otherwise, increment quotient
return remainder == 0U ? quotient : quotient + 1U;
}
//***************************************************************************
///\brief Integral division with rounding to floor.
/// For signed integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
etl::is_integral<T2>::value &&
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
{
typedef typename etl::common_type<T1, T2>::type type;
const type common_num = num;
const type common_den = den;
const type remainder = common_num % common_den;
type quotient = common_num / common_den;
// If remainder is zero, already exact
if (remainder == 0)
{
return quotient;
}
// If signs are different, decrement quotient
return ((common_num ^ common_den) >= 0) ? quotient : quotient - 1;
}
//***************************************************************************
///\brief Integral division with rounding to floor.
/// For unsigned integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
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_to_floor(T1 num, T2 den) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
const type common_num = num;
const type common_den = den;
return common_num / common_den;
}
//***************************************************************************
///\brief Integral division with rounding towards infinity.
/// For signed integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
etl::is_integral<T2>::value &&
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
{
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 remainder = common_num % common_den;
type quotient = common_num / common_den;
if ((common_num ^ common_den) >= 0)
{
// Same sign, round towards +infinity
quotient = remainder ? quotient + 1 : quotient;
}
else
{
// Different signs, round towards -infinity
quotient = remainder ? quotient - 1 : quotient;
}
return quotient;
}
//***************************************************************************
///\brief Integral division with rounding towards infinity.
/// For unsigned integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
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_to_infinity(T1 num, T2 den) 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 remainder = common_num % common_den;
type quotient = common_num / common_den;
return remainder ? quotient + 1U : quotient;
}
//***************************************************************************
///\brief Integral division with rounding towards zero.
/// For integral types.
//***************************************************************************
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
{
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;
return common_num / common_den;
}
//***************************************************************************
///\brief Integral division with rounding to half up.
/// For signed integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
etl::is_integral<T2>::value &&
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
{
typedef typename etl::common_type<T1, T2>::type type;
const type common_num = num;
const type common_den = den;
const type quotient = common_num / common_den;
const type remainder = common_num % common_den;
const type abs_den = etl::absolute(common_den);
const type abs_remainder = etl::absolute(remainder);
// Direction: +1 if result should be more positive, -1 if more negative
const type direction = ((common_num >= 0) == (common_den >= 0)) ? 1 : -1;
// If remainder is at least half the divisor, round away from zero
return abs_remainder >= (abs_den + 1) / 2 ? quotient + direction : quotient;
}
//***************************************************************************
///\brief Integral division with rounding to half up.
/// For unsigned integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
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
{
typedef typename etl::common_type<T1, T2>::type type;
const type common_num = num;
const type common_den = den;
const type remainder = common_num % common_den;
type quotient = common_num / common_den;
// If remainder is at least half the divisor, round up
if (remainder >= (den + 1U) / 2U)
{
++quotient;
}
return quotient;
}
//***************************************************************************
///\brief Integral division with rounding to half down.
/// For signed integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
etl::is_integral<T2>::value &&
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
{
typedef typename etl::common_type<T1, T2>::type type;
const type common_num = num;
const type common_den = den;
const type quotient = common_num / common_den;
const type remainder = common_num % common_den;
const type abs_den = etl::absolute(common_den);
const type abs_remainder = etl::absolute(remainder);
// Direction: +1 if result should be more positive, -1 if more negative
const type direction = ((common_num >= 0) == (common_den >= 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;
}
//***************************************************************************
///\brief Integral division with rounding to half down.
/// For unsigned integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
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
{
typedef typename etl::common_type<T1, T2>::type type;
const type common_num = num;
const type common_den = den;
const type remainder = common_num % common_den;
type quotient = common_num / common_den;
// If remainder is at least half the divisor, round down
if (remainder > (den / 2U))
{
++quotient;
}
return quotient;
}
//***************************************************************************
///\brief Integral division with rounding to half even.
/// For signed integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
etl::is_integral<T2>::value &&
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
{
typedef typename etl::common_type<T1, T2>::type type;
const type common_num = num;
const type common_den = den;
const type quotient = common_num / common_den;
const type remainder = common_num % common_den;
const type abs_den = etl::absolute(common_den);
const type abs_remainder = etl::absolute(remainder);
const type direction = ((common_num >= 0) == (common_den >= 0)) ? 1 : -1;
if ((abs_remainder * 2) < abs_den)
{
return quotient;
}
else if ((abs_remainder * 2) > abs_den)
{
return quotient + direction;
}
else
{
// Exactly halfway, round to even
return (quotient & 1) == 0 ? quotient : quotient + direction;
}
}
//***************************************************************************
///\brief Integral division with rounding to half even.
/// For unsigned integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
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_even(T1 num, T2 den) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
const type common_num = num;
const type common_den = den;
const type quotient = common_num / common_den;
const type remainder = common_num % common_den;
if ((remainder * 2U) < den)
{
// Less than halfway, round down
return quotient;
}
else if ((remainder * 2U) > den)
{
// More than halfway, round up
return quotient + 1U;
}
else
{
// Exactly halfway, round to even
return (quotient & 1U) == 0U ? quotient : quotient + 1;
}
}
//***************************************************************************
///\brief Integral division with rounding to half odd.
/// For signed integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
etl::is_integral<T2>::value &&
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
{
typedef typename etl::common_type<T1, T2>::type type;
const type common_num = num;
const type common_den = den;
const type quotient = common_num / common_den;
const type remainder = common_num % common_den;
const type common_den = etl::absolute(common_den);
const type abs_remainder = etl::absolute(remainder);
const type direction = ((common_num >= 0) == (common_den >= 0)) ? 1 : -1;
if ((abs_remainder * 2) < common_den)
{
return quotient;
}
else if ((abs_remainder * 2) > common_den)
{
return quotient + direction;
}
else
{
// Exactly halfway, round to odd
return (quotient & 1) == 1 ? quotient : quotient + direction;
}
}
//***************************************************************************
///\brief Integral division with rounding to half odd.
/// For unsigned integral types.
//***************************************************************************
template <typename T1, typename T2>
ETL_CONSTEXPR14
typename etl::enable_if<etl::is_integral<T1>::value &&
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_odd(T1 num, T2 den) ETL_NOEXCEPT
{
typedef typename etl::common_type<T1, T2>::type type;
const type common_num = num;
const type common_den = den;
const type quotient = common_num / common_den;
const type remainder = common_num % common_den;
if ((remainder * 2U) < den)
{
// Less than halfway, round down
return quotient;
}
else if ((remainder * 2U) > den)
{
// More than halfway, round up
return quotient + 1U;
}
else
{
// Exactly halfway, round to odd
return (quotient & 1U) == 1U ? quotient : quotient + 1U;
}
}
}
#endif

View File

@ -0,0 +1,357 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2025 John Wellbelove
Permission is hereby granted, free of charge, to any person obtaining a 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
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "unit_test_framework.h"
#include "etl/rounded_integral_division.h"
#include <stdint.h>
#include <array>
namespace
{
SUITE(test_constant)
{
//*************************************************************************
TEST(test_round_to_ceiling_signed)
{
const std::array<int16_t, 42> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400,
0, -49, -50, -51, -99, -100, -149, -150, -151, -199, -200, -249, -259, -251, -299, -300, -349, -350, -351, -399, -400 };
const std::array<int32_t, 2> denominator{ 100, -100 };
const std::array<int32_t, 84> expected{ 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4,
0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4,
0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4 };
std::array<int32_t, 84> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
size_t index = j + (i * numerator.size());
actual[index] = etl::divide_round_to_ceiling(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
//*************************************************************************
TEST(test_round_to_ceiling_unsigned)
{
const std::array<uint16_t, 21> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400 };
const std::array<uint32_t, 1> denominator{ 100 };
const std::array<uint32_t, 21> expected{ 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4 };
std::array<uint32_t, 21> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
actual[j + (i * numerator.size())] = etl::divide_round_to_ceiling(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
//*************************************************************************
TEST(test_round_to_floor_signed)
{
const std::array<int16_t, 42> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400,
0, -49, -50, -51, -99, -100, -149, -150, -151, -199, -200, -249, -259, -251, -299, -300, -349, -350, -351, -399, -400 };
const std::array<int32_t, 2> denominator{ 100, -100 };
const std::array<int32_t, 84> expected{ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4,
0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4,
0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4,
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4 };
std::array<int32_t, 84> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
size_t index = j + (i * numerator.size());
actual[index] = etl::divide_round_to_floor(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
//*************************************************************************
TEST(test_round_to_floor_unsigned)
{
const std::array<uint16_t, 21> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400 };
const std::array<uint32_t, 1> denominator{ 100 };
const std::array<uint32_t, 21> expected{ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4 };
std::array<uint32_t, 21> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
actual[j + (i * numerator.size())] = etl::divide_round_to_floor(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
//*************************************************************************
TEST(test_round_to_zero_signed)
{
const std::array<int16_t, 42> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400,
0, -49, -50, -51, -99, -100, -149, -150, -151, -199, -200, -249, -259, -251, -299, -300, -349, -350, -351, -399, -400 };
const std::array<int32_t, 2> denominator{ 100, -100 };
const std::array<int32_t, 84> expected{ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4,
0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4,
0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4,
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4 };
std::array<int32_t, 84> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
size_t index = j + (i * numerator.size());
actual[index] = etl::divide_round_to_zero(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
//*************************************************************************
TEST(test_round_to_zero_unsigned)
{
const std::array<uint16_t, 21> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400 };
const std::array<uint32_t, 1> denominator{ 100 };
const std::array<uint32_t, 21> expected{ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4 };
std::array<uint32_t, 21> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
actual[j + (i * numerator.size())] = etl::divide_round_to_zero(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
//*************************************************************************
TEST(test_round_to_infinity_signed)
{
const std::array<int16_t, 42> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400,
0, -49, -50, -51, -99, -100, -149, -150, -151, -199, -200, -249, -259, -251, -299, -300, -349, -350, -351, -399, -400 };
const std::array<int32_t, 2> denominator{ 100, -100 };
const std::array<int32_t, 84> expected{ 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4,
0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4,
0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4 };
std::array<int32_t, 84> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
size_t index = j + (i * numerator.size());
actual[index] = etl::divide_round_to_infinity(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
//*************************************************************************
TEST(test_round_to_infinity_unsigned)
{
const std::array<uint16_t, 21> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400 };
const std::array<uint32_t, 1> denominator{ 100 };
const std::array<uint32_t, 21> expected{ 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4 };
std::array<uint32_t, 21> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
size_t index = j + (i * numerator.size());
actual[index] = etl::divide_round_to_infinity(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
//*************************************************************************
TEST(test_round_to_half_up_signed)
{
const std::array<int16_t, 42> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400,
0, -49, -50, -51, -99, -100, -149, -150, -151, -199, -200, -249, -259, -251, -299, -300, -349, -350, -351, -399, -400 };
const std::array<int32_t, 2> denominator{ 100, -100 };
const std::array<int32_t, 84> expected{ 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4,
0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4,
0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4,
0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4 };
std::array<int32_t, 84> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
size_t index = j + (i * numerator.size());
actual[index] = etl::divide_round_half_up(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
//*************************************************************************
TEST(test_round_to_half_up_unsigned)
{
const std::array<uint16_t, 21> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400 };
const std::array<uint32_t, 1> denominator{ 100 };
const std::array<uint32_t, 21> expected{ 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4 };
std::array<uint32_t, 21> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
size_t index = j + (i * numerator.size());
actual[index] = etl::divide_round_half_up(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
//*************************************************************************
TEST(test_round_to_half_down_signed)
{
const std::array<int16_t, 42> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400,
0, -49, -50, -51, -99, -100, -149, -150, -151, -199, -200, -249, -250, -251, -299, -300, -349, -350, -351, -399, -400 };
const std::array<int32_t, 2> denominator{ 100, -100 };
const std::array<int32_t, 84> expected{ 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4,
0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4,
0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4,
0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4 };
std::array<int32_t, 84> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
size_t index = j + (i * numerator.size());
actual[index] = etl::divide_round_half_down(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
//*************************************************************************
TEST(test_round_to_half_down_unsigned)
{
const std::array<uint16_t, 21> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400 };
const std::array<uint32_t, 1> denominator{ 100 };
const std::array<uint32_t, 21> expected{ 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4 };
std::array<uint32_t, 42> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
size_t index = j + (i * numerator.size());
actual[index] = etl::divide_round_half_down(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
//*************************************************************************
TEST(test_round_to_half_even_signed)
{
const std::array<int16_t, 42> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400,
0, -49, -50, -51, -99, -100, -149, -150, -151, -199, -200, -249, -250, -251, -299, -300, -349, -350, -351, -399, -400 };
const std::array<int32_t, 2> denominator{ 100, -100 };
const std::array<int32_t, 84> expected{ 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
0, 0, 0, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -3, -3, -3, -3, -4, -4, -4, -4,
0, 0, 0, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -3, -3, -3, -3, -4, -4, -4, -4,
0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 };
std::array<int32_t, 84> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
size_t index = j + (i * numerator.size());
actual[index] = etl::divide_round_half_even(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
//*************************************************************************
TEST(test_round_to_half_even_unsigned)
{
const std::array<uint16_t, 21> numerator{ 0, 49, 50, 51, 99, 100, 149, 150, 151, 199, 200, 249, 250, 251, 299, 300, 349, 350, 351, 399, 400 };
const std::array<uint32_t, 1> denominator{ 100 };
const std::array<uint32_t, 21> expected{ 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 };
std::array<uint32_t, 42> actual{};
for (size_t i = 0; i < denominator.size(); ++i)
{
for (size_t j = 0; j < numerator.size(); ++j)
{
size_t index = j + (i * numerator.size());
actual[index] = etl::divide_round_half_even(numerator[j], denominator[i]);
}
}
CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size());
}
};
}

View File

@ -3481,6 +3481,7 @@
<ClInclude Include="..\..\include\etl\rescale.h" />
<ClInclude Include="..\..\include\etl\result.h" />
<ClInclude Include="..\..\include\etl\rms.h" />
<ClInclude Include="..\..\include\etl\rounded_integral_division.h" />
<ClInclude Include="..\..\include\etl\scaled_rounding.h" />
<ClInclude Include="..\..\include\etl\shared_message.h" />
<ClInclude Include="..\..\include\etl\singleton.h" />
@ -10331,6 +10332,7 @@
<ClCompile Include="..\test_rescale.cpp" />
<ClCompile Include="..\test_result.cpp" />
<ClCompile Include="..\test_rms.cpp" />
<ClCompile Include="..\test_rounded_integral_division.cpp" />
<ClCompile Include="..\test_shared_message.cpp" />
<ClCompile Include="..\test_priority_queue.cpp" />
<ClCompile Include="..\test_queue.cpp" />

View File

@ -1533,6 +1533,9 @@
<ClInclude Include="..\..\include\etl\delegate_observable.h">
<Filter>ETL\Utilities</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\rounded_integral_division.h">
<Filter>ETL\Maths</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\test_string_char.cpp">
@ -3854,10 +3857,10 @@
<Filter>Resource Files</Filter>
</None>
<None Include="..\..\scripts\convert_headers_to_use_guards.bat">
<Filter>Tests</Filter>
<Filter>Tests\Scripts</Filter>
</None>
<None Include="..\..\scripts\convert_headers_to_use_once.bat">
<Filter>Tests</Filter>
<Filter>Tests\Scripts</Filter>
</None>
</ItemGroup>
<ItemGroup>
@ -3897,7 +3900,9 @@
<Text Include="..\syntax_check\CMakeLists.txt">
<Filter>Tests\Syntax Checks</Filter>
</Text>
<Text Include="..\..\Converting header guards.txt" />
<Text Include="..\..\Converting header guards.txt">
<Filter>Resource Files</Filter>
</Text>
</ItemGroup>
<ItemGroup>
<Image Include="..\..\etl.ico">