据我所知,问题在于 atan2() 的参数顺序因语言而异。以下对我有用*:
Option Explicit
Public Sub Distance()
Dim dbl_Longitude1 As Double, dbl_Longitude2 As Double, dbl_Latitude1 As Double, dbl_Latitude2 As Double
dbl_Longitude1 = 55.629178
dbl_Longitude2 = 29.846686
dbl_Latitude1 = 37.659466
dbl_Latitude2 = 30.24441
Dim dbl_dLat As Double
Dim dbl_dLon As Double
Dim dbl_a As Double
Dim dbl_P As Double
dbl_P = WorksheetFunction.Pi / 180
dbl_dLat = dbl_P * (dbl_Latitude2 - dbl_Latitude1) 'to radians
dbl_dLon = dbl_P * (dbl_Longitude2 - dbl_Longitude1) 'to radians
dbl_a = Sin(dbl_dLat / 2) * Sin(dbl_dLat / 2) + _
Cos(dbl_Latitude1 * dbl_P) * Cos(dbl_Latitude2 * dbl_P) * Sin(dbl_dLon / 2) * Sin(dbl_dLon / 2)
Dim c As Double
Dim dbl_Distance_KM As Double
c = 2 * WorksheetFunction.Atan2(Sqr(1 - dbl_a), Sqr(dbl_a)) ' *** swapped arguments to Atan2
dbl_Distance_KM = 6371 * c
Debug.Print dbl_Distance_KM
End Sub
*输出:2507.26205401321
虽然gcmap.com说答案是 2512 公里。这可能是一个精度问题——我认为它足够接近可以算作工作。(编辑它也可能是 gcmap 使用当地地球半径而不是平均半径;我不确定。)
解释
我发现了大圆距离的半正弦公式的描述,这就是你正在实现的。该页面上的 JavaScript 实现提供了以下计算c
:
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
在 JavaScript 中,atan2()接受参数y
, x
. 但是,在 Excel VBA 中,WorksheetFunction.Atan2
采用参数x
, y
. 您的原始代码作为第一个参数传递Sqr(dbl_a)
,就像在 JavaScript 中一样。但是,Sqr(dbl_a)
需要是 Excel VBA 中的第二个参数。
关于命名的评论
基于@JohnColeman 的观点,有很多方法可以命名变量。在这种情况下,我建议使用单位前缀而不是类型前缀:例如deg_Latitude1
,、、RadPerDeg = Pi/180
和rad_dLat = RadPerDeg * (deg_Latitude2 - deg_Latitude1)
。我个人认为这有助于避免单位转换失误。