Jes*_*Ros 3 c rounding-error math.h
我正在创建一个函数,使用它们的纬度/经度(以度为单位而不是弧度)和余弦的球面律来计算两点的距离.我acos()遇到的问题是,由于函数中的舍入误差,当两点非常接近时,我得到的结果远远不够好.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct{
double lat;
double lon;
} point;
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define EARTH_RADIUS_IN_METERS 6372797.560856
double distance(point a, point b) {
double arg=sin(a.lat * DEG_TO_RAD) * sin(b.lat * DEG_TO_RAD) + cos(a.lat * DEG_TO_RAD) * cos(b.lat * DEG_TO_RAD) * cos((a.lon-b.lon) * DEG_TO_RAD);
if(arg>1) arg=1;
else if (arg<-1) arg=-1;
printf("arg=%.12f acos(arg)=%.12f\n",arg, acos(arg)); //to see the problem
return acos(arg) * EARTH_RADIUS_IN_METERS;
}
int main(){
point p1,p2;
p1.lat=63.0;
p1.lon=27.0;
p2.lat=p1.lat;
p2.lon=p1.lon;
printf("dist=%.8f\n",distance(p1,p2));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是
arg=1.000000000000 acos(arg)=0.000000014901
dist=0.09496208
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,当它计算acos()它时它应该给零,但它确实给出了一些误差,这些误差在乘以地球半径后会得到极大的放大.当两点不相等但非常接近时,也会发生这种情况.如果有任何用途,我的纬度和经度数据最多为7位小数.
你得到的结果acos是最好的:问题是计算arg总是会有一个小错误并返回一个略微偏离的值.当两个点相等或非常接近时,结果小于1,例如1-10 -16.如果你看一下你会看到它在x = 1处几乎垂直的图形acos(x),这意味着即使是最轻微的错误也会arg对相对误差产生巨大影响.换句话说,该算法在数值上是不稳定的.
您可以使用hasrsine公式来获得更好的结果.