Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions include/zephyr/sys/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,95 @@ static inline size_t sys_count_bits(const void *value, size_t len)
return cnt;
}

/**
* @brief Returns the sign of a number.
*
* @param x The input value to determine the sign
*
* @retval 1 if x is positive
* @retval -1 if x is negative
* @retval 0 if x is zero
*/
#define SIGN(x) (((x) > 0) - ((x) < 0))

/**
* @brief Compute the Greatest Common Divisor (GCD) of two integers
* using the Euclidean algorithm.
*
* @param a First integer
* @param b Second integer
*
* @return The greatest common divisor of a and b, always returns a positive value.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This statement is not quite true. If both a and b are INT_MIN, then the result will be INT_MIN -- a negative value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By mathematical definition, the greatest common divisor (GCD) of two integers is always a non-negative integer. But you are right, the old implementation didn't treat this edge case when both a and b are INT_MIN. We fixed this in the current push. Thanks !

* If one of the parameters is 0, returns the absolute value of the other parameter.
*/
#define gcd(a, b) \
_Generic((a), \
int8_t : gcd_s, \
int16_t : gcd_s, \
int32_t : gcd_s, \
uint8_t : gcd_u, \
uint16_t : gcd_u, \
uint32_t : gcd_u)(a, b)

static ALWAYS_INLINE uint32_t gcd_u(uint32_t a, uint32_t b)
{
uint32_t c;

if (a == 0) {
return b;
}

if (b == 0) {
return a;
}

c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}

return b;
}

static ALWAYS_INLINE int32_t gcd_s(int32_t a, int32_t b)
{
return gcd_u(a < 0 ? -a : a, b < 0 ? -b : b);
}

/**
* @brief Compute the Least Common Multiple (LCM) of two integers.
*
* @param a First integer
* @param b Second integer
*
* @retval The least common multiple of a and b.
* @retval 0 if either input is 0.
*/
#define lcm(a, b) \
_Generic((a), \
int8_t : lcm_s, \
int16_t : lcm_s, \
int32_t : lcm_s, \
uint8_t : lcm_u, \
uint16_t : lcm_u, \
uint32_t : lcm_u)(a, b)

static ALWAYS_INLINE uint64_t lcm_u(uint32_t a, uint32_t b)
{
if (a == 0 || b == 0) {
return 0;
}

return (uint64_t)(a / gcd_u(a, b)) * (uint64_t)b;
}

static ALWAYS_INLINE int64_t lcm_s(int32_t a, int32_t b)
{
return lcm_u(a < 0 ? -a : a, b < 0 ? -b : b);
}

#ifdef __cplusplus
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion west.yml
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ manifest:
groups:
- hal
- name: hal_stm32
revision: 286dd285b5bb4fddafdfff27b5405264e5a61bfe
revision: pull/327/head
path: modules/hal/stm32
groups:
- hal
Expand Down
Loading