diff --git a/include/zephyr/sys/util.h b/include/zephyr/sys/util.h index d8a63a25e9d..f352e7b7a80 100644 --- a/include/zephyr/sys/util.h +++ b/include/zephyr/sys/util.h @@ -259,6 +259,25 @@ extern "C" { */ #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +/** + * @brief Divide and round to the nearest integer. + * + * Example: + * @code{.c} + * DIV_ROUND_CLOSEST(5, 2); // 3 + * DIV_ROUND_CLOSEST(5, -2); // -3 + * DIV_ROUND_CLOSEST(5, 3); // 2 + * @endcode + * + * @param n Numerator. + * @param d Denominator. + * + * @return The result of @p n / @p d, rounded to the nearest integer. + */ +#define DIV_ROUND_CLOSEST(n, d) \ + ((((n) < 0) ^ ((d) < 0)) ? ((n) - ((d) / 2)) / (d) : \ + ((n) + ((d) / 2)) / (d)) + /** * @brief Ceiling function applied to @p numerator / @p divider as a fraction. * @deprecated Use DIV_ROUND_UP() instead. diff --git a/tests/unit/util/main.c b/tests/unit/util/main.c index 18a33802eb5..bce626f9fe4 100644 --- a/tests/unit/util/main.c +++ b/tests/unit/util/main.c @@ -151,6 +151,11 @@ ZTEST(util_cxx, test_DIV_ROUND_UP) run_DIV_ROUND_UP(); } +ZTEST(util_cxx, test_DIV_ROUND_CLOSEST) +{ + run_DIV_ROUND_CLOSEST(); +} + ZTEST_SUITE(util_cxx, NULL, NULL, NULL, NULL, NULL); #if __cplusplus @@ -294,4 +299,9 @@ ZTEST(util_cc, test_DIV_ROUND_UP) run_DIV_ROUND_UP(); } +ZTEST(util_cc, test_DIV_ROUND_CLOSEST) +{ + run_DIV_ROUND_CLOSEST(); +} + ZTEST_SUITE(util_cc, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/unit/util/test.inc b/tests/unit/util/test.inc index aef613b9591..c47cc7ab7e2 100644 --- a/tests/unit/util/test.inc +++ b/tests/unit/util/test.inc @@ -615,3 +615,16 @@ void run_DIV_ROUND_UP(void) zassert_equal(DIV_ROUND_UP(1, 2), 1); zassert_equal(DIV_ROUND_UP(3, 2), 2); } + +void run_DIV_ROUND_CLOSEST(void) +{ + zassert_equal(DIV_ROUND_CLOSEST(0, 1), 0); + /* 5 / 2 = 2.5 -> 3 */ + zassert_equal(DIV_ROUND_CLOSEST(5, 2), 3); + zassert_equal(DIV_ROUND_CLOSEST(5, -2), -3); + zassert_equal(DIV_ROUND_CLOSEST(-5, 2), -3); + zassert_equal(DIV_ROUND_CLOSEST(-5, -2), 3); + /* 7 / 3 = 2.(3) -> 2 */ + zassert_equal(DIV_ROUND_CLOSEST(7, 3), 2); + zassert_equal(DIV_ROUND_CLOSEST(-7, 3), -2); +}