diff --git a/include/etl/rounded_integral_division.h b/include/etl/rounded_integral_division.h index 748dc386..5b02a2be 100644 --- a/include/etl/rounded_integral_division.h +++ b/include/etl/rounded_integral_division.h @@ -656,22 +656,22 @@ namespace etl { const T quotient = num / den; const T remainder = num % den; - const T common_den = etl::absolute(common_den); + const T abs_den = etl::absolute(den); const T abs_remainder = etl::absolute(remainder); - const T direction = ((num >= 0) == (common_den >= 0)) ? 1 : -1; + const T direction = ((num >= 0) == (den >= 0)) ? 1 : -1; - if ((abs_remainder * 2) < common_den) + if ((abs_remainder * 2) < abs_den) { return quotient; } - else if ((abs_remainder * 2) > common_den) + else if ((abs_remainder * 2) > abs_den) { return quotient + direction; } else { // Exactly halfway, round to odd - return (quotient & 1) == 1 ? quotient : quotient + direction; + return (quotient & 1) != 0 ? quotient : quotient + direction; } } @@ -706,23 +706,22 @@ namespace etl T>::type divide_round_half_odd(T num, T den) ETL_NOEXCEPT { - const T quotient = num / den; - const T remainder = num % den; + const T quotient = num / den; + const T remainder = num % den; + const T direction = ((num >= 0U) == (den >= 0U)) ? 1 : -1; if ((remainder * 2U) < den) { - // Less than halfway, round down return quotient; } else if ((remainder * 2U) > den) { - // More than halfway, round up - return quotient + 1U; + return quotient + direction; } else { // Exactly halfway, round to odd - return (quotient & 1U) == 1U ? quotient : quotient + 1U; + return (quotient & 1U) != 0U ? quotient : quotient + direction; } } diff --git a/test/test_rounded_integral_division.cpp b/test/test_rounded_integral_division.cpp index e17d23a9..dc91390b 100644 --- a/test/test_rounded_integral_division.cpp +++ b/test/test_rounded_integral_division.cpp @@ -194,6 +194,15 @@ namespace CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); } + //************************************************************************* + TEST(test_round_to_floor_signed_limits) + { + CHECK_EQUAL(std::numeric_limits::max(), etl::divide_round_to_floor(std::numeric_limits::max(), int32_t(1))); + CHECK_EQUAL(int32_t(0), etl::divide_round_to_floor(int32_t(1), std::numeric_limits::max())); + CHECK_EQUAL(std::numeric_limits::min(), etl::divide_round_to_floor(std::numeric_limits::min(), int32_t(1))); + CHECK_EQUAL(int32_t(-1), etl::divide_round_to_floor(int32_t(1), std::numeric_limits::min())); + } + //************************************************************************* TEST(test_round_to_floor_unsigned_different_types) { @@ -232,6 +241,13 @@ namespace CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); } + //************************************************************************* + TEST(test_round_to_floor_unsigned_limits) + { + CHECK_EQUAL(std::numeric_limits::max(), etl::divide_round_to_floor(std::numeric_limits::max(), uint32_t(1))); + CHECK_EQUAL(uint32_t(0), etl::divide_round_to_floor(uint32_t(1), std::numeric_limits::max())); + } + //************************************************************************* TEST(test_round_to_zero_signed_different_types) { @@ -282,6 +298,15 @@ namespace CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); } + //************************************************************************* + TEST(test_round_to_zero_signed_limits) + { + CHECK_EQUAL(std::numeric_limits::max(), etl::divide_round_to_zero(std::numeric_limits::max(), int32_t(1))); + CHECK_EQUAL(int32_t(0), etl::divide_round_to_zero(int32_t(1), std::numeric_limits::max())); + CHECK_EQUAL(std::numeric_limits::min(), etl::divide_round_to_zero(std::numeric_limits::min(), int32_t(1))); + CHECK_EQUAL(int32_t(0), etl::divide_round_to_zero(int32_t(1), std::numeric_limits::min())); + } + //************************************************************************* TEST(test_round_to_zero_unsigned_different_types) { @@ -320,6 +345,13 @@ namespace CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); } + //************************************************************************* + TEST(test_round_to_zero_unsigned_limits) + { + CHECK_EQUAL(std::numeric_limits::max(), etl::divide_round_to_zero(std::numeric_limits::max(), uint32_t(1))); + CHECK_EQUAL(uint32_t(0), etl::divide_round_to_zero(uint32_t(1), std::numeric_limits::max())); + } + //************************************************************************* TEST(test_round_to_infinity_signed_different_types) { @@ -370,6 +402,15 @@ namespace CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); } + //************************************************************************* + TEST(test_round_to_infinity_signed_limits) + { + CHECK_EQUAL(std::numeric_limits::max(), etl::divide_round_to_infinity(std::numeric_limits::max(), int32_t(1))); + CHECK_EQUAL(int32_t(1), etl::divide_round_to_infinity(int32_t(1), std::numeric_limits::max())); + CHECK_EQUAL(std::numeric_limits::min(), etl::divide_round_to_infinity(std::numeric_limits::min(), int32_t(1))); + CHECK_EQUAL(int32_t(-1), etl::divide_round_to_infinity(int32_t(1), std::numeric_limits::min())); + } + //************************************************************************* TEST(test_round_to_infinity_unsigned_different_types) { @@ -412,6 +453,13 @@ namespace CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); } + //************************************************************************* + TEST(test_round_to_infinity_unsigned_limits) + { + CHECK_EQUAL(std::numeric_limits::max(), etl::divide_round_to_infinity(std::numeric_limits::max(), uint32_t(1))); + CHECK_EQUAL(uint32_t(1), etl::divide_round_to_infinity(uint32_t(1), std::numeric_limits::max())); + } + //************************************************************************* TEST(test_round_to_half_up_signed_different_types) { @@ -517,7 +565,7 @@ namespace TEST(test_round_to_half_up_unsigned_limits) { CHECK_EQUAL(std::numeric_limits::max(), etl::divide_round_half_up(std::numeric_limits::max(), uint32_t(1))); - CHECK_EQUAL(uint32_t(0U), etl::divide_round_half_up(uint32_t(1), std::numeric_limits::max())); + CHECK_EQUAL(uint32_t(0U), etl::divide_round_half_up(uint32_t(1), std::numeric_limits::max())); } //************************************************************************* @@ -570,6 +618,15 @@ namespace CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); } + //************************************************************************* + TEST(test_round_to_half_down_signed_limits) + { + CHECK_EQUAL(std::numeric_limits::max(), etl::divide_round_half_down(std::numeric_limits::max(), int32_t(1))); + CHECK_EQUAL(int32_t(0), etl::divide_round_half_down(int32_t(1), std::numeric_limits::max())); + CHECK_EQUAL(std::numeric_limits::min(), etl::divide_round_half_down(std::numeric_limits::min(), int32_t(1))); + CHECK_EQUAL(int32_t(-1), etl::divide_round_half_down(int32_t(1), std::numeric_limits::min())); + } + //************************************************************************* TEST(test_round_to_half_down_unsigned_different_types) { @@ -612,6 +669,13 @@ namespace CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); } + //************************************************************************* + TEST(test_round_to_half_down_unsigned_limits) + { + CHECK_EQUAL(std::numeric_limits::max(), etl::divide_round_half_down(std::numeric_limits::max(), uint32_t(1))); + CHECK_EQUAL(uint32_t(0U), etl::divide_round_half_down(uint32_t(1), std::numeric_limits::max())); + } + //************************************************************************* TEST(test_round_to_half_even_signed_different_types) { @@ -662,6 +726,15 @@ namespace CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); } + //************************************************************************* + TEST(test_round_to_half_even_signed_limits) + { + CHECK_EQUAL(std::numeric_limits::max(), etl::divide_round_half_even(std::numeric_limits::max(), int32_t(1))); + CHECK_EQUAL(int32_t(0), etl::divide_round_half_even(int32_t(1), std::numeric_limits::max())); + CHECK_EQUAL(std::numeric_limits::min(), etl::divide_round_half_even(std::numeric_limits::min(), int32_t(1))); + CHECK_EQUAL(int32_t(-1), etl::divide_round_half_even(int32_t(1), std::numeric_limits::min())); + } + //************************************************************************* TEST(test_round_to_half_even_unsigned_different_types) { @@ -703,5 +776,120 @@ namespace CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); } + + //************************************************************************* + TEST(test_round_to_half_even_unsigned_limits) + { + CHECK_EQUAL(std::numeric_limits::max(), etl::divide_round_half_even(std::numeric_limits::max(), uint32_t(1))); + CHECK_EQUAL(uint32_t(0U), etl::divide_round_half_even(uint32_t(1), std::numeric_limits::max())); + } + + //************************************************************************* + TEST(test_round_to_half_odd_signed_different_types) + { + const std::array 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 denominator{ 100, -100 }; + const std::array expected{ 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, + 0, 0, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -4, -4, -4, + 0, 0, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -4, -4, -4, + 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4 }; + std::array 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_odd(numerator[j], denominator[i]); + } + } + + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); + } + + //************************************************************************* + TEST(test_round_to_half_odd_signed_same_types) + { + const std::array 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 denominator{ 100, -100 }; + const std::array expected{ 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, + 0, 0, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -4, -4, -4, + 0, 0, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -3, -3, -3, -3, -3, -3, -4, -4, -4, + 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4 }; + std::array 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_odd(numerator[j], denominator[i]); + } + } + + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); + } + + //************************************************************************* + TEST(test_round_to_half_odd_signed_limits) + { + CHECK_EQUAL(std::numeric_limits::max(), etl::divide_round_half_odd(std::numeric_limits::max(), int32_t(1))); + CHECK_EQUAL(int32_t(0), etl::divide_round_half_odd(int32_t(1), std::numeric_limits::max())); + CHECK_EQUAL(std::numeric_limits::min(), etl::divide_round_half_odd(std::numeric_limits::min(), int32_t(1))); + CHECK_EQUAL(int32_t(-1), etl::divide_round_half_odd(int32_t(1), std::numeric_limits::min())); + } + + //************************************************************************* + TEST(test_round_to_half_odd_unsigned_different_types) + { + const std::array 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 denominator{ 100 }; + const std::array expected{ 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4 }; + std::array 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_odd(numerator[j], denominator[i]); + } + } + + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); + } + + //************************************************************************* + TEST(test_round_to_half_odd_unsigned_same_types) + { + const std::array 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 denominator{ 100 }; + const std::array expected{ 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4 }; + std::array 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_odd(numerator[j], denominator[i]); + } + } + + CHECK_ARRAY_EQUAL(expected.data(), actual.data(), expected.size()); + } + + //************************************************************************* + TEST(test_round_to_half_odd_unsigned_limits) + { + CHECK_EQUAL(std::numeric_limits::max(), etl::divide_round_half_odd(std::numeric_limits::max(), uint32_t(1))); + CHECK_EQUAL(uint32_t(0U), etl::divide_round_half_odd(uint32_t(1), std::numeric_limits::max())); + } }; }