简体   繁体   English

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

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

I'm trying to implement Haversine's formula to determine whether a given location's latitude and longitude is within a specified radius.我正在尝试实施Haversine 的公式来确定给定位置的纬度和经度是否在指定的半径内。 I used a formula detailed here:我在这里使用了一个详细的公式:
Calculate distance between two latitude-longitude points? 计算两个经纬度点之间的距离? (Haversine formula) (Haversine 公式)

I am experiencing a Math Domain Error with the following re-producible input, it does not happen all the time, but often enough to make me think I've written in-correct code:我遇到了以下可重现输入的数学域错误,它不会一直发生,但通常足以让我认为我编写了不正确的代码:

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

You cannot use sqrt on negative numbers: 您不能对负数使用sqrt

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

use cmath.srt : 使用cmath.srt

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

in your case: 在您的情况下:

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

Speaking generally, and said simply... the variable a must be protected.笼统地说,简单地说......变量a必须受到保护。 It must never be greater than 1.0, and it must never be less than 0.0, and normally, with clean data, it should be properly in this range.它绝不能大于 1.0,绝不能小于 0.0,通常情况下,对于干净的数据,它应该在这个范围内。

The problem is with how the common popular computer implementation of floating point arithmetic does its approximation and roundings, and how those results can sometimes be out of range or out of domain for a builtin math function.问题在于浮点算术的常见流行计算机实现如何进行近似和舍入,以及这些结果有时如何超出内置数学函数的范围或域。 It is not particularly common that the combination of operations results in a number that is out of domain for a following math function, but in those cases where it does occur, depending on the algorithm, it is consistently reproducable, and needs to be accounted for and mitigated, beyond a normal theoretical algorithm intuition.运算组合导致以下数学函数域外的数字并不特别常见,但在确实发生的情况下,根据算法,它始终是可重现的,并且需要加以考虑并减轻了,超出了正常的理论算法直觉。 What we code in computers is subject to how theoretical concepts have been implemented for the software and hardware.我们在计算机中编写的代码取决于软件和硬件的理论概念是如何实现的。 On paper, with pencil, we still must have guidelines for when and how to round floating point math results.在纸上,用铅笔,我们仍然必须有关于何时以及如何舍入浮点数学结果的指导方针。 Computer implementations are no different, but sometimes we are blissfully unaware of such things going on under the hood.计算机实现没有什么不同,但有时我们很幸运地不知道这些事情在幕后发生。 Popular computer implementations not only need to know at what precision to round, but also are dealing with how and when to approximate and round in the conversion to and from the binary number representations that are actually calculated at the machine level.流行的计算机实现不仅需要知道要舍入的精度,而且还需要处理在机器级别实际计算的二进制数表示的转换中如何以及何时进行近似和舍入。

Regarding the haversine formula, what a am I speaking about?关于haversine公式,什么我在谈论?

as seen in this version of code (for reference):如此版本的代码所示(供参考):

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))

In this above example, the a is not properly protected.在上面的这个例子中, a没有得到适当的保护。 It is a lurking problem waiting to crash the c calculation on the next line, in certain conditions presented particularly to the haversine formula.这是一个潜伏的问题,等待下一行的 c 计算崩溃,在某些条件下,特别是半正弦公式。

If some latlon combination of data results in如果某些 latlon 数据组合导致

a = 1.00000000000000000000000000000000000001 a = 1.00000000000000000000000000000000000001

the following c calculation with cause an error.以下c计算导致错误。

If some latlon combination of data results in如果某些 latlon 数据组合导致

a = -0.00000000000000000000000000000000000000000000001 a = -0.00000000000000000000000000000000000000000000001

the following c calculation will cause an error.下面的c计算会导致错误。

It is the floating point math implementation of your language/platform and its method of rounding approximation that can cause the rare but actual and consistently repeatable ever so slightly out of domain condition that causes the error in an unprotected haversine coding.正是您的语言/平台的浮点数学实现及其舍入近似的方法可能导致罕见但实际且始终可重复的稍微超出域条件的情况,从而导致未受保护的半正弦编码错误。

Years ago I did a three day brute force test of relative angular distances between 0 and 1, and 179 and 180, with VERY small step values.几年前,我对 0 和 1、179 和 180 之间的相对角距离进行了三天的蛮力测试,步长值非常小。 The radius of the sphere is one, a unit sphere, so that radius values are irrelevant.球体的半径为 1,单位球体,因此半径值无关紧要。 Of course, finding approximate distances on the surface of the sphere in any unit other than angular distance would require including the radius of the sphere in its units.当然,以角距离以外的任何单位在球体表面上找到近似距离需要在其单位中包括球体的半径。 But I was testing the haversine logic implementation itself, and a radius of 1 eliminated a complication.但我正在测试半正弦逻辑实现本身,半径为 1 消除了复杂性。 When the relative angular distances are 0 -1, or 179-180, these are the conditions where haversine can have difficulties, implemented with popular floating point implementations that involve converting to and from binary at a low system level, if the a is not protected.当相对角距离为 0 -1 或 179-180 时,这些是半正弦可能遇到困难的情况,使用流行的浮点实现实现,涉及在低系统级别转换二进制,如果a不受保护. Haversine is supposed to be well conditioned for small angular distances, theoretically, but a machine or software implementation of FPA (floating point arithmetic) is not always precisely cooperative with the ideals of a spherical geometry theory.从理论上讲,Haversine 应该很好地适应小角距离,但是 FPA(浮点运算)的机器或软件实现并不总是与球面几何理论的理想完美配合。 After 3 days of my brute force test, there were logged thousands of latlon combinations that would crash the unprotected popularly posted haversine formula, because the a was not protected.在我的蛮力测试 3 天后,记录了数千个 latlon 组合,这些组合会使未受保护的普遍发布的半正弦公式崩溃,因为a不受保护。 You must protect the a .您必须保护a If it goes above 1.0, or below 0.0, even the very slightest bit, all one need do is simply test for that condition and nudge it back into range.如果它高于 1.0 或低于 0.0,即使是最轻微的一点,所有需要做的只是测试该条件并将其推回范围内。 Simple.简单的。

I protected an a of -0.000000000000000000002 or in other words, if a < 0.0, by reassigning the value 0.0 to it, and also setting another flag that I could inspect so I would know if a protective action had been necessary for that data.我保护了 a 为 -0.000000000000000000002 或换句话说,如果 a < 0.0,通过将值 0.0 重新分配给它,并设置另一个我可以检查的标志,以便我知道是否需要对该数据采取保护措施。

I protected an a of 1.000000000000000000002 or in other words, if a > 1.0, by reassigning the value 1.0 to it, and also setting another flag that I could inspect so I would know if a protective action had been necessary for that data.我保护了 1.000000000000000000002 的 a 或者换句话说,如果 a > 1.0,通过将值 1.0 重新分配给它,并设置另一个我可以检查的标志,以便我知道是否需要对该数据采取保护措施。

It is a simple 2 extra lines before the c calculation.c计算之前,这是一个简单的 2 行额外的行。 You could squeeze it all on one line.你可以把它全部挤在一条线上。 The protective line(s) of code go after the a calculation, and before the c calculation.代码的保护线在a计算之后, c计算之前。 Protect your a .保护您的a .

Are you then loosing precision with those slight nudges?那么,您是否会因这些轻微的轻推而失去精确度? No more than what the floating point math with that data is already introducing with its approximations and rounding.只不过是带有该数据的浮点数学已经通过其近似值和舍入引入的内容 It crashed with data that should not have crashed a pure theoretical algorithm, one that doesn't have FPA rare issues.它崩溃了不应该崩溃的纯理论算法的数据,一个没有 FPA 罕见问题的算法。 Simply protect the a , and this should mitigate those errors, with haversine in this form.简单地保护a ,这应该可以减轻这些错误,并使用这种形式的正弦。 There are alternatives to haversine, but haversine is completely suitable for many uses, if one understands where it is well suited.半角正弦有多种替代品,但半角正弦完全适用于多种用途,前提是您了解它的用途。 I use it for skysphere calculations where the ellipsoid shape of the earth has nothing to do with anything.我将它用于天空球计算,其中地球的椭球形状与任何事情无关。 Haversine is simple and fast. Haversine 既简单又快速。 But remember to protect your a .但请记住保护您的a .

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

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