acos()结果不好,C中有两个关闭点

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位小数.

Jon*_*oni 5

你得到的结果acos是最好的:问题是计算arg总是会有一个小错误并返回一个略微偏离的值.当两个点相等或非常接近时,结果小于1,例如1-10 -16.如果你看一下你会看到它在x = 1处几乎垂直的图形acos(x),这意味着即使是最轻微的错误也会arg对相对误差产生巨大影响.换句话说,该算法在数值上是不稳定的.

您可以使用hasrsine公式来获得更好的结果.

  • @ gunbl4d3是的,数学知识通常胜过浮点编程的知识. (2认同)