Skip to content

Commit c9f5668

Browse files
committed
sys: util: Add gcd and lcm utilities
Add helpers to compute Greates Common Divisor (GCD) and Least Common Multiple (LCM). Signed-off-by: Phi Bang Nguyen <[email protected]> Signed-off-by: Trung Hieu Le <[email protected]>
1 parent 40ac5e4 commit c9f5668

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed

include/zephyr/sys/util.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,84 @@ static inline size_t sys_count_bits(const void *value, size_t len)
10381038
*/
10391039
#define SIGN(x) (((x) > 0) - ((x) < 0))
10401040

1041+
/**
1042+
* @brief Compute the Greatest Common Divisor (GCD) of two integers
1043+
* using the Euclidean algorithm.
1044+
*
1045+
* @param a First integer
1046+
* @param b Second integer
1047+
*
1048+
* @return The greatest common divisor of a and b, always returns a positive value.
1049+
* If one of the parameters is 0, returns the absolute value of the other parameter.
1050+
*/
1051+
#define gcd(a, b) \
1052+
_Generic((a), \
1053+
int8_t : gcd_s, \
1054+
int16_t : gcd_s, \
1055+
int32_t : gcd_s, \
1056+
uint8_t : gcd_u, \
1057+
uint16_t : gcd_u, \
1058+
uint32_t : gcd_u)(a, b)
1059+
1060+
static ALWAYS_INLINE uint32_t gcd_u(uint32_t a, uint32_t b)
1061+
{
1062+
uint32_t c;
1063+
1064+
if (a == 0) {
1065+
return b;
1066+
}
1067+
1068+
if (b == 0) {
1069+
return a;
1070+
}
1071+
1072+
c = a % b;
1073+
while (c != 0) {
1074+
a = b;
1075+
b = c;
1076+
c = a % b;
1077+
}
1078+
1079+
return b;
1080+
}
1081+
1082+
static ALWAYS_INLINE int32_t gcd_s(int32_t a, int32_t b)
1083+
{
1084+
return gcd_u(a < 0 ? -a : a, b < 0 ? -b : b);
1085+
}
1086+
1087+
/**
1088+
* @brief Compute the Least Common Multiple (LCM) of two integers.
1089+
*
1090+
* @param a First integer
1091+
* @param b Second integer
1092+
*
1093+
* @retval The least common multiple of a and b.
1094+
* @retval 0 if either input is 0.
1095+
*/
1096+
#define lcm(a, b) \
1097+
_Generic((a), \
1098+
int8_t : lcm_s, \
1099+
int16_t : lcm_s, \
1100+
int32_t : lcm_s, \
1101+
uint8_t : lcm_u, \
1102+
uint16_t : lcm_u, \
1103+
uint32_t : lcm_u)(a, b)
1104+
1105+
static ALWAYS_INLINE uint64_t lcm_u(uint32_t a, uint32_t b)
1106+
{
1107+
if (a == 0 || b == 0) {
1108+
return 0;
1109+
}
1110+
1111+
return (uint64_t)(a / gcd_u(a, b)) * (uint64_t)b;
1112+
}
1113+
1114+
static ALWAYS_INLINE int64_t lcm_s(int32_t a, int32_t b)
1115+
{
1116+
return lcm_u(a < 0 ? -a : a, b < 0 ? -b : b);
1117+
}
1118+
10411119
#ifdef __cplusplus
10421120
}
10431121
#endif

0 commit comments

Comments
 (0)