繁体   English   中英

Haversine 的公式和 Python 3 - 数学域错误

[英]Haversine's Formula and Python 3 - Math Domain Error

我正在尝试实施Haversine 的公式来确定给定位置的纬度和经度是否在指定的半径内。 我在这里使用了一个详细的公式:
计算两个经纬度点之间的距离? (Haversine 公式)

我遇到了以下可重现输入的数学域错误,它不会一直发生,但通常足以让我认为我编写了不正确的代码:

from math import atan2, sqrt, sin, cos

# All long / lat values are in radians and of type float
centerLongitude = -0.0391412861306467
centerLatitude = 0.9334153362515779

inputLatitudeValue = -0.6096173085842176
inputLongitudeValue = 2.4190393564390438

longitudeDelta = inputLongitudeValue - centerLongitude # 2.4581806425696904
latitudeDelta = inputLatitudeValue - centerLatitude # -1.5430326448357956

a = (sin(latitudeDelta / 2) ** 2 + cos(centerLatitude) * cos(centerLongitude) 
     * sin(longitudeDelta / 2) ** 2)
# a = 1.0139858858386017

c = 2 * atan2(sqrt(a), sqrt(1 - a)) # Error occurs on this line

# Check whether distance is within our specified radius below

您不能对负数使用sqrt

>>> sqrt(-1)   
ValueError: math domain error

使用cmath.srt

>>> import cmath
>>> cmath.sqrt(-1)
1j

在您的情况下:

>>> a = 1.0139858858386017
>>> sqrt(1-a)
ValueError: math domain error

笼统地说,简单地说......变量a必须受到保护。 它绝不能大于 1.0,绝不能小于 0.0,通常情况下,对于干净的数据,它应该在这个范围内。

问题在于浮点算术的常见流行计算机实现如何进行近似和舍入,以及这些结果有时如何超出内置数学函数的范围或域。 运算组合导致以下数学函数域外的数字并不特别常见,但在确实发生的情况下,根据算法,它始终是可重现的,并且需要加以考虑并减轻了,超出了正常的理论算法直觉。 我们在计算机中编写的代码取决于软件和硬件的理论概念是如何实现的。 在纸上,用铅笔,我们仍然必须有关于何时以及如何舍入浮点数学结果的指导方针。 计算机实现没有什么不同,但有时我们很幸运地不知道这些事情在幕后发生。 流行的计算机实现不仅需要知道要舍入的精度,而且还需要处理在机器级别实际计算的二进制数表示的转换中如何以及何时进行近似和舍入。

关于haversine公式,什么我在谈论?

如此版本的代码所示(供参考):

import math

a = math.sin(dlat / 2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2)**2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))

在上面的这个例子中, a没有得到适当的保护。 这是一个潜伏的问题,等待下一行的 c 计算崩溃,在某些条件下,特别是半正弦公式。

如果某些 latlon 数据组合导致

a = 1.00000000000000000000000000000000000001

以下c计算导致错误。

如果某些 latlon 数据组合导致

a = -0.00000000000000000000000000000000000000000000001

下面的c计算会导致错误。

正是您的语言/平台的浮点数学实现及其舍入近似的方法可能导致罕见但实际且始终可重复的稍微超出域条件的情况,从而导致未受保护的半正弦编码错误。

几年前,我对 0 和 1、179 和 180 之间的相对角距离进行了三天的蛮力测试,步长值非常小。 球体的半径为 1,单位球体,因此半径值无关紧要。 当然,以角距离以外的任何单位在球体表面上找到近似距离需要在其单位中包括球体的半径。 但我正在测试半正弦逻辑实现本身,半径为 1 消除了复杂性。 当相对角距离为 0 -1 或 179-180 时,这些是半正弦可能遇到困难的情况,使用流行的浮点实现实现,涉及在低系统级别转换二进制,如果a不受保护. 从理论上讲,Haversine 应该很好地适应小角距离,但是 FPA(浮点运算)的机器或软件实现并不总是与球面几何理论的理想完美配合。 在我的蛮力测试 3 天后,记录了数千个 latlon 组合,这些组合会使未受保护的普遍发布的半正弦公式崩溃,因为a不受保护。 您必须保护a 如果它高于 1.0 或低于 0.0,即使是最轻微的一点,所有需要做的只是测试该条件并将其推回范围内。 简单的。

我保护了 a 为 -0.000000000000000000002 或换句话说,如果 a < 0.0,通过将值 0.0 重新分配给它,并设置另一个我可以检查的标志,以便我知道是否需要对该数据采取保护措施。

我保护了 1.000000000000000000002 的 a 或者换句话说,如果 a > 1.0,通过将值 1.0 重新分配给它,并设置另一个我可以检查的标志,以便我知道是否需要对该数据采取保护措施。

c计算之前,这是一个简单的 2 行额外的行。 你可以把它全部挤在一条线上。 代码的保护线在a计算之后, c计算之前。 保护您的a .

那么,您是否会因这些轻微的轻推而失去精确度? 只不过是带有该数据的浮点数学已经通过其近似值和舍入引入的内容 它崩溃了不应该崩溃的纯理论算法的数据,一个没有 FPA 罕见问题的算法。 简单地保护a ,这应该可以减轻这些错误,并使用这种形式的正弦。 半角正弦有多种替代品,但半角正弦完全适用于多种用途,前提是您了解它的用途。 我将它用于天空球计算,其中地球的椭球形状与任何事情无关。 Haversine 既简单又快速。 但请记住保护您的a .

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM