Haversine公式是计算球面大圆距离最常用且可靠的方法,它将地球近似为球体,通过经纬度推导两点间最短弧长,精度满足多数工程需求(误差通常在0.5%以内)。

用 haversine 公式算球面距离最常用也最可靠
地球近似球体,haversine 公式专为球面大圆距离设计,精度够用(误差通常
关键步骤:把经纬度转成弧度,套公式,再乘地球平均半径(6371.0 km 或 3958.8 miles)。
-
lat1、lon1、lat2、lon2必须是 弧度制,不是度数;忘了deg2rad转换会导致结果错得离谱(比如算出几百米而不是几百公里) - 用
std::sin、std::cos、std::atan2,别手写泰勒展开——标准库已优化且处理边界值更安全 - 推荐直接用
std::sqrt和std::pow,但注意std::pow(x, 2)比x * x略慢,高频调用时建议手写平方
std::atan2 是计算角度的唯一安全选择
很多初学者用 std::acos 实现 haversine,但当两点几乎重合或接近对跖点时,浮点误差会让 acos 输入超出 [-1, 1],触发 nan 或域错误。而 std::atan2 天然规避这个问题。
标准 haversine 距离公式最后一步是:d = 2 * R * atan2(sqrt(a), sqrt(1-a)),其中 a 是中间项。等价但更稳的写法是:
double a = sin_dlat/2 * sin_dlat/2 + cos(lat1) * cos(lat2) * sin_dlon/2 * sin_dlon/2; double c = 2 * atan2(sqrt(a), sqrt(1-a));
但实际中更推荐直接用 atan2(sqrt(a), sqrt(1-a)) 的变体——即:
double c = 2 * atan2(sqrt(a), sqrt(std::max(0.0, 1.0 - a))); // 防 -0 或超限
-
std::max(0.0, 1.0 - a)防止因浮点扰动导致1-a为负 - 别依赖
std::acos,尤其在嵌入式或低精度 float 场景下,它比atan2更容易崩
要注意 WGS84 坐标系和单位一致性
绝大多数公开经纬度(如高德、Google Maps、GPS 设备输出)默认是 WGS84 坐标系,对应地球平均半径 6371.0 km。如果你混用了其他椭球模型(如 GRS80),或者误把半径当成 6378(赤道半径),误差会随纬度升高而变大(极地附近偏差可达 0.2%)。
- 输入坐标必须是
decimal degrees(如39.9042,116.4074),不是 DMS 格式(度分秒) - 若输入是字符串(如
"39°54'15.12\"N"),必须先解析成十进制度数,否则整个计算无效 - 输出单位由你选的
R决定:用6371.0得 km,用6371000.0得米,别漏掉小数点或单位换算
简单可抄的 C++ 函数模板
下面这个函数已做防错处理,支持 double 输入,返回单位为千米:
double haversine_distance(double lat1, double lon1, double lat2, double lon2) {
constexpr double R = 6371.0;
auto deg2rad = [](double deg) { return deg * M_PI / 180.0; };
lat1 = deg2rad(lat1); lon1 = deg2rad(lon1);
lat2 = deg2rad(lat2); lon2 = deg2rad(lon2);
<pre class="brush:php;toolbar:false;">double dlat = lat2 - lat1;
double dlon = lon2 - lon1;
double a = std::sin(dlat/2) * std::sin(dlat/2) +
std::cos(lat1) * std::cos(lat2) *
std::sin(dlon/2) * std::sin(dlon/2);
double c = 2 * std::atan2(std::sqrt(a), std::sqrt(std::max(0.0, 1.0 - a)));
return R * c;
}
调用示例:double dist = haversine_distance(39.9042, 116.4074, 31.2304, 121.4737); // 北京→上海,约 1068 km
如果要更高精度(比如测绘级),就得上 Vincenty 公式或 GeographicLib 库——但那会引入外部依赖,且对多数定位、物流、LBS 场景属于过度设计。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











