std::lcm 和 std::gcd 定义于 (c++17 起),仅接受同类型整型参数,负数按绝对值计算;std::lcm(0,x) 抛 std::domain_error;多参数可用 std::accumulate 扩展,初值分别为 0 和 1。

std::lcm 和 std::gcd 在哪定义、怎么用
这两个函数在 <numeric></numeric> 头文件里,C++17 起才可用。不是 <algorithm></algorithm>,也不是 <cmath></cmath>,写错头文件会直接编译失败,报 ‘lcm’ was not declared in this scope。
它们只接受两个**同类型**的整型参数(int、long long 等),不支持浮点数,也不支持自定义类型。传入负数时,结果按绝对值计算——比如 std::gcd(-12, 8) 返回 4,std::lcm(-6, 4) 返回 12。
使用示例:
#include <numeric>
#include <iostream><p>int main() {
std::cout </p>
<h3>为什么 std::lcm(0, x) 或 std::lcm(x, 0) 会抛异常</h3>
<p><code>std::lcm</code> 对零的处理是明确未定义行为:只要任一参数为 0,就会抛出 <code>std::domain_error</code>。这不是 bug,是标准强制要求——因为数学上 lcm(0, a) 通常视为 0(当 a ≠ 0),但 C++ 标准选择保守策略,避免歧义和溢出风险。</p>
<p>常见踩坑场景:</p>
<ul>
<li>从用户输入或配置读取数字后直接传给 <code>std::lcm</code>,没做零值检查</li>
<li>用容器元素两两调用 <code>std::lcm</code>,而容器中混有 0</li>
<li>误以为 <code>std::lcm(a, b) == a * b / std::gcd(a, b)</code> 总成立,却忘了除零和溢出问题</li>
</ul>
<p>安全做法是显式兜底:</p>
<pre class="brush:php;toolbar:false;">auto safe_lcm = [](int a, int b) -> int {
if (a == 0 || b == 0) return 0; // 按需定义语义
return std::lcm(a, b);
};
大数运算时 std::lcm 容易溢出,怎么防
std::lcm(a, b) 内部等价于 abs(a) / std::gcd(a, b) * abs(b),但顺序是先除后乘。如果 a 和 b 都接近 INT_MAX,哪怕除完再乘,中间结果仍可能溢出(尤其 int 类型)。
关键点:
- 溢出不触发异常,而是未定义行为(常见表现为静默错误或负数结果)
-
std::lcm不做溢出检测,也不提供 checked 版本 - 改用
long long可缓解,但不能根治;真正安全需手动检查除法余数和乘法边界
简单防护示例(针对 int):
int safe_lcm(int a, int b) {
if (a == 0 || b == 0) return 0;
int g = std::gcd(a, b);
int a_abs = std::abs(a), b_abs = std::abs(b);
int q = a_abs / g;
if (q > INT_MAX / b_abs) throw std::overflow_error("lcm overflow");
return q * b_abs;
}
多个数求 lcm/gcd 怎么扩展
标准库只提供二元版本,但可以用 std::accumulate 快速扩展到容器:
#include <numeric>
#include <vector><p>std::vector<int> v = {12, 18, 24};
int g = std::accumulate(v.begin(), v.end(), 0, std::gcd<int>);
int l = std::accumulate(v.begin(), v.end(), 1, std::lcm<int>); // 注意初值为 1,不是 0
</int></int></int></p></vector></numeric>
注意:std::accumulate 的初值必须与运算律兼容——gcd 的恒等元是 0(因为 gcd(x, 0) == abs(x)),而 lcm 的恒等元是 1(因为 lcm(x, 1) == abs(x))。用错初值会导致结果错误,比如 lcm 初值设成 0 就直接抛异常。
另外,std::gcd 和 std::lcm 都是左结合,所以顺序不影响结果,但性能上建议先对数据排序(小数在前),可更快收敛。
实际项目里,如果频繁多参数运算且数值范围大,最好用 int128(GCC 扩展)或第三方大数库,别硬扛溢出边界。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











