std::gcd最省事但需C++17支持,包含并启用-std=c++17;它自动处理负数、返回非负结果,但gcd(0,0)抛domain_error;手写推荐取模循环版,注意abs输入、用long long防溢出,并确保结果非负。

用 std::gcd 最省事,但得确认编译器支持 C++17
如果你用的是 GCC 8+、Clang 7+ 或 MSVC 2017 及以上,默认开启 C++17 就能直接调 std::gcd。它在 头文件里,处理 int、long long 等整型都没问题,还自动处理负数(取绝对值后算)。
常见错误是忘了加头文件或编译标准,比如用 g++ main.cpp 不带 -std=c++17 就会报错:‘gcd’ is not a member of ‘std’。
- 必须写
#include - 编译时加
-std=c++17(GCC/Clang)或确保 MSVC 设置为 ISO C++17 标准 -
std::gcd(0, 5)返回5,std::gcd(0, 0)抛std::domain_error—— 这点容易被忽略,线上代码建议先判零
手写辗转相除法:用 % 和循环比递归更安全
递归写法简洁,但两个大数(比如接近 INT_MAX)相除时可能栈溢出;循环版本无此风险,也更容易加调试输出或提前终止条件。
核心就是反复做 a = b, b = a % b,直到 b == 0,此时 a 就是结果。注意初始就要对负数取绝对值,否则 % 在 C++ 中的符号依赖实现(C++11 起规定向被除数看齐,但保险起见还是自己 abs)。
- 用
long long接入参,避免中间a % b溢出(例如INT_MAX % (-1)是未定义行为) - 开头加
if (a == 0 && b == 0) return 0;或按需抛异常,避免除零 - 示例片段:
long long gcd(long long a, long long b) { a = a
为什么不用欧几里得算法的减法版本?
减法版(即“更相减损术”)逻辑简单:while (a != b) { if (a > b) a -= b; else b -= a; },但它在极端情况下极慢——比如 gcd(1, 1000000) 要循环一百万次。而取模版最多约 O(log min(a,b)) 次迭代。
- 减法版只在嵌入式等不能用除法硬件的场景才考虑
- 现代 CPU 的
%指令开销远低于大量分支跳转,实测快几十倍到几百倍 - 如果真要优化取模(比如大整数),可结合位运算先提取公因子 2,但普通
int完全没必要
传入 0 或负数时的行为差异要心里有数
std::gcd 明确定义:输入任意整数,返回非负最大公约数;手写函数若没处理,gcd(-12, 8) 可能返回 -4(取决于你是否对结果再取 abs),这会和标准库不一致,导致协作代码出 bug。
- 标准库要求:结果 ≥ 0,且
gcd(a, b) == gcd(|a|, |b|) - 手写时别只对输入取
abs,最后再包一层return a 更稳妥(虽然理论上循环结束时a ≥ 0,但逻辑清晰更重要) - 边界测试至少覆盖:
(0, 0)、(0, x)、(-x, y)、(x, -y)、(-x, -y)
实际用的时候,优先 std::gcd;需要兼容老标准或定制逻辑(比如中途记录步骤、支持自定义类型),再手写。最常被忽略的是 0 输入的处理和负数符号归一化——这两个点不显眼,但上线后容易引发静默错误。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











