无论是使用vincenty还是hasrsine或余弦的球律,明智的做法是了解您计划使用的代码的任何潜在问题,需要注意和缓解的问题以及如何处理vincenty,haversine,sloc问题当人们意识到每个人的潜伏问题/边缘情况时,情况可能会有所不同,这可能会或可能不会广为人知。经验丰富的程序员知道这一点。新手可能不会。在某些情况下,如果论坛中的摘要片段执行了某些意外操作,我希望可以避免其中的一些挫败感。如果认真使用其中任何一种的某些版本,例如vincenty,haversine,sloc,SE,SO,Reddit,Quora等,则可能在解决方案的某些初始编码中提供了有限的帮助,但这并不意味着他们的解决方案或公认的“答案”没有问题。如果一个项目足够重要,则应该进行适当合理数量的研究。阅读手册,阅读文档,如果存在对该代码的代码审查,请阅读该手册。复制并粘贴已被投票一百次或更多次的摘录或要点并不意味着其安全性是全面且有保证的。
cffk提出的有趣的答案提出了要注意在打包的解决方案中潜伏着可能产生异常或其他困难的边缘情况的意义。该职位提出的具体要求超出了我目前的时间预算,但我认为某些包中确实存在潜伏的问题,其中包括至少一项文森特实施,至少有人建议对此进行改进一种方法或另一种方法,以最大程度地减少或消除遇到这些困难的风险。我不会在有关vincenty的话题上做进一步的介绍(对此太不了解了),但是将转而将其改为hasrsine,至少部分是关于OP的话题。
广受欢迎的Haversine公式,无论是python还是其他语言,因为它很可能会在当今大多数所有intel和intel-like系统以及ARM处理器,powerPC等上使用IEEE 754浮点规范。由于浮点近似和舍入,在极近或在180度弧距离处也很容易遇到罕见但真实且可重复的异常错误,即对极点。有些新手可能尚未被这种情况咬伤。因为此fp规范是近似值和四舍五入,所以这并不意味着任何在fp64上调用的代码都可能导致异常错误。但是一些代码 一些公式可能没有那么明显的边缘情况,在这些情况下,IEEE 754 fp64的近似值和舍入可能导致某个值稍微偏离数学方法的范围,而该数学方法可以完美地评估该值。一个例子... sqrt()。如果负数进入sqrt(),例如sqrt(-0.00000000000000000122739),则将出现异常错误。在haversine公式中,它走向求解的方式在atan2()中有两种sqrt()方法。的经过计算然后在sqrt()中使用的a,可以在地球上的对映点稍微偏离0.0或1.0以下,由于fp64近似和四舍五入而非常轻微,很少但可重复。在这种情况下,一致的可靠可重复性使它成为例外风险,这是保护,缓解而不是孤立的随机fl幸的边缘情况。这是haversine的简短python3片段示例,没有必要的保护:
import math as m
a = m.sin(dlat / 2)**2 + m.cos(lat1) * m.cos(lat2) * m.sin(dlon / 2)**2
c = 2 * m.atan2(m.sqrt(a), m.sqrt(1 - a))
distance = Radius * c
在公式的第一行中非常接近或在对映点处,a可能会偏离负值,很少出现,但对于相同的纬度坐标重复出现。为了保护/纠正这些罕见的事件,一个可以简单地添加,后一个计算,所看到如下:
import math as m
note = ''
a = m.sin(dlat / 2)**2 + m.cos(lat1) * m.cos(lat2) * m.sin(dlon / 2)**2
if a < 0.0: a = 0.0 ; note = '*'
if a > 1.0: a = 1.0 ; note = '**'
c = 2 * m.atan2(m.sqrt(a), m.sqrt(1 - a))
distance = Radius * c
# note = '*' # a went below 0.0 and was normalized back to 0.0
# note = '**' # a went above 1.0 and was normalized back to max of 1.0
当然,我并没有在此处显示整个功能,而是发布了一个简短的摘要。但是通过测试a并在必要时对其进行规范化,此示例显示了对sqrt()的保护,同时还省去了将整个过程都尝试一遍的需要。note =“ up up top”是为了防止字节码阶段在分配了值之前抗议使用了该注释,如果该注释随函数结果一起返回。
通过简单的更改,即添加两个a测试,sqrt()函数将很高兴,并且代码现在具有可以返回到调用代码的附加注释,以警告结果已被稍微规范化以及原因。有些人可能在乎,有些人可能不在乎,但是它在那里,防止了“否则”可能发生的异常错误。除非明确编写,try try块可能会捕获该异常,但不能解决该异常。它似乎更容易在后码校正线(S)一个计算行。然后,彻底擦洗的输入应该完全不需要尝试,除非此处阻塞。
总之,如果采用半正矢,显式编码,而不是用包或库,无论你选择的语言,这将是一个好主意,测试和正常化一个为了回0.0要紧的范围<= A <= 1.0用c计算保护下一行。但是大多数haversine代码段没有显示它,也没有提及风险。
经验:在全球范围内以0.001度为增量进行全面测试的过程中,我已经用latlon组合填充了一个硬盘驱动器,该组合导致一个异常(可靠的一致的可重复异常),并且在一个月内同时对CPU冷却的可靠性进行了测试。粉丝,还有我的耐心。是的,自那以后,我删除了大多数这些日志,因为它们的目的主要是为了证明这一点(如果允许使用双关语)。但是我有一些较短的“问题纬度值”日志,用于测试目的。
准确性:a和整个havesine结果会通过将其归一化到域中而损失一些准确性吗?引入的fp64近似值和舍入不多,也许不多,这引起了域外的轻微漂移。如果您已经发现Haversine已经可以接受vincenty了-更简单,更快,更易于自定义,排除故障和维护,那么Haversine可能是您的项目的理想解决方案。
从地球上的某个位置看,我已经在高架投影的天空层上使用了hasversine来测量天空中的对象之间的角距离,将方位角和alt映射到与latlat lonlon等价的坐标类似的坐标,根本没有要考虑的椭球体,因为当从地球表面的某个位置测量两个物体之间的角距离外观时,投影理论天空球是一个理想的球。非常适合我的需求。因此,在某些应用中(正好在我的目的之内),haversine仍然非常有用且非常准确……但是,如果您确实使用它,无论是在地球上进行GIS还是导航,还是在天体观测和测量中,都应加以保护它通过测试径点或非常接近径点的情况下,一并在需要时将其推回其需要的域。
不受保护的Haversine遍及整个Internet,并且我只看到一个老的usenet帖子显示了一些保护,我认为是JPL的某个人提供的,并且可能是1985年前的IEEE 754浮点规范。另外两页提到了对点附近的可能问题,但没有描述这些问题,也没有描述如何解决这些问题。因此,对于像我这样的新手来说,可能会感到担忧,他们可能并不总是对良好实践有足够的了解,无法进一步研究和测试他们复制并粘贴到信任项目中的某些代码的边缘情况。与发布的未受保护和未经讨论的版本相比,cffk令人着迷的帖子令人耳目一新,因为它公开发布了这类问题,这些问题很少提及,很少公开编码以保护摘要,并且很少采用这种方式进行讨论。
截至20190923,由于计算设备中存在浮点问题,haversine公式的wiki页面确实确实提到了对映点可能存在的问题...令人鼓舞...
https://zh.wikipedia.org/wiki/Haversine_formula
(因为该Wiki页面目前没有我直接链接到的部分的html锚,因此,在该页面加载后,请在该浏览器页面上搜索“何时使用这些公式”,可以更正式地看到有关正反点的长石问题。)
这个站点也对此进行了非常简短的提及:
https://www.movable-type.co.uk/scripts/latlong.html
如果在该页面上找到“包括防止舍入错误的保护措施”,那么就会有...
如果atan2不可用,则可以从2⋅asin(min(1,√a))计算c(包括防止舍入误差)。
现在,有一种罕见的情况,其中提到了舍入错误,并且针对asin()版本显示了保护,而对于atan2()版本则没有提及或显示。但是至少提到了舍入错误的风险。
imho,任何使用正己烷的24/7/365应用程序,都需要在反点附近提供这种保护,这是重要且简单的细节。
我不知道哪些hasrsine软件包提供或不提供这种保护,但是如果您不熟悉这一切,并且打算使用流行发行的“代码段”版本,现在您知道它需要保护,并且这种保护非常容易实现,也就是说,如果您不使用vincenty,并且没有使用打包的强效剂,而无法轻松访问修改包的代码的话。
IOW,无论使用vincenty,haversine还是sloc,都应该了解代码中的任何问题,需要注意和缓解的问题,以及随着人们意识到每个人对vincenty,haversine,sloc问题的处理方式会有所不同潜伏的问题/边缘情况,可能会或可能不会广为人知。