核心是通过圆心距平方与半径和差平方比较判断位置关系:dist_sq < (r1−r2)²时内含,dist_sq < (r1+r2)²且不内含时相交(含外切),否则分离;全程避免sqrt,用eps处理浮点误差。

怎么用圆心距离判断两个圆的位置关系
核心就一句话:比较两圆心距离与两半径之和、两半径之差的绝对值。不需要调用任何几何库,纯算术运算就能搞定。
设圆 A 圆心为 (x1, y1)、半径 r1,圆 B 圆心为 (x2, y2)、半径 r2。先算平方距离避免开方(提升性能且防浮点误差):
double dx = x1 - x2; double dy = y1 - y2; double dist_sq = dx * dx + dy * dy;
再分类判断:
- 若
dist_sq < (r1 - r2) * (r1 - r2)(且r1 >= r2),则 B 完全在 A 内部(内含);反过来若r2 > r1且dist_sq < (r2 - r1) * (r2 - r1),则是 A 在 B 内 - 若
dist_sq == (r1 - r2) * (r2 - r1)(即dist_sq == 0且半径相等,或刚好内切),注意浮点数慎用==,建议用abs(dist_sq - diff_sq) < eps - 若
dist_sq < (r1 + r2) * (r1 + r2),且不满足内含条件,则两圆相交(含外切) - 若
dist_sq == (r1 + r2) * (r1 + r2),则外切;>则分离
为什么推荐用平方距离而不是 sqrt
开方运算慢,还引入额外浮点误差。所有比较逻辑(相交、内含、相切)都只依赖距离的大小关系,完全可绕过 sqrt。
立即学习“C++免费学习笔记(深入)”;
常见错误是写成:
if (sqrt(dist_sq) < r1 + r2) // ❌ 不必要,且 sqrt 可能返回 NaN(如 dist_sq 极小负数)
正确写法直接比平方:
if (dist_sq < (r1 + r2) * (r1 + r2)) // ✅
注意:当 r1 或 r2 为负时行为未定义——务必确保输入半径非负,否则结果无意义。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
处理浮点精度问题的实际技巧
用 double 时,dist_sq 和半径计算可能有微小误差,导致本该相切却判为相交或分离。
简单可靠的做法是引入容差 eps:
const double eps = 1e-9;
double sum_sq = (r1 + r2) * (r1 + r2);
double diff_sq = (r1 > r2 ? r1 - r2 : r2 - r1);
diff_sq *= diff_sq;
<p>if (dist_sq < sum_sq - eps) {
// 相交或内含
} else if (dist_sq < sum_sq + eps) {
// 外切(近似)
}关键点:
-
eps值取决于坐标量级,若坐标在百万级,1e-9可能太小,可改用相对误差:eps * sum_sq - 内含判断也需加
eps:用dist_sq + eps < diff_sq而非<= - 不要对
sqrt(dist_sq)加eps后再平方——会放大误差
C++ 实现一个健壮的 circles_intersect_or_contain 函数
把上面逻辑封装成函数时,明确区分三种状态更实用:相交(含外切)、内含(含内切)、分离。
enum class CircleRelation { SEPARATE, INTERSECT, CONTAIN };
<p>CircleRelation relation(double x1, double y1, double r1,
double x2, double y2, double r2) {
if (r1 < 0 || r2 < 0) return CircleRelation::SEPARATE; // 非法输入兜底
double dx = x1 - x2, dy = y1 - y2;
double dist_sq = dx<em>dx + dy</em>dy;
const double eps = 1e-9;</p><pre class='brush:php;toolbar:false;'>double r_sum = r1 + r2;
double r_sum_sq = r_sum * r_sum;
double r_diff = std::abs(r1 - r2);
double r_diff_sq = r_diff * r_diff;
if (dist_sq + eps < r_diff_sq) {
return CircleRelation::CONTAIN;
}
if (dist_sq < r_sum_sq + eps) {
return CircleRelation::INTERSECT;
}
return CircleRelation::SEPARATE;}
这个函数没用 sqrt,处理了负半径,用了合理容差,返回语义清晰的状态——比布尔返回值更能支撑后续逻辑分支。
真正容易被忽略的是:当两圆同心(dx=dy=0)且半径相等时,属于“内含”还是“重合”?数学上重合是内含的特例,代码里按 dist_sq == 0 && r1 == r2 仍走 CONTAIN 分支,没问题;但若业务需要单独识别重合,得额外加判断。

















