You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haversine公式实现异常:路线距离计算结果不准确求助

免责声明:此为家庭作业,请不要认真对待,也请勿为该问题花费超过2秒时间,不值得为此费心,抱歉。

问题:Haversine公式计算路线距离结果不准确

我正尝试计算路线的近似距离。getPoints方法负责从SQLite数据库中获取所有路线点并写入ArrayList数组,该部分运行符合预期。但在执行距离计算时出现问题,Haversine公式计算出的距离结果不准确。我推测问题出在distance方法中,但无法自行定位问题,对比原版Haversine公式实现也未发现差异。

代码片段如下:

public ArrayList<Double> getPoints() {
    ArrayList<Double> location = new ArrayList<>();
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor cursor = db.rawQuery("select latitude,longitude from " + Table_Name_Location, null);
    if (cursor.getCount() > 0) {
        while (cursor.moveToNext()) {
            Double latitude = cursor.getDouble(cursor.getColumnIndex("Lat"));
            Double longitude = cursor.getDouble(cursor.getColumnIndex("Longi"));
            location.add(latitude);
            location.add(longitude);
        }
    }
    cursor.close();
    return location;
}

private double distance(double lat1, double lon1, double lat2, double lon2) {
    double theta = lon1 - lon2;
    double dist = Math.sin(deg2rad(lat1))
            * Math.sin(deg2rad(lat2))
            + Math.cos(deg2rad(lat1))
            * Math.cos(deg2rad(lat2))
            * Math.cos(deg2rad(theta));
    dist = Math.acos(dist);
    dist = rad2deg(dist);
    dist = dist * 60 * 1.1515;
    return (dist);
}

private double deg2rad(double deg) {
    return (deg * Math.PI / 180.0);
}

private double rad2deg(double rad) {
    return (rad * 180.0 / Math.PI);
}

问题排查及修复方案

  1. 数据库字段名不匹配
    SQL查询的字段是latitude和longitude,但取字段值时用的是"Lat"和"Longi",如果数据库实际字段名是前者,会导致获取到错误的经纬度值,直接影响距离计算结果。修改getColumnIndex的参数为查询的字段名:

    Double latitude = cursor.getDouble(cursor.getColumnIndex("latitude"));
    Double longitude = cursor.getDouble(cursor.getColumnIndex("longitude"));
    
  2. 余弦定理版本的精度缺陷
    当前distance方法用的是余弦定理实现,当两点距离极近时,Math.acos容易因浮点精度问题出现误差。改用标准Haversine公式实现,近距离计算精度更稳定:

    private double distance(double lat1, double lon1, double lat2, double lon2) {
        final int EARTH_RADIUS_KM = 6371; // 地球半径(公里),要英里则改为3956
        double dLat = deg2rad(lat2 - lat1);
        double dLon = deg2rad(lon2 - lon1);
        
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
                + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2))
                * Math.sin(dLon / 2) * Math.sin(dLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        
        return EARTH_RADIUS_KM * c;
    }
    
  3. 缺失路线距离累加逻辑
    如果要计算整条路线的总距离,需要遍历getPoints返回的列表,依次计算相邻两点的距离并累加:

    public double getTotalRouteDistance() {
        ArrayList<Double> points = getPoints();
        double total = 0;
        // 每次取两组经纬度,步进为2
        for (int i = 0; i < points.size() - 3; i += 2) {
            total += distance(points.get(i), points.get(i+1), points.get(i+2), points.get(i+3));
        }
        return total;
    }
    

内容的提问来源于stack exchange,提问作者elfxea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 19:40:25