浮点误差使“点在圆周上”需用容差判断而非直接比较,推荐用平方距离与epsilon比较,整数坐标且半径为整数时可用精确整数判别,但需防溢出;半径非正须特殊处理。

浮点误差让“精确位于”变成伪命题
直接用 distance == radius 判断点是否在圆周上,在 C++ 里几乎总是错的。浮点运算存在舍入误差,哪怕数学上严格满足,计算出的距离也极大概率不等于 radius。比如一个理论上刚好在圆上的点,sqrt((x-x0)*(x-x0) + (y-y0)*(y-y0)) 可能返回 4.999999999999999 或 5.000000000000001,而你的 radius 是 5.0 —— 比较结果为 false。
必须用误差容忍(epsilon)做近似判断:
const double eps = 1e-9; double dx = x - cx; double dy = y - cy; double dist_sq = dx * dx + dy * dy; double diff = std::abs(dist_sq - radius * radius); return diff
- 推荐比较平方距离,避免调用
sqrt(更快、更稳) -
eps值需匹配数据量级:若坐标在1e6级,1e-9就太小,应取1e-3左右 - 别用
std::numeric_limits直接当比较阈值——它表示的是 1.0 附近的相对精度,不是通用容差::epsilon()
当输入是整数坐标且半径为整数时,可用精确整数判别
如果所有输入都是整数(int cx, cy, x, y, r),且你真正需要的是“数学意义上的精确落在圆周上”,那可以绕过浮点,用整数运算验证:(x-cx)² + (y-cy)² == r²。这完全精确,无任何误差。
但要注意:
- 必须确保中间结果不溢出:比如
int最大值约 2e9,(x-cx)若达 5e4,其平方就超限。建议用long long存储平方和 - 一旦涉及小数输入(如
float或用户输入带小数),这条路立刻失效,必须回归浮点容差 - 即使坐标是整数,若半径是
double r = 5.0,也不能直接用r*r和整数平方比——因为5.0*5.0在二进制浮点中可能不精确表示为 25
std::hypot 更安全,但不解决根本问题
std::hypot(dx, dy) 比 sqrt(dx*dx + dy*dy) 更抗溢出和下溢,适合坐标差极大或极小的场景。但它仍是浮点运算,返回值仍有误差,不能替代容差判断。
正确用法仍是:
double d = std::hypot(x - cx, y - cy); return std::abs(d - radius)
- 仅当怀疑
dx*dx + dy*dy可能溢出(例如坐标差 > 1e9)时才值得换用hypot - 多数常规图形或几何计算中,平方距离法更高效、更常用
-
hypot在某些旧库或嵌入式平台上可能缺失或慢,需确认可用性
边界情况:半径为零或负数
圆的定义要求半径 > 0。若 radius ,则“圆周”无意义——半径为 0 时只有圆心一个点;负半径无几何定义。代码里应明确处理:
- 若
radius ,直接返回false或抛异常 - 若
radius == 0,则仅当x == cx && y == cy时返回true(注意:此时是点,不是“周界线”) - 不要依赖用户传入合法半径——生产代码必须校验
真正麻烦的不是公式,而是想清楚你到底要什么:是数学理想情况下的精确判定,还是工程中可接受的近似;是整数格点问题,还是连续空间中的浮点定位。选错前提,再准的代码也跑偏。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











