Haversine_formula

**半正矢公式**是一種根據兩點的經度和緯度來確定大圓上兩點之間距離的計算方法，在導航有著重要地位。它是球面三角學中「半正矢定理」公式的特例，該定理涉及了球面三角形的邊和角。

儘管第一份英文版的半正矢表由詹姆斯・安德魯在 1805 年印刷出版，但弗洛里安・卡喬里相信 José de Mendoza y Ríos 在 1801 年就使用過類似的術語。「半正矢」這個名字由詹姆斯・英曼在 1835 年創造。

這個公式正如其名，用半正矢函數表達，通過 $\operatorname {haversin} (\theta )=\sin ^{2}\left({\frac {\theta }{2}}\right)$ 而來。該公式可以用半正矢函數的任意倍數表達，如正矢函數（半正矢函數的兩倍）。在計算機出現之前，為了計算簡便，人們會利用對數來計算乘積和利用半正矢函數計算距離，所以在十九和二十世紀初的導航和三角測量書中包含了半正矢值表和對數表。現在，將該公式用半正矢函數表達也很方便，因為它能避免 $\sin ^{2}$ 的係數。

## 半正矢公式

對於任何球面上的兩點，圓心角的半正矢值可以通過如下公式計算：

　
: $\operatorname {hav} \left({\frac {d}{r}}\right)=\operatorname {hav} (\varphi _{2}-\varphi _{1})+\cos(\varphi _{1})\cos(\varphi _{2})\operatorname {hav} (\lambda _{2}-\lambda _{1})$

 * $\operatorname {hav} $ 是半正矢函數的縮寫：

　
: $\operatorname {hav} (\theta )=\sin ^{2}\left({\frac {\theta }{2}}\right)={\frac {1-\cos(\theta )}{2}}$

 * $d$ 是兩點之間的距離（沿大圓，見球面距離）；
* $r$ 是球的半徑；
* $\varphi _{1}\varphi _{2}$ ：點 1 的緯度和點 2 的緯度，以弧度制度量；
* $\lambda _{1}\lambda _{2}$ ：點 1 的經度和點 2 的經度，以弧度制度量。

左邊的等號 ${\frac {d}{r}}$ 是圓心角，以弧度來度量。

可以通過應用反半正矢函數（如果可以查到值）或通過使用反正弦函數來解出 $d$ ：

　
: $d=r\operatorname {archav} (h)=2r\arcsin \left({\sqrt {h}}\right)$

 $h=\operatorname {hav} {\frac {d}{r}}$ ，代入可得：

　
: ${\begin{aligned}d&=2r\arcsin \left({\sqrt {\operatorname {hav} (\varphi _{2}-\varphi _{1})+\cos(\varphi _{1})\cos(\varphi _{2})\operatorname {hav} (\lambda _{2}-\lambda _{1})}}\right)\\&=2r\arcsin \left({\sqrt {\sin ^{2}\left({\frac {\varphi _{2}-\varphi _{1}}{2}}\right)+\cos(\varphi _{1})\cos(\varphi _{2})\sin ^{2}\left({\frac {\lambda _{2}-\lambda _{1}}{2}}\right)}}\right)\end{aligned}}$

在使用這個公式時，必須確保 $h$ 不超過 1 （ $d$ 只當 $h$ 的值在 0 到 1 間才有意義）。 $h$ 僅在球面上兩點連線過球心時才為 1 ，當測量精度有限時，會產生較大的計算誤差。 $d$ 如果大到接近圓周的一半長度 $\pi R$ 時（這個情況並不常見），一個小錯誤通常是一個大問題在。雖然還有其他的大圓距離公式，能夠避免這個問題。上述公式有時候用反正切函數表達，但是 $h$ 接近 1 時這個問題仍然存在。

但是仍有對策來避免上述問題。類似的公式可以使用餘弦函數表達（有時亦稱為球面餘弦定理，但是並非平面餘弦定理）而不是半正矢，但如果這兩點十分靠近（例如在地球上的一公里外）你可能得到的結果為 $\cos {\frac {d}{r}}=0.99999999$ ，導致一系列的誤差。而由於半正矢式使用正弦函數，避免了這一問題。所以兩個公式應該互補使用。

因為地球是一個不完美的球體，故當其應用於地球時，無論哪一個公式只是做一個近似測算，「地球半徑」 $R$ 在極點地區是 $6356.752$ 公里，在赤道地區為 $6378.137$ 公里。另外，半徑曲率在極點處（ $\approx 6399.594$ 公里）比在赤道處 ( $\approx 6335.439$ 公里) 大 1% ，所以半正矢公式或者球面餘弦定理是不能保證 0.5% 以內的誤差。更準確的方法，應該是使用考慮地球離心率的 Vincenty 的公式或其他有關地理距離的論文所給出方法。

## 半正矢定理

給出一個單位球，一個在表面的球面三角形三個過三點 $(u,v,w)$ 的大圓所圍出來的區域。如圖，這個球面三角形的三邊分別是 $a$ （ $\mathbf {u} $ 至 $\mathbf {v} $ ）， $b$ （ $\mathbf {u} $ 到 $\mathbf {w} $ ）和 $c$ （ $\mathbf {v} $ 至 $\mathbf {w} $ ）並且角 $C$ 對邊 $c$ 那麼有如下關係

$$
\operatorname {hav} (c)=\operatorname {hav} (a-b)+\sin(a)\sin(b)\operatorname {hav} (C)
$$

由於這是一個單位球，弧長 $a$ 、 $b$ 和 $c$ 與兩端點同球心構成的圓心角（弧度制）相等。

為了從該定理中得到半正矢公式，只需要考慮一種特殊情況，即 $\mathbf {u} $ 是北極，而 $\mathbf {v} $ 和 $\mathbf {w} $ 是需要確定距離 $\mathbf {d} $ 兩個點。在這個情況下， $a$ 和 $b$ 由 ${\frac {\pi }{2}}-\varphi _{1,2}$ 來計算（即 90° - 維度）， $C$ 為經度分隔 $\Delta \lambda $ 和 $c$ 為求得的 ${\frac {d}{R}}$ 。結合 $\sin \left({\frac {\pi }{2}}-\varphi \right)=\cos(\varphi )$ ，半正矢公式即可推導得出。

或者可以從球面餘弦定理中得出

　
: $\cos(c)=\cos(a)\cos(b)+\sin(a)\sin(b)\cos(C)$ $$

當 $c$ 很小時，這個公式精度不高。所以我們可以用 $\cos(\theta )=1-2\operatorname {\operatorname {hav} } (\theta )$ 來替換 ，並引用三角恆等式 $\cos(a-b)=\cos(a)\cos(b)+\sin(a)\sin(b)$ ，半正矢定理就能推出。

## 另見

* 視覺算法

## 參考文獻

## 延伸閱讀

* 美國人口普查局的 地理信息系統的問題 (內容已被轉移到 什麼是最好的方式來計算兩點間的距離？（頁面存檔備份，存於網際網路檔案館）)
* R.W.Sinnott 的 "半正矢的優點", _Sky and Telescope_ **68** (2), 159 (1984).
* 推導半正矢公式（頁面存檔備份，存於網際網路檔案館），_Ask Dr.Math_(Apr. 20–21,1999)。
* Romuald Ireneus'Scibor-Marchocki, 球三角形， 初等幾何 (1997 年)。
* W.Gellert,S.Gottwald,M.Hellwich，H.Kästner 和 H.Küstner 的，_The VNR Concise Encyclopedia of Mathematics_,2nd ed., ch. 12 (Van Nostrand Reinhold：紐約，1989 年)。

## 外部連結

* 用的 91 種程式語言 rosettacode.org 實現半正矢公式（頁面存檔備份，存於網際網路檔案館） 或 17 種程式語言 codecodex.com（頁面存檔備份，存於網際網路檔案館）
* 其它在 C++（頁面存檔備份，存於網際網路檔案館）、C (mac os)（頁面存檔備份，存於網際網路檔案館）、Pascal（頁面存檔備份，存於網際網路檔案館）、Python、Ruby （頁面存檔備份，存於網際網路檔案館）、JavaScript（頁面存檔備份，存於網際網路檔案館）、PHP（頁面存檔備份，存於網際網路檔案館）、Matlab（頁面存檔備份，存於網際網路檔案館）、MySQL 中的實現。
* 由任何兩者之間的緯度和經度計算距離、方位等。http://www.movable-type.co.uk（頁面存檔備份，存於網際網路檔案館）