Python 函数和 C 函数之间的精度差异

Difference in Precision Between Python Function and C Function

我正在使用一些代码进行从地心地球固定坐标到 Latitude/Longitude/Altitude 坐标的数学转换。此函数的一个迭代是用 Python 编写的,另一个是用 C 编写的。C 方法是在 Python 方法编写之后出现的,应该是直接翻译。但是,我发现 Python 方法虽然使用浮点值进行计算,但得到了正确的答案,而 C 方法,即使使用双精度数,似乎也只在小数点后 5 位进行舍入因此在尝试将 ECEF 转换为 LLA 坐标时得到错误答案。这是转换的 Python 方法,以及一个示例坐标:

import math
import numpy as np


def ecef2lla(eceflist):
    x = float(eceflist[0])
    y = float(eceflist[1])
    z = float(eceflist[2])
    a = 6378137 # radius
    e = 8.1819190842622e-2  # eccentricity
    e_string = "E value:" + " " + str(e)
    print(e_string)
    asq = math.pow(a,2)
    asq_string = "asq value:" + " " + str(asq)
    print(asq_string)
    esq=math.pow(e,2)
    esq_string = "esq value:" + " " + str(esq)
    print(esq_string)
    b = math.sqrt( asq * (1-esq) )
    b_string = "b value:" + " " + str(b)
    print(b_string)
    bsq = math.pow(b,2)
    ep = math.sqrt( (asq - bsq)/bsq)
    ep_string = "ep value:" + " " + str(ep)
    print(ep_string)
    p = math.sqrt( math.pow(x,2) + math.pow(y,2) )
    p_string = "p value:" + " " + str(p)
    print(p_string)

    th = math.atan2(a*z, b*p)
    th_string = "th value:" + " " + str(th)
    print(th_string)

    lon = math.atan2(y,x)
    lon_string = "lon value:" + " " + str(lon)
    print(lon_string)
    lat = math.atan2( (z + math.pow(ep,2)*b*math.pow(math.sin(th),3) ), (p - esq*a*math.pow(math.cos(th),3)))
    lat_string = "lat value:" + " " + str(lat)
    print(lat_string)
    N = a/( math.sqrt(1-esq*math.pow(math.sin(lat),2)) )
    N_divisor = math.sqrt(1-esq*math.pow(math.sin(lat),2))
    ND_string = "N divisor value is" + " " + str(N_divisor)
    print(ND_string)
    N_string = "N value:" + " " + str(N)
    print(N_string)
    alt = p / math.cos(lat) - N
    alt_string = "alt value:" + " " + str(alt)
    print(alt_string)
    lon = lon % (2*math.pi)
    ret = [lat*180/math.pi, lon*180/math.pi, alt]
    return ret


if __name__ == '__main__':
    lla_coords = ecef2lla([2155172.63, 2966340.65, 5201390])
    print(lla_coords)

以下方法是翻译的C方法,使用double数据类型,认为这样可以确保最大精度:

#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <unistd.h>


void ecef_to_lla(double *coordinate){
    double ecef_latitude = coordinate[0];
    double ecef_longitude = coordinate[1];
    double ecef_altitude = coordinate[2];
    double a = 6378137;
    //double e = 8.1819190842622e-2;  
    double e = 0.081819190842622;  

    printf("E value: %.16f\n",e);
    double asq = pow(a,2);
    printf("asq string: %.16f\n",asq);
    double esq = pow(e,2);
    printf("esq string: %.16f\n",esq);
    double b = sqrt(asq * (1-esq));
    printf("b string: %.16f\n",b);
    double bsq = pow(b,2);
    double ep = sqrt((asq-bsq)/bsq);
    printf("ep string: %.16f\n",ep);
    double p = sqrt(pow(ecef_latitude,2) + pow(ecef_longitude,2));
    printf("p string: %.16f\n",p);
    double th = atan2(a*ecef_altitude,b*p);
    printf("th string: %.16f\n",th);
    double lla_longitude = atan2(ecef_longitude,ecef_latitude);
    double lla_latitude = atan2((ecef_altitude + pow(ep,2)*b*pow(sin(th),2)),p-esq*a*pow(cos(th),3));
    printf("Lat is %.16f\n",lla_latitude);
    double n = a/(sqrt(1-esq*pow(sin(lla_latitude),2)));
    double n_divisor = sqrt(1-esq*pow(sin(lla_latitude),2));
    printf("n_divisor is %.16f\n",n_divisor);
    printf("n is %.16f\n",n);
    double lla_altitude = p / cos(lla_latitude) - n;
    printf("alt is %.16f\n",lla_altitude);
    lla_longitude = fmod(lla_longitude ,(2 * M_PI));
    lla_latitude = fmod(lla_latitude ,(2 * M_PI));
    lla_latitude = lla_latitude * 180/M_PI;
    lla_longitude = lla_longitude * 180/M_PI;
    coordinate[0] = lla_latitude;
    coordinate[1] = lla_longitude;
    coordinate[2] = lla_altitude;
}

int main(void){
    double coordinates[3] = {2155172.63, 2966340.65, 5201390};
    ecef_to_lla(coordinates);
}

Python方法返回的LLA坐标为:

54.99999538240099, 54.00000006037918, 8.26665045041591

而C方法返回的是:

55.0268382213345930,54.0000000603791790,4279.4874338442459702

所以高度计算似乎是问题所在

有一个小的转录错误。换行

double lla_latitude = atan2((ecef_altitude + pow(ep,2)*b*pow(sin(th),2)),p-esq*a*pow(cos(th),3));

double lla_latitude = atan2((ecef_altitude + pow(ep,2)*b*pow(sin(th),3)),p-esq*a*pow(cos(th),3));

当我进行更改时,海拔高度为 8.2666504495。