diff --git a/base/base_tests/math_test.cpp b/base/base_tests/math_test.cpp index 4feb161c62..cd0606dc7e 100644 --- a/base/base_tests/math_test.cpp +++ b/base/base_tests/math_test.cpp @@ -131,3 +131,13 @@ UNIT_TEST(IsIntersect_Intervals) TEST(my::IsIntersect(0, 100, -50, 0), ()); TEST(!my::IsIntersect(0, 100, -50, -20), ()); } + +UNIT_TEST(GCD_Test) +{ + TEST_EQUAL(my::GCD(6, 3), 3, ()); + TEST_EQUAL(my::GCD(14, 7), 7, ()); + TEST_EQUAL(my::GCD(100, 100), 100, ()); + TEST_EQUAL(my::GCD(7, 3), 1, ()); + TEST_EQUAL(my::GCD(8, 3), 1, ()); + TEST_EQUAL(my::GCD(9, 3), 3, ()); +} diff --git a/base/math.hpp b/base/math.hpp index f1eed73e8b..41614af7a4 100644 --- a/base/math.hpp +++ b/base/math.hpp @@ -139,4 +139,49 @@ inline uint32_t NextPowOf2(uint32_t v) return v + 1; } +// Greatest Common Divisor +inline uint32_t GCD(uint32_t a, uint32_t b) +{ + uint32_t multiplier = 1; + uint32_t gcd = 1; + while (true) + { + if (a == 0 || b == 0) + { + gcd = max(a, b); + break; + } + + if (a == 1 || b == 1) + { + gcd = 1; + break; + } + + if ((a & 0x1) == 0 && (b & 0x1) == 0) + { + multiplier <<= 1; + a >>= 1; + b >>= 1; + continue; + } + + if ((a & 0x1) != 0 && (b & 0x1) != 0) + { + uint32_t minV = min(a, b); + uint32_t maxV = max(a, b); + a = (maxV - minV) >> 1; + b = minV; + continue; + } + + if ((a & 0x1) != 0) + swap(a, b); + + a >>= 1; + } + + return multiplier * gcd; +} + }