I'll add to comments made by others.
In "real life" - use the standard library version
Well, first and foremost - I understand you're writing this as an exercise, but it must be said that for code you actually intend to use for anything - prefer the C++ standard library's std::gcd
from <numeric>
.
As a comment kindly points out, this is only available starting from C++17.
Consider recursion over loops
I would suggest you consider avoiding loops in favor of recursion, unless you're working on some super-optimized version (in which case your code would be different anyway).
I'm not claiming that's the "best" thing to do, but in mathematics we often define things recrusively and validate the definition inductively. This also goes for the the gcd: Consider the following recursive implementation (assuming non-negative integers):
constexpr unsigned gcd(unsigned n, unsigned m)
if (m == 0) { return n; }
if (n < m) { return gcd(m, n); }
return gcd(m, n - m);
}
(I chose unsigned to avoid more code for negative numbers.)
it is very easy to prove this is correct - that each statement is correct. And I do mean prove in the mathematical sense. With imperative code and loops, that doesn't happen as often.
One should note the above implementation is problematic in that it involves much deeper recursion than is necessary: O(n/m) calls (for n > m) rather than O(log(n/m)) (thanks @KevinCline for reminding me to point that out.) Here's another version - more efficient, even more terse, and also recursive:
constexpr int gcd(int greater, int lesser) {
if (smaller == 0) { return greater; }
return gcd(m, n % m);
}
... and we don't even need to assume non-negativity.
Consider templating for wider applicability
The last example (as well as many imperative/loop-based versions) could be used for any type which behavies kinda-sorta like the integers (e.g. constitutes a Euclidean Domain if you ignore overflow). So you can implement your GCD at once for all such types:
template <typename EuclideanDomain>
constexpr EuclideanDomain gcd(EuclideanDomain greater, EuclideanDomain lesser) {
if (smaller == 0) { return greater; }
return gcd(m, n % m);
}
std::min
andstd::max
? If your<algorithm>
also puts names into the global namespace, you can easily write code that's not portable. \$\endgroup\$