距离估算-不了解此数学域错误

时间:2019-12-10 14:28:38

标签: python

我尝试计算2个位置之间的距离,但是此公式有误

acos(sin(latA)*sin(latB) + cos(latA)*cos(latB)*cos(abs(longB-longA)))

这是我计算距离的功能:

def distanceGPS(latA, longA, latB, longB):
    """Retourne la distance en Kilomètres entre les 2 points A et B connus grâce à
       leurs coordonnées GPS (en radians).
    """
    latA, longA, latB, longB = deg2rad(latA, longA, latB, longB)

    print(latA)
    print(longA)
    print(latB)
    print(longB)

    # Rayon de la terre en mètres (sphère IAG-GRS80)
    RT = 6378.137
    # angle en radians entre les 2 points
    S = acos(sin(latA)*sin(latB) + cos(latA)*cos(latB)*cos(abs(longB-longA)))

    # distance entre les 2 points, comptée sur un arc de grand cercle
    return (S*RT)

打印结果:

lat    0.651706 
dtype: float64
lon   -0.079956
dtype: float64
0.6517058798628295
-0.07995634999527296

这是我将度数转换为弧度的函数:

def deg2rad(latA, longA, latB, longB):
    """Convertit un angle "degrés décimaux" en "radians"
    """
    return latA/180*pi, longA/180*pi, latB/180*pi, longB/180*pi

def test_prediction(corpus, lat_moy, long_moy, i):
    """
    Cette fonction test si la localisation predite est a une distance inferieure a 100km de la localisation correct. 
    Si oui, alors on defini la prediction comme correct
    Si non, alors on defini la prediction comme non correct
    """

    for word in corpus.correct_localisation[i]:
        loc = geolocator.geocode(word)

        if loc is not None and distanceGPS(lat_moy, long_moy, loc.latitude, loc.longitude) <= 100:
            corpus.at[i, "test_pred"] = "OK"
            return
        else:
            corpus.at[i, "test_pred"] = "NOK"

    return

我的错误是:

> --------------------------------------------------------------------------- ValueError                                Traceback (most recent call
> last) <ipython-input-18-75f41b231cbd> in <module>
>      11     df = coordonnees_article(corpus['article'][i])
>      12     lat_moy, long_moy = position_moyenne(outliers_coordonnees(df))
> ---> 13     test_prediction(corpus, lat_moy, long_moy, i)
>      14     print(i)
> 
> <ipython-input-17-47270c034d33> in test_prediction(corpus, lat_moy,
> long_moy, i)
>      11         print(loc)
>      12  #       try:
> ---> 13         if loc is not None and distanceGPS(lat_moy, long_moy, loc.latitude, loc.longitude) <= 100:
>      14             corpus.at[i, "test_pred"] = "OK"
>      15             return
> 
> <ipython-input-16-129df29f0484> in distanceGPS(latA, longA, latB,
> longB)
>      13     RT = 6378.137
>      14     # angle en radians entre les 2 points
> ---> 15     S = acos(sin(latA)*sin(latB) + cos(latA)*cos(latB)*cos(abs(longB-longA)))
>      16 
>      17     # distance entre les 2 points, comptée sur un arc de grand cercle
> 
> ValueError: math domain error

谢谢您的帮助

1 个答案:

答案 0 :(得分:2)

对于您有时会遇到的“怪异”情况,这是由于浮点数不准确所致。 例如,如果您运行:

1.2 - 1.0 = 0.19999999999999996

我们显然希望它表示为0.2,但是由于表示浮点数的方式(使用固定数目的二进制数字),我们得到了上面的结果。

您该如何处理?您可以使用decimal module或将值四舍五入到小数位数。

如果您在python中使用十进制模块:

from decimal import *

# the following sets the number of decimal places to 8
getcontext().prec = 8

# if you run
sin(latA)*sin(latB) + cos(latA)*cos(latB)*cos(abs(longB-longA))
# the output is
0.999999999999954

# if you use the decimal module
# (please note I am multiplying by 1 at the end)
Decimal(sin(latA)*sin(latB) + cos(latA)*cos(latB)*cos(abs(longB-longA)))*1
# the output is
Decimal('1.00000000000')

您还可以使用舍入功能并将数字舍入到更少的小数位:

x = 0.19999999999999996
round(x,8)
# the output is
0.2

在您的情况下,尽管我没有收到域错误,但我认为得到该错误的原因是因为您的计算机可能会计算出1.000000000004的值(例如)。因此,当您尝试使用 acos(1.0000000004)时,会出现域错误。在调用 acos 之前,使用上述两种方法对“答案”进行“四舍五入”可能会解决您面临的问题。