在计算两个经度点之间的距离时,为什么余弦定律比正弦定律更可取?


41

实际上,当Sinnott发布Haversine公式时,计算精度受到了限制。如今,JavaScript(以及大多数现代计算机和语言)使用IEEE 754 64位浮点数,该数字提供15位有效精度。有了这样的精度,余弦公式(cos c = cos a cos b + sin a sin b cos C)的简单 球面定律就可以提供良好的条件结果,直到小到1米左右的距离。 有鉴于此,在大多数情况下,使用更简单的余弦定律或使用更精确的椭圆形Vincenty公式(而不是正己烷)可能是值得的!(请注意以下关于球形模型精度限制的注意事项)。
资料来源:http : //www.movable-type.co.uk/scripts/latlong.html

余弦定律更可取的原因是什么?

注:引用的文字已经被更新,它的作者提到以下


10
余弦定律如何“优先”?我们可以通过两种方式回答此问题:对于计算机和程序员。对于计算机,haversine公式使用的trig函数较少,但需要两个平方根。为了提高计算效率,这是一个麻烦。对于程序员来说,haversine公式会更长一些。但是,余弦公式定律要求具有ACos实现,这种实现比ATan实现的频率要低一些。此外,要编写防弹代码,您必须检查ACos不会失败。仅出于这个原因,我们应该更喜欢大麻油。
whuber

2
我刚刚在Python中实现了Haversine和余弦。在这台计算机上,haversine需要3.3μs的时间,而余弦需要2.2μs的时间,如果您需要做很多,这是非常重要的
gnibbler 2011年

1
感谢大家的一些有益的观察和信息。我希望我将问题中引用的文本更新为更加客观和有益的。
ChrisV

@ChrisV,感谢您的更新!我将其移至评论中,因为它不能直接回答问题,谢谢您的出色站点。
scw

Answers:


48

该问题由“条件良好”一词表示。这是计算机算术而不是数学的问题。

这里是要考虑的基本事实:

  1. 地球上的一个弧度跨度将近10 ^ 7米。

  2. 参数x接近0 的余弦函数大约等于1- x ^ 2/2。

  3. 双精度浮点的精度约为15个十进制数字。

点(2)和(3)表示,当x约为1米或10 ^ -7弧度(点1)时,几乎所有精度都会丢失:1-(10 ^ -7)^ 2 = 1-10 ^- 14是一种计算,其中15个有效数字中的前14个都被抵消,只剩下一个数字来表示结果。翻转此位置(这就是反余弦“ acos”的作用)意味着无法以任何有意义的精度计算对应于米长度距离的角度的acos。 (在某些糟糕的情况下,精度损失会给出一个甚至未定义acos的值,因此代码将崩溃且不给出答案,无意义的答案或使机器崩溃。)类似的考虑因素建议您应避免使用反余弦值如果距离小于几百米,则取决于您愿意损失多少精度。

在原始的余弦定律公式中,acos扮演的角色是将角度转换为距离。在haversine公式中,atan2发挥了这一作用。小角度x的切线近似等于x本身。因此,近似于该数的数的反正切值基本上在精度上没有损失。这就是为什么Haversine公式虽然在数学上等效于余弦公式,但对于小距离(大约1米或更短),其优越性更高

这是在地球上使用100个随机点对对这两个公式的比较(使用Mathematica的双精度计算)。

替代文字

您可以看到,对于小于约0.5米的距离,这两个公式会发散。在0.5米以上,他们倾向于达成共识。为了显示它们之间的接近程度,下图显示了余弦定律:haversine结果对另外100个随机点对的比率,它们的纬度和经度之间的随机差异最大为5米。

替代文字

这表明,一旦距离超过5-10米,余弦公式的法则就可以精确到小数点后3-4位。精度的小数位数增加了两倍;因此,在50-100米(一个数量级)上,您可以获得5-6 dp的精度(两个数量级);在500-1000米处,您会得到7-8 dp,依此类推。


是否有一些便宜的测试-例如delta latitude > .1 || delta longitude > .1,动态选择余弦(适用于较大)还是正弦(适用于较小距离)?为了获得最佳性能和良好的精度。
2013年

@ Anony-Mousse对于世界四分之一的距离,这两个公式都可能相差百分之一的十分之几,所以到那时我们就不会在精度上大惊小怪了!因此,任何能够将近点(几百米)与几乎完全相反的点(约2000万米)之间的所有东西区分开的测试就足够了。
ub

atan2带来数字收益asin吗?我看到了基准测试,它atan2比慢了2-3倍asin,我们也需要一秒钟sqrt
Erich Schubert

@Erich我还没有研究差异,但是请注意,这asin本质上是相同的acos,因此对于某些值(在这种情况下,对于1和-1左右的参数),精度也遭受相同的损失。原则atan2上没有这个问题。
whuber

那会很远吗?然后将其与@ Anony-Mousse的建议结合起来似乎很有趣。
Erich Schubert

6

历史脚注:

Haversine是一种避免在计算中产生较大舍入误差的方法,例如

1 - cos(x)

当x小时。关于haversine,我们有

1 - cos(x) = 2*sin(x/2)^2
           = 2*haversin(x)

即使x很小,也可以精确计算2 * sin(x / 2)^ 2。

在过去,haversine公式具有避免加法的另一个优点(这需要进行反对数查找,加法和对数查找)。仅仅包含乘法的三角学公式被认为是“对数形式”。

如今,使用haversine公式有点过时了。角度x可能用sin(x)和表示cos(x)(并且x可能未明确知道)。在那种情况下,1 - cos(x)通过haversine公式进行计算需要反正切(获取角度x),减半(获取x/2),正弦(获取sin(x/2)),平方(获取sin(x/2)^2)和最终加倍。使用评估会更好

1 - cos(x) = sin(x)^2/(1 + cos(x))

这不需要三角函数的评估。(显然,只有在使用时,才使用右侧cos(x) > 0;否则,可以1 - cos(x)直接使用 。)


1

余弦公式可以在一行中实现:

  Distance = acos(SIN(lat1)*SIN(lat2)+COS(lat1)*COS(lat2)*COS(lon2-lon1))*6371

Haversine公式包含多行:

  dLat = (lat2-lat1)
  dLon = (lon2-lon1)
  a = sin(dLat/2) * sin(dLat/2) + cos(lat1) * cos(lat2) * sin(dLon/2) * sin(dLon/2)
  distance = 6371 * 2 * atan2(sqrt(a), sqrt(1-a))

从数学上讲,它们是相同的,因此唯一的区别是实用性之一。


虽然原始的Haversine没有使用与计算机相关的atan2公式,但是没有什么可以阻止将上面的4行重写为一个公式。
Arjan

@Arjan,真实的,但它是低效的,因为你需要计算一个两次。该公式必须同时包含Sqrt(a)和Sqrt(1-a),这是至关重要的,因为尽管其中之一对于很小或非常大的距离在数值上都是不稳定的,而对于另一个则不会:这就是使这种方法起作用的原因。
whuber

的确,@ whuber,但我仍然怀疑行数是否会使我选择另一行。(就像您已经在回答中解释了您一样,有更多重要的理由赞成这一点。)
Arjan

3
@Arjan我同意。一个人的首要任务应该是为编程任务编写足够的代码。之后,我要说清楚:可读性,可维护性和素养的文档。在这种情况下,计算代码行数是没有意义的。
Whuber

1
atan2(sqrt(a), sqrt(1-a))asin(sqrt(a))
user102008 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.