首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 計算地理座標距離:Haversine 公式實作與精度說明

     編輯:Java 相關知識

前言

計算兩組經緯度間的球面距離是 LBS 應用常見需求。本文提供基於 Haversine 公式 的 Java 實作,並說明公式原理、精度考量與替代方案。

一、Haversine 公式原理

假設地球為半徑 R = 6371 km 的完美球體,兩點 (lat1, lon1), (lat2, lon2) (弧度) 的球面距離:

a = sin²(Δlat/2) + cos(lat1)·cos(lat2)·sin²(Δlon/2)
c = 2·atan2(√a, √(1−a))
d = R·c

此公式在短距離數值穩定性優於球面餘弦定理,且避免反余弦在極小角度的精度損失。

二、Java 標準實作

public class GeoDistance {

    private static final double EARTH_RADIUS_KM = 6371.0; // 平均半徑
    private static final double DEG_TO_RAD = Math.PI / 180.0;

    /**
     * 計算兩點間球面距離 (公里)
     * @param lon1 經度1
     * @param lat1 緯度1
     * @param lon2 經度2
     * @param lat2 緯度2
     * @return 距離 (km)
     */
    public static double haversine(double lon1, double lat1, double lon2, double lat2) {
        double dLat = (lat2 - lat1) * DEG_TO_RAD;
        double dLon = (lon2 - lon1) * DEG_TO_RAD;

        double lat1Rad = lat1 * DEG_TO_RAD;
        double lat2Rad = lat2 * DEG_TO_RAD;

        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                   Math.cos(lat1Rad) * Math.cos(lat2Rad) *
                   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;
    }

    /** 便利方法:回傳公尺 */
    public static double haversineInMeters(double lon1, double lat1, double lon2, double lat2) {
        return haversine(lon1, lat1, lon2, lat2) * 1000;
    }

    // 測試主程式
    public static void main(String[] args) {
        // 台北 101 到 台北車站 約 3.3 km
        double dist = haversine(121.5645, 25.0338, 121.5173, 25.0478);
        System.out.printf("距離: %.2f km (%.0f m)%n", dist, dist * 1000);
    }
}

三、精度與效能比較

方法精度適用場景備註
Haversine~0.5% 誤差 (球體假設)一般 LBS、物流估算、半徑搜尋速度快、無依賴
Vincenty 公式毫米級 (橢球體 WGS84)測量、精密導航迭代收斂、較慢、極點可能不收斂
GeographicLib奈米級科學計算、GIS 核心Java 移植版 geographiclib-java
PostGIS / MySQL ST_Distance資料庫層級空間查詢、就近搜尋推薦下推至 DB 層

四、實務優化技巧

  • 單位統一:內部一律用弧度,介面可接受度數自動轉換。
  • 避免重複計算:同一查詢點對多目標時,預先計算 sin(lat), cos(lat)。
  • 向量化:批次計算可用 double[] + 迴圈展開,或專案引入 Vector API (JEP 338/Incubator)。
  • 邊界過濾:先用簡易矩形包絡盒 (|Δlat|<threshold && |Δlon|<threshold) 粗篩,再精算。

五、常見誤區

  1. 直接用歐幾里得距離 √(Δx²+Δy²) 計算經緯度 → 嚴重錯誤,極地附近誤差極大。
  2. 假設 1 度 ≈ 111 km 直接相乘 → 忽略經度隨緯度變化 (cos(lat)),中高緯度誤差 > 30%。
  3. 忽略海拔高度 → 山區實際路徑距離會比球面距離長。

六、總結

Haversine 公式以 極低複雜度、零依賴、足夠精度 成為行動應用計算距離的首選。若需測量級精度,請改用 GeographicLib 或資料庫空間函式。記得根據業務場景選擇「球面距離」還是「路網距離」(需結合地圖 API)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved